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
91 #if PRAGMA_MARK
92 #pragma mark External & Internal Function Protos
93 #endif
94 /*********************************************************************
95 *********************************************************************/
96 extern "C" {
97 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
98 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
99
100 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
101 extern int dtrace_keep_kernel_symbols(void);
102
103 #if defined(__x86_64__) || defined(__i386__)
104 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
105 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
106 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
107 static void *allocate_kcfileset_map_entry_list(void);
108 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
109 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
110 int vnode_put(struct vnode *vp);
111 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
112 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
113 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
114 void * ubc_getobject(struct vnode *vp, __unused int flags);
115 #endif //(__x86_64__) || defined(__i386__)
116 }
117
118 extern unsigned long gVirtBase;
119 extern unsigned long gPhysBase;
120 extern vm_map_t g_kext_map;
121
122 bool pageableKCloaded = false;
123 bool auxKCloaded = false;
124 bool resetAuxKCSegmentOnUnload = false;
125
126 extern boolean_t pageablekc_uuid_valid;
127 extern uuid_t pageablekc_uuid;
128 extern uuid_string_t pageablekc_uuid_string;
129
130 extern boolean_t auxkc_uuid_valid;
131 extern uuid_t auxkc_uuid;
132 extern uuid_string_t auxkc_uuid_string;
133
134 static OSReturn _OSKextCreateRequest(
135 const char * predicate,
136 OSSharedPtr<OSDictionary> & requestP);
137 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
138 static OSObject * _OSKextGetRequestArgument(
139 OSDictionary * requestDict,
140 const char * argName);
141 static bool _OSKextSetRequestArgument(
142 OSDictionary * requestDict,
143 const char * argName,
144 OSMetaClassBase * value);
145 template <typename T>
146 static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
147 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
148 static OSReturn _OSDictionarySetCStringValue(
149 OSDictionary * dict,
150 const char * key,
151 const char * value);
152 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
153 #if CONFIG_KXLD
154 static bool _OSKextInPrelinkRebuildWindow(void);
155 #endif
156
157 // We really should add containsObject() & containsCString to OSCollection & subclasses.
158 // So few pad slots, though....
159 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
160 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
161
162 static const char *getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size);
163
164 /* Prelinked arm kexts do not have VM entries because the method we use to
165 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
166 * not work on ARM. To get around that, we must free prelinked kext
167 * executables with ml_static_mfree() instead of kext_free().
168 */
169 #if __i386__ || __x86_64__
170 #define VM_MAPPED_KEXTS 1
171 #define KASLR_KEXT_DEBUG 0
172 #define KASLR_IOREG_DEBUG 0
173 #elif __arm__ || __arm64__
174 #define VM_MAPPED_KEXTS 0
175 #define KASLR_KEXT_DEBUG 0
176 #else
177 #error Unsupported architecture
178 #endif
179
180 #if PRAGMA_MARK
181 #pragma mark Constants & Macros
182 #endif
183 /*********************************************************************
184 * Constants & Macros
185 *********************************************************************/
186
187 /* Use this number to create containers.
188 */
189 #define kOSKextTypicalLoadCount (150)
190 #define kOSKextTypicalUpgradeCount (5)
191
192 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
193 * A loaded kext will no dependents or external retains will have 2 retains.
194 */
195 #define kOSKextMinRetainCount (1)
196 #define kOSKextMinLoadedRetainCount (2)
197
198 #define kOSKextMaxDextLaunchedCount (~((uint32_t)0))
199 #define KOSBundleDextUniqueIdentifierMaxStringLength (KOSBundleDextUniqueIdentifierMaxLength * 2 +1)
200
201 /**********
202 * Strings and substrings used in dependency resolution.
203 */
204 #define APPLE_KEXT_PREFIX "com.apple."
205 #define KERNEL_LIB "com.apple.kernel"
206
207 #define PRIVATE_KPI "com.apple.kpi.private"
208
209 /* Version for compatbility pseudokexts (com.apple.kernel.*),
210 * compatible back to v6.0.
211 */
212 #define KERNEL6_LIB "com.apple.kernel.6.0"
213 #define KERNEL6_VERSION "7.9.9"
214
215 #define KERNEL_LIB_PREFIX "com.apple.kernel."
216 #define KPI_LIB_PREFIX "com.apple.kpi."
217
218 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
219
220 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
221 #define MINIMUM_WAKEUP_SECONDS (30)
222
223 /*********************************************************************
224 * infoDict keys for internally-stored data. Saves on ivar slots for
225 * objects we don't keep around past boot time or during active load.
226 *********************************************************************/
227
228 /* A usable, uncompressed file is stored under this key.
229 */
230 #define _kOSKextExecutableKey "_OSKextExecutable"
231
232 /* An indirect reference to the executable file from an mkext
233 * is stored under this key.
234 */
235 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
236
237 /* If the file is contained in a larger buffer laid down by the booter or
238 * sent from user space, the OSKext stores that OSData under this key so that
239 * references are properly tracked. This is always an mkext, right now.
240 */
241 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
242
243 #define OS_LOG_HDR_VERSION 1
244 #define NUM_OS_LOG_SECTIONS 3
245
246 #define OS_LOG_SECT_IDX 0
247 #define CSTRING_SECT_IDX 1
248 #define ASAN_CSTRING_SECT_IDX 2
249
250 #if PRAGMA_MARK
251 #pragma mark Typedefs
252 #endif
253 /*********************************************************************
254 * Typedefs
255 *********************************************************************/
256
257 /*********************************************************************
258 * osLogDataHeaderRef describes the header information of an OSData
259 * object that is returned when querying for kOSBundleLogStringsKey.
260 * We currently return information regarding 2 sections - os_log and
261 * cstring. In the case that the os_log section doesn't exist, we just
262 * return an offset and length of 0 for that section.
263 *********************************************************************/
264 typedef struct osLogDataHeader {
265 uint32_t version;
266 uint32_t sect_count;
267 struct {
268 uint32_t sect_offset;
269 uint32_t sect_size;
270 } sections[0];
271 } osLogDataHeaderRef;
272
273 /*********************************************************************
274 * MkextEntryRef describes the contents of an OSData object
275 * referencing a file entry from an mkext so that we can uncompress
276 * (if necessary) and extract it on demand.
277 *
278 * It contains the mkextVersion in case we ever wind up supporting
279 * multiple mkext formats. Mkext format 1 is officially retired as of
280 * Snow Leopard.
281 *********************************************************************/
282 typedef struct MkextEntryRef {
283 mkext_basic_header * mkext; // beginning of whole mkext file
284 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
285 } MkextEntryRef;
286
287 #if PRAGMA_MARK
288 #pragma mark Global and static Module Variables
289 #endif
290 /*********************************************************************
291 * Global & static variables, used to keep track of kexts.
292 *********************************************************************/
293
294 static bool sPrelinkBoot = false;
295 static bool sSafeBoot = false;
296 static bool sKeepSymbols = false;
297 static bool sPanicOnKCMismatch = false;
298 static bool sOSKextWasResetAfterUserspaceReboot = false;
299
300 /*********************************************************************
301 * sKextLock is the principal lock for OSKext, and guards all static
302 * and global variables not owned by other locks (declared further
303 * below). It must be taken by any entry-point method or function,
304 * including internal functions called on scheduled threads.
305 *
306 * sKextLock and sKextInnerLock are recursive due to multiple functions
307 * that are called both externally and internally. The other locks are
308 * nonrecursive.
309 *
310 * Which locks are taken depends on what they protect, but if more than
311 * one must be taken, they must always be locked in this order
312 * (and unlocked in reverse order) to prevent deadlocks:
313 *
314 * 1. sKextLock
315 * 2. sKextInnerLock
316 * 3. sKextSummariesLock
317 * 4. sKextLoggingLock
318 */
319 static IORecursiveLock * sKextLock = NULL;
320
321 static OSSharedPtr<OSDictionary> sKextsByID;
322 static OSSharedPtr<OSDictionary> sExcludeListByID;
323 static OSKextVersion sExcludeListVersion = 0;
324 static OSSharedPtr<OSArray> sLoadedKexts;
325 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
326 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
327 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
328 static OSSharedPtr<OSDictionary> sDriverKitToUpgradeByID;
329
330 // Requests to the IOKit daemon waiting to be picked up.
331 static OSSharedPtr<OSArray> sKernelRequests;
332 // Identifier of kext load requests in sKernelRequests
333 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
334 static OSSharedPtr<OSArray> sRequestCallbackRecords;
335
336 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
337 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
338 #if CONFIG_KXLD
339 static KXLDContext * sKxldContext = NULL;
340 #endif
341 static uint32_t sNextLoadTag = 0;
342 static uint32_t sNextRequestTag = 0;
343
344 static bool sUserLoadsActive = false;
345 static bool sIOKitDaemonActive = false;
346 static bool sDeferredLoadSucceeded = false;
347 static bool sConsiderUnloadsExecuted = false;
348
349 #if NO_KEXTD
350 static bool sKernelRequestsEnabled = false;
351 #else
352 static bool sKernelRequestsEnabled = true;
353 #endif
354 static bool sLoadEnabled = true;
355 static bool sUnloadEnabled = true;
356
357 /*********************************************************************
358 * Stuff for the OSKext representing the kernel itself.
359 **********/
360 static OSKext * sKernelKext = NULL;
361
362 /* Load Tag IDs used by statically loaded binaries (e.g, the kernel itself). */
363 enum : uint32_t {
364 kOSKextKernelLoadTag = 0,
365 kOSKextLoadTagCount
366 };
367
368 /* Set up a fake kmod_info struct for the kernel.
369 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
370 * before OSKext is initialized; that call only needs the name
371 * and address to be set correctly.
372 *
373 * We don't do much else with the kerne's kmod_info; we never
374 * put it into the kmod list, never adjust the reference count,
375 * and never have kernel components reference it.
376 * For that matter, we don't do much with kmod_info structs
377 * at all anymore! We just keep them filled in for gdb and
378 * binary compability.
379 */
380 kmod_info_t g_kernel_kmod_info = {
381 .next = NULL,
382 .info_version = KMOD_INFO_VERSION,
383 .id = kOSKextKernelLoadTag, // loadTag: kernel is always 0
384 .name = kOSKextKernelIdentifier,// bundle identifier
385 .version = "0", // filled in in OSKext::initialize()
386 .reference_count = -1, // never adjusted; kernel never unloads
387 .reference_list = NULL,
388 .address = 0,
389 .size = 0, // filled in in OSKext::initialize()
390 .hdr_size = 0,
391 .start = NULL,
392 .stop = NULL
393 };
394
395
396 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
397
398 kmod_info_t invalid_kmod_info = {
399 .next = NULL,
400 .info_version = KMOD_INFO_VERSION,
401 .id = UINT32_MAX,
402 .name = "invalid",
403 .version = "0",
404 .reference_count = -1,
405 .reference_list = NULL,
406 .address = 0,
407 .size = 0,
408 .hdr_size = 0,
409 .start = NULL,
410 .stop = NULL
411 };
412
413 extern "C" {
414 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
415 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
416 // misc_protos.h, db_low_trace.c, kgmacros
417 // 'kmod' is a holdover from the old kmod system, we can't rename it.
418 kmod_info_t * kmod = NULL;
419
420 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
421
422
423 static char * loaded_kext_paniclist = NULL;
424 static uint32_t loaded_kext_paniclist_size = 0;
425
426 AbsoluteTime last_loaded_timestamp;
427 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
428 static u_long last_loaded_strlen = 0;
429 static void * last_loaded_address = NULL;
430 static u_long last_loaded_size = 0;
431
432 AbsoluteTime last_unloaded_timestamp;
433 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
434 static u_long last_unloaded_strlen = 0;
435 static void * last_unloaded_address = NULL;
436 static u_long last_unloaded_size = 0;
437
438 // Statically linked kmods described by several mach-o sections:
439 //
440 // kPrelinkInfoSegment:kBuiltinInfoSection
441 // Array of pointers to kmod_info_t structs.
442 //
443 // kPrelinkInfoSegment:kBuiltinInfoSection
444 // Array of pointers to an embedded mach-o header.
445 //
446 // __DATA:kBuiltinInitSection, kBuiltinTermSection
447 // Structors for all kmods. Has to be filtered by proc address.
448 //
449
450 static uint32_t gBuiltinKmodsCount;
451 static kernel_section_t * gBuiltinKmodsSectionInfo;
452 static kernel_section_t * gBuiltinKmodsSectionStart;
453
454 const OSSymbol * gIOSurfaceIdentifier;
455 vm_tag_t gIOSurfaceTag;
456
457 /*********************************************************************
458 * sKextInnerLock protects against cross-calls with IOService and
459 * IOCatalogue, and owns the variables declared immediately below.
460 *
461 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
462 *
463 * When both sKextLock and sKextInnerLock need to be taken,
464 * always lock sKextLock first and unlock it second. Never take both
465 * locks in an entry point to OSKext; if you need to do so, you must
466 * spawn an independent thread to avoid potential deadlocks for threads
467 * calling into OSKext.
468 **********/
469 static IORecursiveLock * sKextInnerLock = NULL;
470
471 #if XNU_TARGET_OS_OSX
472 static bool sAutounloadEnabled = true;
473 #endif
474 static bool sConsiderUnloadsCalled = false;
475 static bool sConsiderUnloadsPending = false;
476
477 static unsigned int sConsiderUnloadDelay = 60; // seconds
478 static thread_call_t sUnloadCallout = NULL;
479 #if CONFIG_KXLD
480 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
481 #endif // CONFIG_KXLD
482 static bool sSystemSleep = false; // true when system going to sleep
483 static AbsoluteTime sLastWakeTime; // last time we woke up
484
485 /*********************************************************************
486 * Backtraces can be printed at various times so we need a tight lock
487 * on data used for that. sKextSummariesLock protects the variables
488 * declared immediately below.
489 *
490 * gLoadedKextSummaries is accessed by other modules, but only during
491 * a panic so the lock isn't needed then.
492 *
493 * gLoadedKextSummaries has the "used" attribute in order to ensure
494 * that it remains visible even when we are performing extremely
495 * aggressive optimizations, as it is needed to allow the debugger
496 * to automatically parse the list of loaded kexts.
497 **********/
498 static IOLock * sKextSummariesLock = NULL;
499 extern "C" lck_ticket_t vm_allocation_sites_lock;
500 extern "C" lck_grp_t vm_page_lck_grp_bucket;
501 static lck_ticket_t * sKextAccountsLock = &vm_allocation_sites_lock;
502 static lck_grp_t * sKextAccountsLockGrp = &vm_page_lck_grp_bucket;
503
504 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
505 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
506 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
507 static size_t sLoadedKextSummariesAllocSize = 0;
508
509 static OSKextActiveAccount * sKextAccounts;
510 static uint32_t sKextAccountsCount;
511 };
512
513 /*********************************************************************
514 * sKextLoggingLock protects the logging variables declared immediately below.
515 **********/
516 static IOLock * sKextLoggingLock = NULL;
517
518 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
519 kOSKextLogVerboseFlagsMask;
520 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
521 static bool sBootArgLogFilterFound = false;
522 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
523 0, "kernel kext logging");
524
525 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
526 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
527 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
528
529 /*********
530 * End scope for sKextInnerLock-protected variables.
531 *********************************************************************/
532
533 /*********************************************************************
534 * OSValueObject concrete type instantiations
535 **********/
536 OSDefineValueObjectForDependentType(void*)
537 OSDefineValueObjectForDependentType(OSKextRequestResourceCallback)
538
539
540 /**********************************************************************/
541
542 TUNABLE(uint32_t, kMaxDextCrashesInOneDay, "daily_max_dext_crashes", kMaxDextCrashesInOneDayDefault);
543
544 /*********************************************************************
545 * helper function used for collecting PGO data upon unload of a kext
546 */
547
548 static int OSKextGrabPgoDataLocked(OSKext *kext,
549 bool metadata,
550 uuid_t instance_uuid,
551 uint64_t *pSize,
552 char *pBuffer,
553 uint64_t bufferSize);
554
555 /**********************************************************************/
556
557
558
559 #if PRAGMA_MARK
560 #pragma mark OSData callbacks (need to move to OSData)
561 #endif
562 /*********************************************************************
563 * C functions used for callbacks.
564 *********************************************************************/
565 extern "C" {
566 void
osdata_kmem_free(void * ptr,unsigned int length)567 osdata_kmem_free(void * ptr, unsigned int length)
568 {
569 kmem_free(kernel_map, (vm_address_t)ptr, length);
570 return;
571 }
572
573 void
osdata_phys_free(void * ptr,unsigned int length)574 osdata_phys_free(void * ptr, unsigned int length)
575 {
576 ml_static_mfree((vm_offset_t)ptr, length);
577 return;
578 }
579
580 void
osdata_vm_deallocate(void * ptr,unsigned int length)581 osdata_vm_deallocate(void * ptr, unsigned int length)
582 {
583 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
584 return;
585 }
586
587 void
osdata_kext_free(void * ptr,unsigned int length)588 osdata_kext_free(void * ptr, unsigned int length)
589 {
590 (void)kext_free((vm_offset_t)ptr, length);
591 }
592 };
593
594 #if PRAGMA_MARK
595 #pragma mark KXLD Allocation Callback
596 #endif
597 #if CONFIG_KXLD
598 /*********************************************************************
599 * KXLD Allocation Callback
600 *********************************************************************/
601 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)602 kern_allocate(
603 u_long size,
604 KXLDAllocateFlags * flags,
605 void * user_data)
606 {
607 vm_address_t result = 0; // returned
608 kern_return_t mach_result = KERN_FAILURE;
609 bool success = false;
610 OSKext * theKext = (OSKext *)user_data;
611 unsigned int roundSize = 0;
612 OSSharedPtr<OSData> linkBuffer;
613
614 if (round_page(size) > UINT_MAX) {
615 OSKextLog(theKext,
616 kOSKextLogErrorLevel |
617 kOSKextLogGeneralFlag,
618 "%s: Requested memory size is greater than UINT_MAX.",
619 theKext->getIdentifierCString());
620 goto finish;
621 }
622
623 roundSize = (unsigned int)round_page(size);
624
625 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
626 if (mach_result != KERN_SUCCESS) {
627 OSKextLog(theKext,
628 kOSKextLogErrorLevel |
629 kOSKextLogGeneralFlag,
630 "Can't allocate kernel memory to link %s.",
631 theKext->getIdentifierCString());
632 goto finish;
633 }
634
635 /* Create an OSData wrapper for the allocated buffer.
636 */
637 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
638 if (!linkBuffer) {
639 OSKextLog(theKext,
640 kOSKextLogErrorLevel |
641 kOSKextLogGeneralFlag,
642 "Can't allocate linked executable wrapper for %s.",
643 theKext->getIdentifierCString());
644 goto finish;
645 }
646 linkBuffer->setDeallocFunction(osdata_kext_free);
647 OSKextLog(theKext,
648 kOSKextLogProgressLevel |
649 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
650 "Allocated link buffer for kext %s at %p (%lu bytes).",
651 theKext->getIdentifierCString(),
652 (void *)result, (unsigned long)roundSize);
653
654 theKext->setLinkedExecutable(linkBuffer.get());
655
656 *flags = kKxldAllocateWritable;
657 success = true;
658
659 finish:
660 if (!success && result) {
661 kext_free(result, roundSize);
662 result = 0;
663 }
664
665 return (kxld_addr_t)result;
666 }
667
668 /*********************************************************************
669 *********************************************************************/
670 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)671 kxld_log_callback(
672 KXLDLogSubsystem subsystem,
673 KXLDLogLevel level,
674 const char * format,
675 va_list argList,
676 void * user_data)
677 {
678 OSKext *theKext = (OSKext *) user_data;
679 OSKextLogSpec logSpec = 0;
680
681 switch (subsystem) {
682 case kKxldLogLinking:
683 logSpec |= kOSKextLogLinkFlag;
684 break;
685 case kKxldLogPatching:
686 logSpec |= kOSKextLogPatchFlag;
687 break;
688 }
689
690 switch (level) {
691 case kKxldLogExplicit:
692 logSpec |= kOSKextLogExplicitLevel;
693 break;
694 case kKxldLogErr:
695 logSpec |= kOSKextLogErrorLevel;
696 break;
697 case kKxldLogWarn:
698 logSpec |= kOSKextLogWarningLevel;
699 break;
700 case kKxldLogBasic:
701 logSpec |= kOSKextLogProgressLevel;
702 break;
703 case kKxldLogDetail:
704 logSpec |= kOSKextLogDetailLevel;
705 break;
706 case kKxldLogDebug:
707 logSpec |= kOSKextLogDebugLevel;
708 break;
709 }
710
711 OSKextVLog(theKext, logSpec, format, argList);
712 }
713 #endif // CONFIG_KXLD
714
715 #if PRAGMA_MARK
716 #pragma mark IOStatistics defines
717 #endif
718
719 #if IOKITSTATS
720
721 #define notifyKextLoadObservers(kext, kmod_info) \
722 do { \
723 IOStatistics::onKextLoad(kext, kmod_info); \
724 } while (0)
725
726 #define notifyKextUnloadObservers(kext) \
727 do { \
728 IOStatistics::onKextUnload(kext); \
729 } while (0)
730
731 #define notifyAddClassObservers(kext, addedClass, flags) \
732 do { \
733 IOStatistics::onClassAdded(kext, addedClass); \
734 } while (0)
735
736 #define notifyRemoveClassObservers(kext, removedClass, flags) \
737 do { \
738 IOStatistics::onClassRemoved(kext, removedClass); \
739 } while (0)
740
741 #else
742
743 #define notifyKextLoadObservers(kext, kmod_info)
744 #define notifyKextUnloadObservers(kext)
745 #define notifyAddClassObservers(kext, addedClass, flags)
746 #define notifyRemoveClassObservers(kext, removedClass, flags)
747
748 #endif /* IOKITSTATS */
749
750 #if PRAGMA_MARK
751 #pragma mark Module Config (Startup & Shutdown)
752 #endif
753 /*********************************************************************
754 * Module Config (Class Definition & Class Methods)
755 *********************************************************************/
756 #define super OSObject
757 OSDefineMetaClassAndStructors(OSKext, OSObject)
758
759 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
760
761 OSDefineMetaClassAndStructors(OSDextStatistics, OSObject);
762
763 /*********************************************************************
764 *********************************************************************/
765 /**
766 * Allocate and intialize a fake/representative OSKext object for a statically
767 * loaded (by iBoot) binary (e.g., the XNU kernel itself).
768 *
769 * @param kmod_info Pointer to the kmod_info structure for the binary being
770 * setup. At least the "name" and "id" fields needs to already
771 * be set correctly.
772 *
773 * @return The allocated and initialized OSKext object.
774 */
775 /* static */
776 OSKext *
allocAndInitFakeKext(kmod_info_t * kmod_info)777 OSKext::allocAndInitFakeKext(kmod_info_t *kmod_info)
778 {
779 vm_offset_t load_address = 0;
780 const char *bundle_name = NULL;
781 bool macho_is_unslid = false;
782 bool set_custom_path = false;
783 const char *executable_fallback_name = NULL;
784
785 if (kmod_info->id == kOSKextKernelLoadTag) {
786 load_address = (vm_offset_t)&_mh_execute_header;
787 bundle_name = "mach_kernel";
788
789 /* The kernel Mach-O header is fixed up to slide all of its addresses. */
790 macho_is_unslid = false;
791
792 /**
793 * No path to the binary is set for the kernel in its OSKext object. The
794 * kernel binary is located in fixed directories depending on the OS.
795 */
796 set_custom_path = false;
797 executable_fallback_name = NULL;
798 } else {
799 panic("%s: Unsupported kmod_info->id (%d)", __func__, kmod_info->id);
800 }
801
802 /* Set up an OSKext instance to represent the statically loaded binary. */
803 OSKext *fakeKext = new OSKext;
804 assert(fakeKext);
805 assert(load_address != 0);
806
807 /*
808 * The start address is always a slid address whereas the last VA returned
809 * by getlastaddr() might be unslid depending on the Mach-O. If the address
810 * coming from the Mach-O is unslid, then unslide the start address before
811 * computing the length of the executable.
812 */
813 size_t binaryLength = getlastaddr((kernel_mach_header_t*)load_address);
814 binaryLength -= (macho_is_unslid) ? ml_static_unslide(load_address) : load_address;
815 assert(binaryLength <= UINT_MAX);
816
817 /**
818 * The load address is always slid. That value will be unslid before being
819 * exposed to userspace.
820 */
821 OSSharedPtr<OSData> executable = OSData::withBytesNoCopy(
822 (void*)load_address, (unsigned int)binaryLength);
823 assert(executable);
824
825 fakeKext->loadTag = sNextLoadTag++;
826 fakeKext->bundleID = OSSymbol::withCString(kmod_info->name);
827
828 fakeKext->version = OSKextParseVersionString(osrelease);
829 fakeKext->compatibleVersion = fakeKext->version;
830 fakeKext->linkedExecutable = os::move(executable);
831 fakeKext->interfaceUUID = fakeKext->copyUUID();
832
833 fakeKext->flags.hasAllDependencies = 1;
834 fakeKext->flags.kernelComponent = 1;
835 fakeKext->flags.prelinked = 0;
836 fakeKext->flags.loaded = 1;
837 fakeKext->flags.started = 1;
838 fakeKext->flags.CPPInitialized = 0;
839 fakeKext->flags.jettisonLinkeditSeg = 0;
840 fakeKext->flags.unslidMachO = macho_is_unslid;
841
842
843 fakeKext->kmod_info = kmod_info;
844 strlcpy(kmod_info->version, osrelease,
845 sizeof(kmod_info->version));
846 kmod_info->size = binaryLength;
847 assert(kmod_info->id == fakeKext->loadTag);
848
849 /*
850 * Con up an info dict, so we don't have to have special-case checking all
851 * over.
852 */
853 fakeKext->infoDict = OSDictionary::withCapacity(5);
854 assert(fakeKext->infoDict);
855 bool setResult = fakeKext->infoDict->setObject(kCFBundleIdentifierKey,
856 fakeKext->bundleID.get());
857 assert(setResult);
858 setResult = fakeKext->infoDict->setObject(kOSKernelResourceKey,
859 kOSBooleanTrue);
860 assert(setResult);
861
862 {
863 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
864 assert(scratchString);
865 setResult = fakeKext->infoDict->setObject(kCFBundleVersionKey,
866 scratchString.get());
867 assert(setResult);
868 }
869
870 {
871 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(bundle_name));
872 assert(scratchString);
873 setResult = fakeKext->infoDict->setObject(kCFBundleNameKey,
874 scratchString.get());
875 assert(setResult);
876 }
877
878 return fakeKext;
879 }
880
881 /* static */
882 void
initialize(void)883 OSKext::initialize(void)
884 {
885 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
886 IORegistryEntry * registryRoot = NULL;// do not release
887 OSSharedPtr<OSNumber> kernelCPUType;
888 OSSharedPtr<OSNumber> kernelCPUSubtype;
889 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
890 bool setResult = false;
891 uint64_t * timestamp = NULL;
892 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
893
894 /* This must be the first thing allocated. Everything else grabs this lock.
895 */
896 sKextLock = IORecursiveLockAlloc();
897 sKextInnerLock = IORecursiveLockAlloc();
898 sKextSummariesLock = IOLockAlloc();
899 sKextLoggingLock = IOLockAlloc();
900 assert(sKextLock);
901 assert(sKextInnerLock);
902 assert(sKextSummariesLock);
903 assert(sKextLoggingLock);
904
905 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
906 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
907 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
908 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
909 sKernelRequests = OSArray::withCapacity(0);
910 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
911 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
912 sRequestCallbackRecords = OSArray::withCapacity(0);
913 sDriverKitToUpgradeByID = OSDictionary::withCapacity(kOSKextTypicalUpgradeCount);
914
915 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
916 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
917 sRequestCallbackRecords && sUnloadedPrelinkedKexts && sDriverKitToUpgradeByID);
918
919 /* Read the log flag boot-args and set the log flags.
920 */
921 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
922 sBootArgLogFilterFound = true;
923 sKernelLogFilter = bootLogFilter;
924 // log this if any flags are set
925 OSKextLog(/* kext */ NULL,
926 kOSKextLogBasicLevel |
927 kOSKextLogFlagsMask,
928 "Kernel kext log filter 0x%x per kextlog boot arg.",
929 (unsigned)sKernelLogFilter);
930 }
931
932 #if !defined(__arm__) && !defined(__arm64__)
933 /*
934 * On our ARM targets, the kernelcache/boot kernel collection contains
935 * the set of kexts required to boot, as specified by KCB. Safeboot is
936 * either unsupported, or is supported by the bootloader only loading
937 * the boot kernel collection; as a result OSKext has no role to play
938 * in safeboot policy on ARM.
939 */
940 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
941 sizeof(bootArgBuffer)) ? true : false;
942 #endif /* defined(__arm__) && defined(__arm64__) */
943
944 if (sSafeBoot) {
945 OSKextLog(/* kext */ NULL,
946 kOSKextLogWarningLevel |
947 kOSKextLogGeneralFlag,
948 "SAFE BOOT DETECTED - "
949 "only valid OSBundleRequired kexts will be loaded.");
950 }
951
952 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
953 #if CONFIG_DTRACE
954 if (dtrace_keep_kernel_symbols()) {
955 sKeepSymbols = true;
956 }
957 #endif /* CONFIG_DTRACE */
958 #if KASAN_DYNAMIC_BLACKLIST
959 /* needed for function lookup */
960 sKeepSymbols = true;
961 #endif
962
963 /*
964 * Should we panic when the SystemKC is not linked against the
965 * BootKC that was loaded by the booter? By default: yes, if the
966 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
967 * on mis-match and instead just print an error and continue.
968 */
969 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
970 sizeof(bootArgBuffer)) ? false : true;
971
972 /* Set up an OSKext instance to represent the kernel itself. */
973 sKernelKext = allocAndInitFakeKext(&g_kernel_kmod_info);
974 assert(sKernelKext);
975
976
977 /* Add the kernel kext to the bookkeeping dictionaries. Note that
978 * the kernel kext doesn't have a kmod_info struct. copyInfo()
979 * gathers info from other places anyhow.
980 */
981 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
982 assert(setResult);
983 setResult = sLoadedKexts->setObject(sKernelKext);
984 assert(setResult);
985
986
987 // XXX: better way with OSSharedPtr?
988 // sKernelKext remains a valid pointer even after the decref
989 sKernelKext->release();
990
991 registryRoot = IORegistryEntry::getRegistryRoot();
992 kernelCPUType = OSNumber::withNumber(
993 (long long unsigned int)_mh_execute_header.cputype,
994 8 * sizeof(_mh_execute_header.cputype));
995 kernelCPUSubtype = OSNumber::withNumber(
996 (long long unsigned int)_mh_execute_header.cpusubtype,
997 8 * sizeof(_mh_execute_header.cpusubtype));
998 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
999
1000 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
1001 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
1002
1003 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
1004 if (gBuiltinKmodsSectionInfo) {
1005 uint32_t count;
1006
1007 assert(gBuiltinKmodsSectionInfo->addr);
1008 assert(gBuiltinKmodsSectionInfo->size);
1009 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
1010 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
1011
1012 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
1013 assert(gBuiltinKmodsSectionStart);
1014 assert(gBuiltinKmodsSectionStart->addr);
1015 assert(gBuiltinKmodsSectionStart->size);
1016 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
1017 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
1018 // one extra pointer for the end of last kmod
1019 assert(count == (gBuiltinKmodsCount + 1));
1020
1021 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
1022 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
1023 }
1024
1025 // Don't track this object -- it's never released
1026 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
1027
1028 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
1029 *timestamp = 0;
1030 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
1031 *timestamp = 0;
1032 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
1033 *timestamp = 0;
1034
1035 OSKextLog(/* kext */ NULL,
1036 kOSKextLogProgressLevel |
1037 kOSKextLogGeneralFlag,
1038 "Kext system initialized.");
1039
1040 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
1041
1042 return;
1043 }
1044
1045 /*********************************************************************
1046 * This is expected to be called exactly once, from exactly one thread
1047 * context, during kernel bootstrap.
1048 *********************************************************************/
1049 /* static */
1050 OSReturn
removeKextBootstrap(void)1051 OSKext::removeKextBootstrap(void)
1052 {
1053 OSReturn result = kOSReturnError;
1054
1055 const char * dt_kernel_header_name = "Kernel-__HEADER";
1056 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
1057 kernel_mach_header_t * dt_mach_header = NULL;
1058 int dt_mach_header_size = 0;
1059 struct symtab_command * dt_symtab = NULL;
1060 int dt_symtab_size = 0;
1061 int dt_result = 0;
1062
1063 kernel_segment_command_t * seg_kld = NULL;
1064 kernel_segment_command_t * seg_klddata = NULL;
1065 kernel_segment_command_t * seg_linkedit = NULL;
1066
1067 const char __unused * dt_segment_name = NULL;
1068 void __unused * segment_paddress = NULL;
1069 int __unused segment_size = 0;
1070
1071 OSKextLog(/* kext */ NULL,
1072 kOSKextLogProgressLevel |
1073 kOSKextLogGeneralFlag,
1074 "Jettisoning kext bootstrap segments.");
1075
1076 /*
1077 * keep the linkedit segment around when booted from a new MH_FILESET
1078 * KC because all the kexts shared a linkedit segment.
1079 */
1080 kc_format_t kc_format;
1081 if (!PE_get_primary_kc_format(&kc_format)) {
1082 OSKextLog(/* kext */ NULL,
1083 kOSKextLogErrorLevel |
1084 kOSKextLogGeneralFlag,
1085 "Unable to determine primary KC format");
1086 }
1087
1088 /*****
1089 * Dispose of unnecessary stuff that the booter didn't need to load.
1090 */
1091 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1092 (void **)&dt_mach_header, &dt_mach_header_size);
1093 if (dt_result == 0 && dt_mach_header) {
1094 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1095 round_page_32(dt_mach_header_size));
1096 }
1097 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1098 (void **)&dt_symtab, &dt_symtab_size);
1099 if (dt_result == 0 && dt_symtab) {
1100 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1101 round_page_32(dt_symtab_size));
1102 }
1103
1104 /*****
1105 * KLD & KLDDATA bootstrap segments.
1106 */
1107 // xxx - should rename KLD segment
1108 seg_kld = getsegbyname("__KLD");
1109 seg_klddata = getsegbyname("__KLDDATA");
1110 if (seg_klddata) {
1111 // __mod_term_func is part of __KLDDATA
1112 OSRuntimeUnloadCPPForSegment(seg_klddata);
1113 }
1114
1115 #if __arm__ || __arm64__
1116 /* Free the memory that was set up by iBoot.
1117 */
1118 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1119 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1120 * is covered by the contiguous rorgn.
1121 */
1122 dt_segment_name = "Kernel-__KLD";
1123 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1124 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1125 (int)segment_size); // calls ml_static_mfree
1126 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1127 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1128 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1129 seg_kld->vmsize);
1130 }
1131 #endif
1132 dt_segment_name = "Kernel-__KLDDATA";
1133 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1134 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1135 (int)segment_size); // calls ml_static_mfree
1136 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1137 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1138 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1139 seg_klddata->vmsize);
1140 }
1141 #elif __i386__ || __x86_64__
1142 /* On x86, use the mapping data from the segment load command to
1143 * unload KLD & KLDDATA directly.
1144 * This may invalidate any assumptions about "avail_start"
1145 * defining the lower bound for valid physical addresses.
1146 */
1147 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1148 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1149 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1150 }
1151 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1152 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1153 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1154 }
1155 #else
1156 #error arch
1157 #endif
1158
1159 /*****
1160 * Prelinked kernel's symtab (if there is one).
1161 */
1162 if (kc_format != KCFormatFileset) {
1163 kernel_section_t * sect;
1164 sect = getsectbyname("__PRELINK", "__symtab");
1165 if (sect && sect->addr && sect->size) {
1166 ml_static_mfree(sect->addr, sect->size);
1167 }
1168 }
1169
1170 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1171
1172 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1173 * pageable, unless keepsyms is set. To do that, we have to copy it from
1174 * its booter-allocated memory, free the booter memory, reallocate proper
1175 * managed memory, then copy the segment back in.
1176 *
1177 * NOTE: This optimization is not valid for fileset KCs because each
1178 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1179 * that points to one fileset-global LINKEDIT segment. This
1180 * optimization is also only valid for platforms that support vm
1181 * mapped kexts or mapped kext collections (pageable KCs)
1182 */
1183 #if VM_MAPPED_KEXTS
1184 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1185 kern_return_t mem_result;
1186 void *seg_copy = NULL;
1187 void *seg_data = NULL;
1188 vm_map_offset_t seg_offset = 0;
1189 vm_map_offset_t seg_copy_offset = 0;
1190 vm_map_size_t seg_length = 0;
1191
1192 seg_data = (void *) seg_linkedit->vmaddr;
1193 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1194 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1195
1196 /* Allocate space for the LINKEDIT copy.
1197 */
1198 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1199 seg_length, KMA_ZERO, VM_KERN_MEMORY_KEXT);
1200 if (mem_result != KERN_SUCCESS) {
1201 OSKextLog(/* kext */ NULL,
1202 kOSKextLogErrorLevel |
1203 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1204 "Can't copy __LINKEDIT segment for VM reassign.");
1205 return result;
1206 }
1207 seg_copy_offset = (vm_map_offset_t) seg_copy;
1208
1209 /* Copy it out.
1210 */
1211 memcpy(seg_copy, seg_data, seg_length);
1212
1213 /* Dump the booter memory.
1214 */
1215 ml_static_mfree(seg_offset, seg_length);
1216
1217 /* Set up the VM region.
1218 */
1219 mem_result = vm_map_enter_mem_object(
1220 kernel_map,
1221 &seg_offset,
1222 seg_length, /* mask */ 0,
1223 VM_MAP_KERNEL_FLAGS_FIXED(.vmf_overwrite = true),
1224 (ipc_port_t)NULL,
1225 (vm_object_offset_t) 0,
1226 /* copy */ FALSE,
1227 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1228 /* max_protection */ VM_PROT_ALL,
1229 /* inheritance */ VM_INHERIT_DEFAULT);
1230 if ((mem_result != KERN_SUCCESS) ||
1231 (seg_offset != (vm_map_offset_t) seg_data)) {
1232 OSKextLog(/* kext */ NULL,
1233 kOSKextLogErrorLevel |
1234 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1235 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1236 seg_data, seg_length, mem_result);
1237 return result;
1238 }
1239
1240 /* And copy it back.
1241 */
1242 memcpy(seg_data, seg_copy, seg_length);
1243
1244 /* Free the copy.
1245 */
1246 kmem_free(kernel_map, seg_copy_offset, seg_length);
1247 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1248 /* Remove the linkedit segment of the Boot KC */
1249 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1250 OSKext::jettisonFileSetLinkeditSegment(mh);
1251 }
1252 #else // !VM_MAPPED_KEXTS
1253 /*****
1254 * Dump the LINKEDIT segment, unless keepsyms is set.
1255 */
1256 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1257 dt_segment_name = "Kernel-__LINKEDIT";
1258 if (0 == IODTGetLoaderInfo(dt_segment_name,
1259 &segment_paddress, &segment_size)) {
1260 #ifdef SECURE_KERNEL
1261 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1262 bzero((void*)vmaddr, segment_size);
1263 #endif
1264 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1265 (int)segment_size);
1266 }
1267 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1268 /* Remove the linkedit segment of the Boot KC */
1269 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1270 OSKext::jettisonFileSetLinkeditSegment(mh);
1271 } else {
1272 OSKextLog(/* kext */ NULL,
1273 kOSKextLogBasicLevel |
1274 kOSKextLogGeneralFlag,
1275 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1276 }
1277 #endif // VM_MAPPED_KEXTS
1278
1279 result = kOSReturnSuccess;
1280
1281 return result;
1282 }
1283
1284 #if CONFIG_KXLD
1285 /*********************************************************************
1286 *********************************************************************/
1287 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1288 OSKext::flushNonloadedKexts(
1289 Boolean flushPrelinkedKexts)
1290 {
1291 OSSharedPtr<OSSet> keepKexts;
1292
1293 /* TODO: make this more efficient with MH_FILESET kexts */
1294
1295 // Do not unload prelinked kexts on arm because the kernelcache is not
1296 // structured in a way that allows them to be unmapped
1297 #if !defined(__x86_64__)
1298 flushPrelinkedKexts = false;
1299 #endif /* defined(__x86_64__) */
1300
1301 IORecursiveLockLock(sKextLock);
1302
1303 OSKextLog(/* kext */ NULL,
1304 kOSKextLogProgressLevel |
1305 kOSKextLogKextBookkeepingFlag,
1306 "Flushing nonloaded kexts and other unused data.");
1307
1308 OSKext::considerDestroyingLinkContext();
1309
1310 /* If we aren't flushing unused prelinked kexts, we have to put them
1311 * aside while we flush everything else so make a container for them.
1312 */
1313 keepKexts = OSSet::withCapacity(16);
1314 if (!keepKexts) {
1315 goto finish;
1316 }
1317
1318 /* Set aside prelinked kexts (in-use or not) and break
1319 * any lingering inter-kext references for nonloaded kexts
1320 * so they have min. retain counts.
1321 */
1322 {
1323 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1324 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1325 if (!thisKext) {
1326 return false;
1327 }
1328 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1329 keepKexts->setObject(thisKext);
1330 } else if (!thisKext->declaresExecutable()) {
1331 /*
1332 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1333 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1334 * flushNonloadedKexts().
1335 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1336 */
1337 keepKexts->setObject(thisKext);
1338 } else if (thisKext->isInFileset()) {
1339 /* keep all kexts in the new MH_FILESET KC */
1340 keepKexts->setObject(thisKext);
1341 }
1342
1343 thisKext->flushDependencies(/* forceIfLoaded */ false);
1344 return false;
1345 });
1346 }
1347 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1348 */
1349 sKextsByID->flushCollection();
1350
1351 /* Now put the loaded kexts back into the ID dictionary.
1352 */
1353 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1354 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1355 if (!thisKext) {
1356 return false;
1357 }
1358 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1359 return false;
1360 });
1361
1362 /* Finally, put back the kept kexts if we saved any.
1363 */
1364 keepKexts->iterateObjects(^bool (OSObject * obj) {
1365 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1366 if (!thisKext) {
1367 return false;
1368 }
1369 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1370 return false;
1371 });
1372
1373 finish:
1374 IORecursiveLockUnlock(sKextLock);
1375 return;
1376 }
1377 #else /* !CONFIG_KXLD */
1378
1379 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1380 OSKext::flushNonloadedKexts(
1381 Boolean flushPrelinkedKexts __unused)
1382 {
1383 IORecursiveLockLock(sKextLock);
1384
1385 OSKextLog(/* kext */ NULL,
1386 kOSKextLogProgressLevel |
1387 kOSKextLogKextBookkeepingFlag,
1388 "Flushing dependency info for non-loaded kexts.");
1389
1390 /*
1391 * In a world where we don't dynamically link kexts, they all come
1392 * from a kext collection that's either in wired memory, or
1393 * wire-on-demand. We don't need to mess around with moving kexts in
1394 * and out of the sKextsByID array - they can all just stay there.
1395 * Here we just flush the dependency list for kexts that are not
1396 * loaded.
1397 */
1398 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1399 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1400 if (!thisKext) {
1401 return false;
1402 }
1403 thisKext->flushDependencies(/* forceIfLoaded */ false);
1404 return false;
1405 });
1406
1407 IORecursiveLockUnlock(sKextLock);
1408 return;
1409 }
1410
1411 #endif /* CONFIG_KXLD */
1412
1413 /*********************************************************************
1414 *********************************************************************/
1415 /* static */
1416 void
setIOKitDaemonActive(bool active)1417 OSKext::setIOKitDaemonActive(bool active)
1418 {
1419 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1420 IORecursiveLockLock(sKextLock);
1421 sIOKitDaemonActive = active;
1422 if (sKernelRequests->getCount()) {
1423 OSKext::pingIOKitDaemon();
1424 }
1425 IORecursiveLockUnlock(sKextLock);
1426
1427 return;
1428 }
1429
1430 /*********************************************************************
1431 * OSKextLib.cpp might need access to this someday but for now it's
1432 * private.
1433 *********************************************************************/
1434 extern "C" {
1435 extern void ipc_port_release_send(ipc_port_t);
1436 };
1437
1438 /* static */
1439 OSReturn
pingIOKitDaemon(void)1440 OSKext::pingIOKitDaemon(void)
1441 {
1442 OSReturn result = kOSReturnError;
1443 #if !NO_KEXTD
1444 mach_port_t kextd_port = IPC_PORT_NULL;
1445
1446 if (!sIOKitDaemonActive) {
1447 result = kOSKextReturnDisabled; // basically unavailable
1448 goto finish;
1449 }
1450
1451 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1452 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1453 OSKextLog(/* kext */ NULL,
1454 kOSKextLogErrorLevel |
1455 kOSKextLogIPCFlag,
1456 "Can't get " kIOKitDaemonName " port.");
1457 goto finish;
1458 }
1459
1460 result = kextd_ping(kextd_port);
1461 if (result != KERN_SUCCESS) {
1462 OSKextLog(/* kext */ NULL,
1463 kOSKextLogErrorLevel |
1464 kOSKextLogIPCFlag,
1465 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1466 goto finish;
1467 }
1468
1469 finish:
1470 if (IPC_PORT_VALID(kextd_port)) {
1471 ipc_port_release_send(kextd_port);
1472 }
1473 #endif
1474
1475 return result;
1476 }
1477
1478 /*********************************************************************
1479 *********************************************************************/
1480 /* static */
1481 bool
iokitDaemonAvailable(void)1482 OSKext::iokitDaemonAvailable(void)
1483 {
1484 int notused;
1485 if (PE_parse_boot_argn("-restore", ¬used, sizeof(notused))) {
1486 return false;
1487 }
1488 return true;
1489 }
1490
1491 /*********************************************************************
1492 *********************************************************************/
1493 /* static */
1494 void
setDeferredLoadSucceeded(Boolean succeeded)1495 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1496 {
1497 IORecursiveLockLock(sKextLock);
1498 sDeferredLoadSucceeded = succeeded;
1499 IORecursiveLockUnlock(sKextLock);
1500
1501 return;
1502 }
1503
1504 /*********************************************************************
1505 * Called from IOSystemShutdownNotification.
1506 *********************************************************************/
1507 /* static */
1508 void
willShutdown(void)1509 OSKext::willShutdown(void)
1510 {
1511 #if !NO_KEXTD
1512 OSReturn checkResult = kOSReturnError;
1513 #endif
1514 OSSharedPtr<OSDictionary> exitRequest;
1515
1516 IORecursiveLockLock(sKextLock);
1517
1518 OSKext::setLoadEnabled(false);
1519 OSKext::setUnloadEnabled(false);
1520 OSKext::setAutounloadsEnabled(false);
1521 OSKext::setKernelRequestsEnabled(false);
1522
1523 #if defined(__x86_64__) || defined(__i386__)
1524 if (IOPMRootDomainGetWillShutdown()) {
1525 OSKext::freeKCFileSetcontrol();
1526 }
1527 #endif // (__x86_64__) || defined(__i386__)
1528
1529 #if !NO_KEXTD
1530 OSKextLog(/* kext */ NULL,
1531 kOSKextLogProgressLevel |
1532 kOSKextLogGeneralFlag,
1533 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1534
1535 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1536 exitRequest);
1537 if (checkResult != kOSReturnSuccess) {
1538 goto finish;
1539 }
1540 if (!sKernelRequests->setObject(exitRequest.get())) {
1541 goto finish;
1542 }
1543
1544 OSKext::pingIOKitDaemon();
1545
1546 finish:
1547 #endif
1548
1549 IORecursiveLockUnlock(sKextLock);
1550 return;
1551 }
1552
1553 void
willUserspaceReboot(void)1554 OSKext::willUserspaceReboot(void)
1555 {
1556 OSKext::willShutdown();
1557 IOService::userSpaceWillReboot();
1558 gIOCatalogue->terminateDriversForUserspaceReboot();
1559 }
1560
1561 void
resetAfterUserspaceReboot(void)1562 OSKext::resetAfterUserspaceReboot(void)
1563 {
1564 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1565 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1566
1567 IORecursiveLockLock(sKextLock);
1568 gIOCatalogue->resetAfterUserspaceReboot();
1569 IOService::userSpaceDidReboot();
1570 OSKext::removeDaemonExitRequests();
1571 OSKext::setLoadEnabled(true);
1572 OSKext::setUnloadEnabled(true);
1573 OSKext::setAutounloadsEnabled(true);
1574 OSKext::setKernelRequestsEnabled(true);
1575 sOSKextWasResetAfterUserspaceReboot = true;
1576 IORecursiveLockUnlock(sKextLock);
1577 }
1578
1579 extern "C" void
OSKextResetAfterUserspaceReboot(void)1580 OSKextResetAfterUserspaceReboot(void)
1581 {
1582 OSKext::resetAfterUserspaceReboot();
1583 }
1584
1585 /*
1586 * Remove daemon exit requests from sKernelRequests
1587 *
1588 * If we sent a daemon exit request during a userspace reboot and launchd
1589 * killed the IOKit daemon before it was able to dequeue the exit request, the
1590 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1591 *
1592 * This removes exit requests so that this does not happen.
1593 */
1594 void
removeDaemonExitRequests(void)1595 OSKext::removeDaemonExitRequests(void)
1596 {
1597 OSDictionary * current = NULL;
1598 OSString * predicate = NULL;
1599 size_t index = 0;
1600 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1601
1602 while (index < sKernelRequests->getCount()) {
1603 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1604 if (current) {
1605 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1606 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1607 sKernelRequests->removeObject(index);
1608 continue;
1609 }
1610 }
1611 index++;
1612 }
1613 }
1614
1615 /*********************************************************************
1616 *********************************************************************/
1617 /* static */
1618 bool
getLoadEnabled(void)1619 OSKext::getLoadEnabled(void)
1620 {
1621 bool result;
1622
1623 IORecursiveLockLock(sKextLock);
1624 result = sLoadEnabled;
1625 IORecursiveLockUnlock(sKextLock);
1626 return result;
1627 }
1628
1629 /*********************************************************************
1630 *********************************************************************/
1631 /* static */
1632 bool
setLoadEnabled(bool flag)1633 OSKext::setLoadEnabled(bool flag)
1634 {
1635 bool result;
1636
1637 IORecursiveLockLock(sKextLock);
1638 result = sLoadEnabled;
1639 sLoadEnabled = (flag ? true : false);
1640
1641 if (sLoadEnabled != result) {
1642 OSKextLog(/* kext */ NULL,
1643 kOSKextLogBasicLevel |
1644 kOSKextLogLoadFlag,
1645 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1646 }
1647
1648 IORecursiveLockUnlock(sKextLock);
1649
1650 return result;
1651 }
1652
1653 /*********************************************************************
1654 *********************************************************************/
1655 /* static */
1656 bool
getUnloadEnabled(void)1657 OSKext::getUnloadEnabled(void)
1658 {
1659 bool result;
1660
1661 IORecursiveLockLock(sKextLock);
1662 result = sUnloadEnabled;
1663 IORecursiveLockUnlock(sKextLock);
1664 return result;
1665 }
1666
1667 /*********************************************************************
1668 *********************************************************************/
1669 /* static */
1670 bool
setUnloadEnabled(bool flag)1671 OSKext::setUnloadEnabled(bool flag)
1672 {
1673 bool result;
1674
1675 IORecursiveLockLock(sKextLock);
1676 result = sUnloadEnabled;
1677 sUnloadEnabled = (flag ? true : false);
1678 IORecursiveLockUnlock(sKextLock);
1679
1680 if (sUnloadEnabled != result) {
1681 OSKextLog(/* kext */ NULL,
1682 kOSKextLogBasicLevel |
1683 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1684 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1685 }
1686
1687 return result;
1688 }
1689
1690 /*********************************************************************
1691 * Do not call any function that takes sKextLock here!
1692 *********************************************************************/
1693 /* static */
1694 bool
getAutounloadEnabled(void)1695 OSKext::getAutounloadEnabled(void)
1696 {
1697 #if XNU_TARGET_OS_OSX
1698 bool result;
1699
1700 IORecursiveLockLock(sKextInnerLock);
1701 result = sAutounloadEnabled ? true : false;
1702 IORecursiveLockUnlock(sKextInnerLock);
1703 return result;
1704 #else
1705 return false;
1706 #endif /* XNU_TARGET_OS_OSX */
1707 }
1708
1709 /*********************************************************************
1710 * Do not call any function that takes sKextLock here!
1711 *********************************************************************/
1712 /* static */
1713 bool
setAutounloadsEnabled(bool flag)1714 OSKext::setAutounloadsEnabled(bool flag)
1715 {
1716 #if XNU_TARGET_OS_OSX
1717 bool result;
1718
1719 IORecursiveLockLock(sKextInnerLock);
1720
1721 result = sAutounloadEnabled;
1722 sAutounloadEnabled = (flag ? true : false);
1723 if (!sAutounloadEnabled && sUnloadCallout) {
1724 thread_call_cancel(sUnloadCallout);
1725 }
1726
1727 if (sAutounloadEnabled != result) {
1728 OSKextLog(/* kext */ NULL,
1729 kOSKextLogBasicLevel |
1730 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1731 "Kext autounloading now %sabled.",
1732 sAutounloadEnabled ? "en" : "dis");
1733 }
1734
1735 IORecursiveLockUnlock(sKextInnerLock);
1736
1737 return result;
1738 #else
1739 (void)flag;
1740 return false;
1741 #endif /* XNU_TARGET_OS_OSX */
1742 }
1743
1744 /*********************************************************************
1745 *********************************************************************/
1746 /* instance method operating on OSKext field */
1747 bool
setAutounloadEnabled(bool flag)1748 OSKext::setAutounloadEnabled(bool flag)
1749 {
1750 bool result = flags.autounloadEnabled ? true : false;
1751 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1752
1753 if (result != (flag ? true : false)) {
1754 OSKextLog(this,
1755 kOSKextLogProgressLevel |
1756 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1757 "Autounloading for kext %s now %sabled.",
1758 getIdentifierCString(),
1759 flags.autounloadEnabled ? "en" : "dis");
1760 }
1761 return result;
1762 }
1763
1764 /*********************************************************************
1765 *********************************************************************/
1766 /* static */
1767 bool
setKernelRequestsEnabled(bool flag)1768 OSKext::setKernelRequestsEnabled(bool flag)
1769 {
1770 bool result;
1771
1772 IORecursiveLockLock(sKextLock);
1773 result = sKernelRequestsEnabled;
1774 sKernelRequestsEnabled = flag ? true : false;
1775
1776 if (sKernelRequestsEnabled != result) {
1777 OSKextLog(/* kext */ NULL,
1778 kOSKextLogBasicLevel |
1779 kOSKextLogGeneralFlag,
1780 "Kernel requests now %sabled.",
1781 sKernelRequestsEnabled ? "en" : "dis");
1782 }
1783 IORecursiveLockUnlock(sKextLock);
1784 return result;
1785 }
1786
1787 /*********************************************************************
1788 *********************************************************************/
1789 /* static */
1790 bool
getKernelRequestsEnabled(void)1791 OSKext::getKernelRequestsEnabled(void)
1792 {
1793 bool result;
1794
1795 IORecursiveLockLock(sKextLock);
1796 result = sKernelRequestsEnabled;
1797 IORecursiveLockUnlock(sKextLock);
1798 return result;
1799 }
1800
1801 static bool
segmentIsMutable(kernel_segment_command_t * seg)1802 segmentIsMutable(kernel_segment_command_t *seg)
1803 {
1804 /* Mutable segments have to have VM_PROT_WRITE */
1805 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1806 return false;
1807 }
1808 /* Exclude the __DATA_CONST segment */
1809 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1810 return false;
1811 }
1812 /* Exclude __LINKEDIT */
1813 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1814 return false;
1815 }
1816 return true;
1817 }
1818
1819 #if PRAGMA_MARK
1820 #pragma mark Kext Life Cycle
1821 #endif
1822 /*********************************************************************
1823 *********************************************************************/
1824 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1825 OSKext::withPrelinkedInfoDict(
1826 OSDictionary * anInfoDict,
1827 bool doCoalescedSlides,
1828 kc_kind_t type)
1829 {
1830 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1831
1832 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1833 return NULL;
1834 }
1835
1836 return newKext;
1837 }
1838
1839 OSData *
parseDextUniqueID(OSDictionary * anInfoDict,const char * dextIDCS)1840 OSKext::parseDextUniqueID(
1841 OSDictionary * anInfoDict,
1842 const char *dextIDCS)
1843 {
1844 OSData *ret = NULL;
1845 OSData *data_duid = OSDynamicCast(OSData, anInfoDict->getObject(kOSBundleDextUniqueIdentifierKey));
1846 if (data_duid != NULL) {
1847 if (data_duid->getLength() > KOSBundleDextUniqueIdentifierMaxLength) {
1848 OSKextLog(NULL,
1849 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1850 "Dext %s DextUniqueIdentifier too long.",
1851 dextIDCS);
1852 } else {
1853 /*
1854 * If the DextUniqueID exists it should be
1855 * present also into the personalities.
1856 */
1857 setDextUniqueIDInPersonalities(anInfoDict, data_duid);
1858 ret = data_duid;
1859 }
1860 } else {
1861 OSKextLog(NULL,
1862 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1863 "Dext %s does not have a DextUniqueIdentifier",
1864 dextIDCS);
1865 }
1866 return ret;
1867 }
1868
1869 void
setDextUniqueIDInPersonalities(OSDictionary * anInfoDict,OSData * dextUniqueID)1870 OSKext::setDextUniqueIDInPersonalities(
1871 OSDictionary * anInfoDict,
1872 OSData * dextUniqueID)
1873 {
1874 OSDictionary * dextPersonalities = NULL;
1875 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
1876 OSString * personalityName = NULL;
1877
1878 dextPersonalities = OSDynamicCast(OSDictionary,
1879 anInfoDict->getObject(kIOKitPersonalitiesKey));
1880 if (!dextPersonalities || !dextPersonalities->getCount()) {
1881 return;
1882 }
1883
1884 personalitiesIterator =
1885 OSCollectionIterator::withCollection(dextPersonalities);
1886 if (!personalitiesIterator) {
1887 return;
1888 }
1889 while ((personalityName = OSDynamicCast(OSString,
1890 personalitiesIterator->getNextObject()))) {
1891 OSDictionary * personality = OSDynamicCast(OSDictionary,
1892 dextPersonalities->getObject(personalityName));
1893 if (personality) {
1894 OSObject *duid = personality->getObject(kOSBundleDextUniqueIdentifierKey);
1895 if (duid == NULL) {
1896 personality->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID);
1897 }
1898 }
1899 }
1900 }
1901 /*********************************************************************
1902 *********************************************************************/
1903 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1904 OSKext::initWithPrelinkedInfoDict(
1905 OSDictionary * anInfoDict,
1906 bool doCoalescedSlides,
1907 kc_kind_t type)
1908 {
1909 bool result = false;
1910 OSString * kextPath = NULL; // do not release
1911 OSNumber * addressNum = NULL; // reused; do not release
1912 OSNumber * lengthNum = NULL; // reused; do not release
1913 OSBoolean * scratchBool = NULL; // do not release
1914 void * data = NULL; // do not free
1915 void * srcData = NULL; // do not free
1916 OSSharedPtr<OSData> prelinkedExecutable;
1917 uint32_t length = 0; // reused
1918 uintptr_t kext_slide = PE_get_kc_slide(type);
1919 bool shouldSaveSegments = false;
1920 kc_format format = KCFormatUnknown;
1921
1922 if (!super::init()) {
1923 goto finish;
1924 }
1925
1926 /* Get the path. Don't look for an arch-specific path property.
1927 */
1928 kextPath = OSDynamicCast(OSString,
1929 anInfoDict->getObject(kPrelinkBundlePathKey));
1930
1931 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1932 goto finish;
1933 }
1934
1935 #if KASLR_KEXT_DEBUG
1936 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1937 #endif
1938
1939 /* Also get the executable's bundle-relative path if present.
1940 * Don't look for an arch-specific path property.
1941 */
1942 executableRelPath.reset(OSDynamicCast(OSString,
1943 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1944 userExecutableRelPath.reset(OSDynamicCast(OSString,
1945 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1946
1947 /* Don't need the paths to be in the info dictionary any more.
1948 */
1949 anInfoDict->removeObject(kPrelinkBundlePathKey);
1950 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1951
1952 scratchBool = OSDynamicCast(OSBoolean,
1953 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1954 if (scratchBool == kOSBooleanTrue) {
1955 flags.requireExplicitLoad = 1;
1956 }
1957
1958 /* Create an OSData wrapper around the linked executable.
1959 */
1960 addressNum = OSDynamicCast(OSNumber,
1961 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1962 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1963 lengthNum = OSDynamicCast(OSNumber,
1964 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1965 if (!lengthNum) {
1966 OSKextLog(this,
1967 kOSKextLogErrorLevel |
1968 kOSKextLogArchiveFlag,
1969 "Kext %s can't find prelinked kext executable size.",
1970 getIdentifierCString());
1971 return result;
1972 }
1973
1974 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1975 length = (uint32_t) (lengthNum->unsigned32BitValue());
1976
1977 #if KASLR_KEXT_DEBUG
1978 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1979 (unsigned long)ml_static_unslide((vm_offset_t)data),
1980 (unsigned long)data,
1981 length);
1982 #endif
1983
1984 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1985 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1986
1987 /* If the kext's load address differs from its source address, allocate
1988 * space in the kext map at the load address and copy the kext over.
1989 */
1990 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1991 if (addressNum) {
1992 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1993
1994 #if KASLR_KEXT_DEBUG
1995 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1996 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1997 (unsigned long)srcData);
1998 #endif
1999
2000 if (data != srcData) {
2001 #if __LP64__
2002 kern_return_t alloc_result;
2003
2004 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
2005 if (alloc_result != KERN_SUCCESS) {
2006 OSKextLog(this,
2007 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2008 "Failed to allocate space for prelinked kext %s.",
2009 getIdentifierCString());
2010 goto finish;
2011 }
2012 memcpy(data, srcData, length);
2013 #else
2014 OSKextLog(this,
2015 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2016 "Error: prelinked kext %s - source and load addresses "
2017 "differ on ILP32 architecture.",
2018 getIdentifierCString());
2019 goto finish;
2020 #endif /* __LP64__ */
2021 }
2022
2023 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
2024 }
2025
2026 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
2027 if (!prelinkedExecutable) {
2028 OSKextLog(this,
2029 kOSKextLogErrorLevel |
2030 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
2031 "Kext %s failed to create executable wrapper.",
2032 getIdentifierCString());
2033 goto finish;
2034 }
2035
2036 /*
2037 * Fileset KCs are mapped as a whole by iBoot.
2038 * Individual kext executables should not be unmapped
2039 * by xnu.
2040 * Doing so may result in panics like rdar://85419651
2041 */
2042 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
2043 prelinkedExecutable->setDeallocFunction(NULL);
2044 } else { // Not from a Fileset KC
2045 #if VM_MAPPED_KEXTS
2046 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
2047 #else
2048 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
2049 #endif
2050 }
2051 setLinkedExecutable(prelinkedExecutable.get());
2052 addressNum = OSDynamicCast(OSNumber,
2053 anInfoDict->getObject(kPrelinkKmodInfoKey));
2054 if (!addressNum) {
2055 OSKextLog(this,
2056 kOSKextLogErrorLevel |
2057 kOSKextLogArchiveFlag,
2058 "Kext %s can't find prelinked kext kmod_info address.",
2059 getIdentifierCString());
2060 goto finish;
2061 }
2062
2063 if (addressNum->unsigned64BitValue() != 0) {
2064 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2065 if (kmod_info->address) {
2066 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
2067 } else {
2068 kmod_info->address = (uintptr_t)data;
2069 kmod_info->size = length;
2070 }
2071 #if KASLR_KEXT_DEBUG
2072 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
2073 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
2074 (unsigned long)kmod_info);
2075 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
2076 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
2077 (unsigned long)kmod_info->address);
2078 #endif
2079 }
2080
2081 anInfoDict->removeObject(kPrelinkKmodInfoKey);
2082 }
2083
2084 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
2085 uintptr_t builtinTextStart;
2086 uintptr_t builtinTextEnd;
2087
2088 flags.builtin = true;
2089 builtinKmodIdx = addressNum->unsigned32BitValue();
2090 assert(builtinKmodIdx < gBuiltinKmodsCount);
2091
2092 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
2093 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
2094
2095 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
2096 kmod_info->address = builtinTextStart;
2097 kmod_info->size = builtinTextEnd - builtinTextStart;
2098 }
2099
2100 /* If the plist has a UUID for an interface, save that off.
2101 */
2102 if (isInterface()) {
2103 interfaceUUID.reset(OSDynamicCast(OSData,
2104 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
2105 if (interfaceUUID) {
2106 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
2107 }
2108 }
2109
2110 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
2111 if (!result) {
2112 goto finish;
2113 }
2114
2115 kc_type = type;
2116 /* Exclude builtin and codeless kexts */
2117 if (prelinkedExecutable && kmod_info) {
2118 switch (kc_type) {
2119 case KCKindPrimary:
2120 shouldSaveSegments = (
2121 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
2122 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
2123 if (shouldSaveSegments) {
2124 flags.resetSegmentsFromImmutableCopy = 1;
2125 } else {
2126 flags.unloadUnsupported = 1;
2127 }
2128 break;
2129 case KCKindPageable:
2130 flags.resetSegmentsFromVnode = 1;
2131 break;
2132 case KCKindAuxiliary:
2133 if (!pageableKCloaded) {
2134 flags.resetSegmentsFromImmutableCopy = 1;
2135 } else if (resetAuxKCSegmentOnUnload) {
2136 flags.resetSegmentsFromVnode = 1;
2137 } else {
2138 flags.unloadUnsupported = 1;
2139 }
2140 break;
2141 default:
2142 break;
2143 }
2144 }
2145
2146 if (flags.resetSegmentsFromImmutableCopy) {
2147 /* Save a pristine copy of the mutable segments */
2148 kernel_segment_command_t *seg = NULL;
2149 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
2150
2151 savedMutableSegments = OSArray::withCapacity(0);
2152
2153 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
2154 if (!segmentIsMutable(seg)) {
2155 continue;
2156 }
2157 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
2158 uint64_t vmsize = seg->vmsize;
2159 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2160 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2161 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
2162 if (!savedSegment) {
2163 OSKextLog(this,
2164 kOSKextLogErrorLevel |
2165 kOSKextLogGeneralFlag,
2166 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2167 result = false;
2168 goto finish;
2169 }
2170 savedMutableSegments->setObject(savedSegment);
2171 }
2172 }
2173
2174 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2175 /*
2176 * set VM protections now, wire pages for the old style Aux KC now,
2177 * wire pages for the rest of the KC types at load time.
2178 */
2179 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2180 if (!result) {
2181 goto finish;
2182 }
2183 }
2184
2185 flags.prelinked = true;
2186
2187 if (isDriverKit()) {
2188 dextStatistics = OSDextStatistics::create();
2189 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2190 dextLaunchedCount = 0;
2191 }
2192
2193 /* If we created a kext from prelink info,
2194 * we must be booting from a prelinked kernel.
2195 */
2196 sPrelinkBoot = true;
2197
2198 result = (registerIdentifier() == kOSKextInitialized);
2199 finish:
2200 return result;
2201 }
2202
2203 /*********************************************************************
2204 *********************************************************************/
2205 /* static */
2206 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict,OSKextInitResult * result)2207 OSKext::withCodelessInfo(OSDictionary * anInfoDict, OSKextInitResult *result)
2208 {
2209 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2210 if (!newKext) {
2211 return NULL;
2212 }
2213
2214 OSKextInitResult ret = newKext->initWithCodelessInfo(anInfoDict);
2215 if (result != NULL) {
2216 *result = ret;
2217 }
2218 if (ret != kOSKextInitialized) {
2219 return NULL;
2220 }
2221
2222 return newKext;
2223 }
2224
2225 /*********************************************************************
2226 *********************************************************************/
2227 OSKextInitResult
initWithCodelessInfo(OSDictionary * anInfoDict)2228 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2229 {
2230 OSKextInitResult result = kOSKextInitFailure;
2231 OSString * kextPath = NULL; // do not release
2232 OSBoolean * scratchBool = NULL; // do not release
2233
2234 if (anInfoDict == NULL || !super::init()) {
2235 goto finish;
2236 }
2237
2238 /*
2239 * Get the path. Don't look for an arch-specific path property.
2240 */
2241 kextPath = OSDynamicCast(OSString,
2242 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2243 if (!kextPath) {
2244 OSKextLog(NULL,
2245 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2246 "Requested codeless kext dictionary does not contain the '%s' key",
2247 kKextRequestArgumentCodelessInfoBundlePathKey);
2248 goto finish;
2249 }
2250
2251 uniquePersonalityProperties(anInfoDict);
2252
2253 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2254 goto finish;
2255 }
2256
2257 /*
2258 * This path is meant to initialize codeless kexts only. Refuse
2259 * anything that looks like it has an executable and/or declares
2260 * itself as a kernel component.
2261 */
2262 if (declaresExecutable() || isKernelComponent()) {
2263 OSKextLog(NULL,
2264 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2265 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2266 getIdentifierCString());
2267 goto finish;
2268 }
2269
2270 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2271 boolean_t updated = updateExcludeList(infoDict.get());
2272 if (updated) {
2273 OSKextLog(this,
2274 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2275 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2276 }
2277 }
2278
2279 kc_type = KCKindNone;
2280
2281 scratchBool = OSDynamicCast(OSBoolean,
2282 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2283 if (scratchBool == kOSBooleanTrue) {
2284 flags.requireExplicitLoad = 1;
2285 }
2286
2287 /* Also get the executable's bundle-relative path if present.
2288 * Don't look for an arch-specific path property.
2289 */
2290 userExecutableRelPath.reset(OSDynamicCast(OSString,
2291 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2292
2293 /* remove unnecessary paths from the info dict */
2294 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2295
2296 if (isDriverKit()) {
2297 dextStatistics = OSDextStatistics::create();
2298 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2299 dextLaunchedCount = 0;
2300 }
2301
2302 result = registerIdentifier();
2303
2304 finish:
2305 return result;
2306 }
2307
2308 /*********************************************************************
2309 *********************************************************************/
2310 /* static */
2311 void
setAllVMAttributes(void)2312 OSKext::setAllVMAttributes(void)
2313 {
2314 OSSharedPtr<OSCollectionIterator> kextIterator;
2315 const OSSymbol * thisID = NULL; // do not release
2316
2317 IORecursiveLockLock(sKextLock);
2318
2319 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2320 if (!kextIterator) {
2321 goto finish;
2322 }
2323
2324 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2325 OSKext * thisKext; // do not release
2326
2327 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2328 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2329 continue;
2330 }
2331
2332 if (!thisKext->flags.resetSegmentsFromVnode) {
2333 /*
2334 * set VM protections now, wire pages for the old style Aux KC now,
2335 * wire pages for the rest of the KC types at load time.
2336 */
2337 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2338 }
2339 }
2340
2341 finish:
2342 IORecursiveLockUnlock(sKextLock);
2343
2344 return;
2345 }
2346
2347 /*********************************************************************
2348 *********************************************************************/
2349 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2350 OSKext::withBooterData(
2351 OSString * deviceTreeName,
2352 OSData * booterData)
2353 {
2354 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2355
2356 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2357 return NULL;
2358 }
2359
2360 return newKext;
2361 }
2362
2363 /*********************************************************************
2364 *********************************************************************/
2365 typedef struct _BooterKextFileInfo {
2366 uint32_t infoDictPhysAddr;
2367 uint32_t infoDictLength;
2368 uint32_t executablePhysAddr;
2369 uint32_t executableLength;
2370 uint32_t bundlePathPhysAddr;
2371 uint32_t bundlePathLength;
2372 } _BooterKextFileInfo;
2373
2374 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2375 OSKext::initWithBooterData(
2376 OSString * deviceTreeName,
2377 OSData * booterData)
2378 {
2379 bool result = false;
2380 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2381 char * infoDictAddr = NULL; // do not free
2382 void * executableAddr = NULL; // do not free
2383 char * bundlePathAddr = NULL; // do not free
2384
2385 OSDictionary * theInfoDict = NULL; // do not release
2386 OSSharedPtr<OSObject> parsedXML;
2387 OSSharedPtr<OSString> kextPath;
2388
2389 OSSharedPtr<OSString> errorString;
2390 OSSharedPtr<OSData> executable;
2391
2392 if (!super::init()) {
2393 goto finish;
2394 }
2395
2396 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2397 if (!kextFileInfo) {
2398 OSKextLog(this,
2399 kOSKextLogErrorLevel |
2400 kOSKextLogGeneralFlag,
2401 "No booter-provided data for kext device tree entry %s.",
2402 deviceTreeName->getCStringNoCopy());
2403 goto finish;
2404 }
2405
2406 /* The info plist must exist or we can't read the kext.
2407 */
2408 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2409 OSKextLog(this,
2410 kOSKextLogErrorLevel |
2411 kOSKextLogGeneralFlag,
2412 "No kext info dictionary for booter device tree entry %s.",
2413 deviceTreeName->getCStringNoCopy());
2414 goto finish;
2415 }
2416
2417 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2418 if (!infoDictAddr) {
2419 OSKextLog(this,
2420 kOSKextLogErrorLevel |
2421 kOSKextLogGeneralFlag,
2422 "Can't translate physical address 0x%x of kext info dictionary "
2423 "for device tree entry %s.",
2424 (int)kextFileInfo->infoDictPhysAddr,
2425 deviceTreeName->getCStringNoCopy());
2426 goto finish;
2427 }
2428
2429 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2430 if (parsedXML) {
2431 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2432 }
2433 if (!theInfoDict) {
2434 const char * errorCString = "(unknown error)";
2435
2436 if (errorString && errorString->getCStringNoCopy()) {
2437 errorCString = errorString->getCStringNoCopy();
2438 } else if (parsedXML) {
2439 errorCString = "not a dictionary";
2440 }
2441 OSKextLog(this,
2442 kOSKextLogErrorLevel |
2443 kOSKextLogGeneralFlag,
2444 "Error unserializing info dictionary for device tree entry %s: %s.",
2445 deviceTreeName->getCStringNoCopy(), errorCString);
2446 goto finish;
2447 }
2448
2449 /* A bundle path is not mandatory.
2450 */
2451 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2452 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2453 if (!bundlePathAddr) {
2454 OSKextLog(this,
2455 kOSKextLogErrorLevel |
2456 kOSKextLogGeneralFlag,
2457 "Can't translate physical address 0x%x of kext bundle path "
2458 "for device tree entry %s.",
2459 (int)kextFileInfo->bundlePathPhysAddr,
2460 deviceTreeName->getCStringNoCopy());
2461 goto finish;
2462 }
2463 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2464
2465 kextPath = OSString::withCString(bundlePathAddr);
2466 if (!kextPath) {
2467 OSKextLog(this,
2468 kOSKextLogErrorLevel |
2469 kOSKextLogGeneralFlag,
2470 "Failed to create wrapper for device tree entry %s kext path %s.",
2471 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2472 goto finish;
2473 }
2474 }
2475
2476 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2477 goto finish;
2478 }
2479
2480 /* An executable is not mandatory.
2481 */
2482 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2483 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2484 if (!executableAddr) {
2485 OSKextLog(this,
2486 kOSKextLogErrorLevel |
2487 kOSKextLogGeneralFlag,
2488 "Can't translate physical address 0x%x of kext executable "
2489 "for device tree entry %s.",
2490 (int)kextFileInfo->executablePhysAddr,
2491 deviceTreeName->getCStringNoCopy());
2492 goto finish;
2493 }
2494
2495 executable = OSData::withBytesNoCopy(executableAddr,
2496 kextFileInfo->executableLength);
2497 if (!executable) {
2498 OSKextLog(this,
2499 kOSKextLogErrorLevel |
2500 kOSKextLogGeneralFlag,
2501 "Failed to create executable wrapper for device tree entry %s.",
2502 deviceTreeName->getCStringNoCopy());
2503 goto finish;
2504 }
2505
2506 /* A kext with an executable needs to retain the whole booterData
2507 * object to keep the executable in memory.
2508 */
2509 if (!setExecutable(executable.get(), booterData)) {
2510 OSKextLog(this,
2511 kOSKextLogErrorLevel |
2512 kOSKextLogGeneralFlag,
2513 "Failed to set kext executable for device tree entry %s.",
2514 deviceTreeName->getCStringNoCopy());
2515 goto finish;
2516 }
2517 }
2518
2519 if (isDriverKit()) {
2520 dextStatistics = OSDextStatistics::create();
2521 dextUniqueID.reset(parseDextUniqueID(theInfoDict, getIdentifierCString()), OSRetain);
2522 dextLaunchedCount = 0;
2523 }
2524
2525 result = (registerIdentifier() == kOSKextInitialized);
2526
2527 finish:
2528 return result;
2529 }
2530
2531 /*********************************************************************
2532 *********************************************************************/
2533 OSKextInitResult
registerIdentifier(void)2534 OSKext::registerIdentifier(void)
2535 {
2536 OSKextInitResult result = kOSKextInitFailure;
2537 OSKext * existingKext = NULL; // do not release
2538 bool existingIsLoaded = false;
2539 bool existingIsPrelinked = false;
2540 bool existingIsCodeless = false;
2541 bool existingIsDext = false;
2542 OSKextVersion newVersion = -1;
2543 OSKextVersion existingVersion = -1;
2544 char newVersionCString[kOSKextVersionMaxLength];
2545 char existingVersionCString[kOSKextVersionMaxLength];
2546 OSSharedPtr<OSData> newUUID;
2547 OSSharedPtr<OSData> existingUUID;
2548 const char *newDextUniqueIDCString = NULL;
2549 const char *existingDextUniqueIDCString = NULL;
2550 unsigned int newDextUniqueIDCStringSize = 0;
2551 unsigned int existingDextUniqueIDCStringSize = 0;
2552
2553 IORecursiveLockLock(sKextLock);
2554
2555 /* Get the new kext's version for checks & log messages.
2556 */
2557 newVersion = getVersion();
2558 OSKextVersionGetString(newVersion, newVersionCString,
2559 kOSKextVersionMaxLength);
2560
2561 /* If we don't have an existing kext with this identifier,
2562 * just record the new kext and we're done!
2563 */
2564 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2565 if (!existingKext) {
2566 sKextsByID->setObject(bundleID.get(), this);
2567 result = kOSKextInitialized;
2568 goto finish;
2569 }
2570
2571 /* Get the existing kext's version for checks & log messages.
2572 */
2573 existingVersion = existingKext->getVersion();
2574 OSKextVersionGetString(existingVersion,
2575 existingVersionCString, kOSKextVersionMaxLength);
2576
2577 existingIsLoaded = existingKext->isLoaded();
2578 existingIsPrelinked = existingKext->isPrelinked();
2579 existingIsDext = existingKext->isDriverKit();
2580 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2581
2582 /*
2583 * Check if we are trying to upgrade a dext
2584 * with another dext.
2585 */
2586 if (isDriverKit() && existingIsDext) {
2587 OSData *newDextUID = getDextUniqueID();
2588 if (!newDextUID) {
2589 OSKextLog(this,
2590 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2591 "New dext %s, v%s requested does not have a unique dext identifier\n",
2592 getIdentifierCString(), newVersionCString);
2593 goto finish;
2594 }
2595 newDextUniqueIDCString = getDextUniqueIDCString(newDextUID, &newDextUniqueIDCStringSize);
2596 assert(newDextUniqueIDCString != NULL);
2597
2598 OSData *existingDextUID = existingKext->getDextUniqueID();
2599 if (!existingDextUID) {
2600 OSKextLog(this,
2601 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2602 "Found a dext %s, v%s: with no unique dext identifier\n",
2603 existingKext->getIdentifierCString(), existingVersionCString);
2604 goto finish;
2605 }
2606 existingDextUniqueIDCString = getDextUniqueIDCString(existingDextUID, &existingDextUniqueIDCStringSize);
2607 assert(existingDextUniqueIDCString != NULL);
2608
2609 /*
2610 * We might get multiple requests to save the same dext.
2611 * Check if we already have saved it or if this is an upgrade
2612 * for a dext with the same BundleID.
2613 * Dexts are uniquely identified by DextUniqueID, if a new DextUniqueID
2614 * is requested for a BundleID we are going to upgrade to the newest
2615 * received irrespective from the dext version.
2616 */
2617 if (newDextUID->isEqualTo(existingDextUID) && existingKext->flags.dextToReplace == 0) {
2618 OSKextLog(this,
2619 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2620 "Refusing new dext %s, v%s:"
2621 "a dext v %s with the same unique dext identifier (%s) already exists\n",
2622 getIdentifierCString(), newVersionCString,
2623 existingVersionCString, newDextUniqueIDCString);
2624 result = kOSKextAlreadyExist;
2625 goto finish;
2626 }
2627
2628 bool upgraded = upgradeDext(existingKext, this);
2629 if (upgraded) {
2630 /* If the dext was upgraded existingKext might have been deallocated */
2631 existingKext = NULL;
2632 OSKextLog(this,
2633 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2634 "Dext %s, v%s , unique dext identifier %s "
2635 "Upgraded to v%s, unique dext identifier %s \n",
2636 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2637 newVersionCString, newDextUniqueIDCString);
2638 result = kOSKextInitialized;
2639 } else {
2640 OSKextLog(this,
2641 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2642 "Upgrade delayed for %s v%s, unique dext identifier %s "
2643 "with v%s, unique dext identifier %s.\n",
2644 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2645 newVersionCString, newDextUniqueIDCString);
2646 result = kOSKextAlreadyExist;
2647 }
2648
2649 goto finish;
2650 }
2651
2652 /* If we have a non-codeless kext with this identifier that's already
2653 * loaded/prelinked, we can't use the new one, but let's be really
2654 * thorough and check how the two are related for a precise diagnostic
2655 * log message.
2656 *
2657 * This check is valid for kexts that declare an executable and for
2658 * dexts, but not for codeless kexts - we can just replace those.
2659 */
2660 if ((!existingIsCodeless || existingIsDext) &&
2661 (existingIsLoaded || existingIsPrelinked)) {
2662 bool sameVersion = (newVersion == existingVersion);
2663 bool sameExecutable = true; // assume true unless we have UUIDs
2664
2665 /* Only get the UUID if the existing kext is loaded. Doing so
2666 * might have to uncompress an mkext executable and we shouldn't
2667 * take that hit when neither kext is loaded.
2668 *
2669 * Note: there is no decompression that happens when all kexts
2670 * are loaded from kext collecitons.
2671 */
2672 newUUID = copyUUID();
2673 existingUUID = existingKext->copyUUID();
2674
2675 if (existingIsDext && !isDriverKit()) {
2676 OSKextLog(this,
2677 kOSKextLogWarningLevel |
2678 kOSKextLogKextBookkeepingFlag,
2679 "Notice - new kext %s, v%s matches a %s dext"
2680 "with the same bundle ID, v%s.",
2681 getIdentifierCString(), newVersionCString,
2682 (existingIsLoaded ? "loaded" : "prelinked"),
2683 existingVersionCString);
2684 goto finish;
2685 }
2686
2687 /* I'm entirely too paranoid about checking equivalence of executables,
2688 * but I remember nasty problems with it in the past.
2689 *
2690 * - If we have UUIDs for both kexts, compare them.
2691 * - If only one kext has a UUID, they're definitely different.
2692 */
2693 if (newUUID && existingUUID) {
2694 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2695 } else if (newUUID || existingUUID) {
2696 sameExecutable = false;
2697 }
2698
2699 if (!newUUID && !existingUUID) {
2700 /* If there are no UUIDs, we can't really tell that the executables
2701 * are *different* without a lot of work; the loaded kext's
2702 * unrelocated executable is no longer around (and we never had it
2703 * in-kernel for a prelinked kext). We certainly don't want to do
2704 * a whole fake link for the new kext just to compare, either.
2705 */
2706 OSKextLog(this,
2707 kOSKextLogWarningLevel |
2708 kOSKextLogKextBookkeepingFlag,
2709 "Notice - new kext %s, v%s matches %s kext "
2710 "but can't determine if executables are the same (no UUIDs).",
2711 getIdentifierCString(),
2712 newVersionCString,
2713 (existingIsLoaded ? "loaded" : "prelinked"));
2714 }
2715
2716 if (sameVersion && sameExecutable) {
2717 OSKextLog(this,
2718 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2719 kOSKextLogKextBookkeepingFlag,
2720 "Refusing new kext %s, v%s: a %s copy is already present "
2721 "(same version and executable).",
2722 getIdentifierCString(), newVersionCString,
2723 (existingIsLoaded ? "loaded" : "prelinked"));
2724 } else {
2725 if (!sameVersion) {
2726 /* This condition is significant so log it under warnings.
2727 */
2728 OSKextLog(this,
2729 kOSKextLogWarningLevel |
2730 kOSKextLogKextBookkeepingFlag,
2731 "Refusing new kext %s, v%s: already have %s v%s.",
2732 getIdentifierCString(),
2733 newVersionCString,
2734 (existingIsLoaded ? "loaded" : "prelinked"),
2735 existingVersionCString);
2736 } else {
2737 /* This condition is significant so log it under warnings.
2738 */
2739 OSKextLog(this,
2740 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2741 "Refusing new kext %s, v%s: a %s copy with a different "
2742 "executable UUID is already present.",
2743 getIdentifierCString(), newVersionCString,
2744 (existingIsLoaded ? "loaded" : "prelinked"));
2745 }
2746 }
2747 goto finish;
2748 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2749
2750 /* Refuse to allow an existing loaded codeless kext be replaced by a
2751 * normal kext with the same bundle ID.
2752 */
2753 if (existingIsCodeless && declaresExecutable()) {
2754 OSKextLog(this,
2755 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2756 "Refusing new kext %s, v%s: a codeless copy is already %s",
2757 getIdentifierCString(), newVersionCString,
2758 (existingIsLoaded ? "loaded" : "prelinked"));
2759 goto finish;
2760 }
2761
2762 /* Dexts packaged in the BootKC will be protected against replacement
2763 * by non-dexts by the logic above which checks if they are prelinked.
2764 * Dexts which are prelinked into the System KC will be registered
2765 * before any other kexts in the AuxKC are registered, and we never
2766 * put dexts in the AuxKC. Therefore, there is no need to check if an
2767 * existing object is a dext and is being replaced by a non-dext.
2768 * The scenario cannot happen by construction.
2769 *
2770 * See: OSKext::loadFileSetKexts()
2771 */
2772
2773
2774 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2775 * user loads are happening or if we're still in early boot. User agents are
2776 * supposed to resolve dependencies topside and include only the exact
2777 * kexts needed; so we always accept the new kext (in fact we should never
2778 * see an older unloaded copy hanging around).
2779 */
2780 if (sUserLoadsActive) {
2781 sKextsByID->setObject(bundleID.get(), this);
2782 result = kOSKextInitialized;
2783
2784 OSKextLog(this,
2785 kOSKextLogStepLevel |
2786 kOSKextLogKextBookkeepingFlag,
2787 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2788 getIdentifierCString(),
2789 existingVersionCString,
2790 newVersionCString);
2791
2792 goto finish;
2793 }
2794
2795 /* During early boot, the kext with the highest version always wins out.
2796 * Prelinked kernels will never hit this, but mkexts and booter-read
2797 * kexts might have duplicates.
2798 */
2799 if (newVersion > existingVersion) {
2800 sKextsByID->setObject(bundleID.get(), this);
2801 result = kOSKextInitialized;
2802
2803 OSKextLog(this,
2804 kOSKextLogStepLevel |
2805 kOSKextLogKextBookkeepingFlag,
2806 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2807 existingVersionCString,
2808 getIdentifierCString(),
2809 newVersionCString);
2810 } else {
2811 OSKextLog(this,
2812 kOSKextLogStepLevel |
2813 kOSKextLogKextBookkeepingFlag,
2814 "Kext %s is already registered with a higher/same version (v%s); "
2815 "dropping newly-added (v%s).",
2816 getIdentifierCString(),
2817 existingVersionCString,
2818 newVersionCString);
2819 }
2820
2821 /* result has been set appropriately by now. */
2822
2823 finish:
2824
2825 IORecursiveLockUnlock(sKextLock);
2826
2827 if (newDextUniqueIDCString != NULL) {
2828 kfree_data(newDextUniqueIDCString, newDextUniqueIDCStringSize);
2829 }
2830 if (existingDextUniqueIDCString != NULL) {
2831 kfree_data(existingDextUniqueIDCString, existingDextUniqueIDCStringSize);
2832 }
2833
2834 if (result == kOSKextInitialized) {
2835 OSKextLog(this,
2836 kOSKextLogStepLevel |
2837 kOSKextLogKextBookkeepingFlag,
2838 "Kext %s, v%s registered and available for loading.",
2839 getIdentifierCString(), newVersionCString);
2840 }
2841
2842 return result;
2843 }
2844
2845 /*********************************************************************
2846 * Does the bare minimum validation to look up a kext.
2847 * All other validation is done on the spot as needed.
2848 **********************************************************************/
2849 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)2850 OSKext::setInfoDictionaryAndPath(
2851 OSDictionary * aDictionary,
2852 OSString * aPath)
2853 {
2854 bool result = false;
2855 OSString * bundleIDString = NULL; // do not release
2856 OSString * versionString = NULL; // do not release
2857 OSString * compatibleVersionString = NULL; // do not release
2858 const char * versionCString = NULL; // do not free
2859 const char * compatibleVersionCString = NULL; // do not free
2860 OSBoolean * scratchBool = NULL; // do not release
2861 OSDictionary * scratchDict = NULL; // do not release
2862
2863 if (infoDict) {
2864 panic("Attempt to set info dictionary on a kext "
2865 "that already has one (%s).",
2866 getIdentifierCString());
2867 }
2868
2869 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2870 goto finish;
2871 }
2872
2873 infoDict.reset(aDictionary, OSRetain);
2874
2875 /* Check right away if the info dictionary has any log flags.
2876 */
2877 scratchBool = OSDynamicCast(OSBoolean,
2878 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2879 if (scratchBool == kOSBooleanTrue) {
2880 flags.loggingEnabled = 1;
2881 }
2882
2883 /* The very next thing to get is the bundle identifier. Unlike
2884 * in user space, a kext with no bundle identifier gets axed
2885 * immediately.
2886 */
2887 bundleIDString = OSDynamicCast(OSString,
2888 getPropertyForHostArch(kCFBundleIdentifierKey));
2889 if (!bundleIDString) {
2890 OSKextLog(this,
2891 kOSKextLogErrorLevel |
2892 kOSKextLogValidationFlag,
2893 "CFBundleIdentifier missing/invalid type in kext %s.",
2894 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2895 goto finish;
2896 }
2897 bundleID = OSSymbol::withString(bundleIDString);
2898 if (!bundleID) {
2899 OSKextLog(this,
2900 kOSKextLogErrorLevel |
2901 kOSKextLogValidationFlag,
2902 "Can't copy bundle identifier as symbol for kext %s.",
2903 bundleIDString->getCStringNoCopy());
2904 goto finish;
2905 }
2906
2907 /* Save the path if we got one (it should always be available but it's
2908 * just something nice to have for bookkeeping).
2909 */
2910 if (aPath) {
2911 path.reset(aPath, OSRetain);
2912 }
2913
2914 /*****
2915 * Minimal validation to initialize. We'll do other validation on the spot.
2916 */
2917 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2918 OSKextLog(this,
2919 kOSKextLogErrorLevel |
2920 kOSKextLogValidationFlag,
2921 "Kext %s error - CFBundleIdentifier over max length %d.",
2922 getIdentifierCString(), KMOD_MAX_NAME - 1);
2923 goto finish;
2924 }
2925
2926 version = compatibleVersion = -1;
2927
2928 versionString = OSDynamicCast(OSString,
2929 getPropertyForHostArch(kCFBundleVersionKey));
2930 if (!versionString) {
2931 OSKextLog(this,
2932 kOSKextLogErrorLevel |
2933 kOSKextLogValidationFlag,
2934 "Kext %s error - CFBundleVersion missing/invalid type.",
2935 getIdentifierCString());
2936 goto finish;
2937 }
2938 versionCString = versionString->getCStringNoCopy();
2939 version = OSKextParseVersionString(versionCString);
2940 if (version < 0) {
2941 OSKextLog(this,
2942 kOSKextLogErrorLevel |
2943 kOSKextLogValidationFlag,
2944 "Kext %s error - CFBundleVersion bad value '%s'.",
2945 getIdentifierCString(), versionCString);
2946 goto finish;
2947 }
2948
2949 compatibleVersion = -1; // set to illegal value for kexts that don't have
2950
2951 compatibleVersionString = OSDynamicCast(OSString,
2952 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2953 if (compatibleVersionString) {
2954 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2955 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2956 if (compatibleVersion < 0) {
2957 OSKextLog(this,
2958 kOSKextLogErrorLevel |
2959 kOSKextLogValidationFlag,
2960 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2961 getIdentifierCString(), compatibleVersionCString);
2962 goto finish;
2963 }
2964
2965 if (compatibleVersion > version) {
2966 OSKextLog(this,
2967 kOSKextLogErrorLevel |
2968 kOSKextLogValidationFlag,
2969 "Kext %s error - %s %s > %s %s (must be <=).",
2970 getIdentifierCString(),
2971 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2972 kCFBundleVersionKey, versionCString);
2973 goto finish;
2974 }
2975 }
2976
2977 /* Check to see if this kext is in exclude list */
2978 if (isInExcludeList()) {
2979 OSKextLog(this,
2980 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2981 "Kext %s is in exclude list, not loadable",
2982 getIdentifierCString());
2983 goto finish;
2984 }
2985
2986 /* Set flags for later use if the infoDict gets flushed. We only
2987 * check for true values, not false ones(!)
2988 */
2989 scratchBool = OSDynamicCast(OSBoolean,
2990 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2991 if (scratchBool == kOSBooleanTrue) {
2992 flags.interface = 1;
2993 }
2994
2995 scratchBool = OSDynamicCast(OSBoolean,
2996 getPropertyForHostArch(kOSKernelResourceKey));
2997 if (scratchBool == kOSBooleanTrue) {
2998 flags.kernelComponent = 1;
2999 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
3000 flags.started = 1;
3001
3002 /* A kernel component has one implicit dependency on the kernel.
3003 */
3004 flags.hasAllDependencies = 1;
3005 }
3006
3007 /* Make sure common string values in personalities are uniqued to OSSymbols.
3008 */
3009 scratchDict = OSDynamicCast(OSDictionary,
3010 getPropertyForHostArch(kIOKitPersonalitiesKey));
3011 if (scratchDict) {
3012 uniquePersonalityProperties(scratchDict);
3013 }
3014
3015 result = true;
3016
3017 finish:
3018
3019 return result;
3020 }
3021
3022 /*********************************************************************
3023 * Not used for prelinked kernel boot as there is no unrelocated
3024 * executable.
3025 *********************************************************************/
3026 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)3027 OSKext::setExecutable(
3028 OSData * anExecutable,
3029 OSData * externalData,
3030 bool externalDataIsMkext)
3031 {
3032 bool result = false;
3033 const char * executableKey = NULL; // do not free
3034
3035 if (!anExecutable) {
3036 infoDict->removeObject(_kOSKextExecutableKey);
3037 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3038 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3039 result = true;
3040 goto finish;
3041 }
3042
3043 if (infoDict->getObject(_kOSKextExecutableKey) ||
3044 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
3045 panic("Attempt to set an executable on a kext "
3046 "that already has one (%s).",
3047 getIdentifierCString());
3048 goto finish;
3049 }
3050
3051 if (externalDataIsMkext) {
3052 executableKey = _kOSKextMkextExecutableReferenceKey;
3053 } else {
3054 executableKey = _kOSKextExecutableKey;
3055 }
3056
3057 if (anExecutable) {
3058 infoDict->setObject(executableKey, anExecutable);
3059 if (externalData) {
3060 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
3061 }
3062 }
3063
3064 result = true;
3065
3066 finish:
3067 return result;
3068 }
3069
3070 /*********************************************************************
3071 *********************************************************************/
3072 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)3073 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
3074 {
3075 OSObject * value = NULL; // do not release
3076 OSString * stringValue = NULL; // do not release
3077 OSSharedPtr<const OSSymbol> symbolValue;
3078
3079 value = dict->getObject(key);
3080 if (!value) {
3081 goto finish;
3082 }
3083 if (OSDynamicCast(OSSymbol, value)) {
3084 /* this is already an OSSymbol: we're good */
3085 goto finish;
3086 }
3087
3088 stringValue = OSDynamicCast(OSString, value);
3089 if (!stringValue) {
3090 goto finish;
3091 }
3092
3093 symbolValue = OSSymbol::withString(stringValue);
3094 if (!symbolValue) {
3095 goto finish;
3096 }
3097
3098 dict->setObject(key, symbolValue.get());
3099
3100 finish:
3101 return;
3102 }
3103
3104 /*********************************************************************
3105 *********************************************************************/
3106 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)3107 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
3108 {
3109 OSObject * value = NULL; // do not release
3110 OSString * stringValue = NULL; // do not release
3111 OSSharedPtr<const OSSymbol> symbolValue;
3112
3113 value = dict->getObject(key);
3114 if (!value) {
3115 goto finish;
3116 }
3117 if (OSDynamicCast(OSSymbol, value)) {
3118 /* this is already an OSSymbol: we're good */
3119 goto finish;
3120 }
3121
3122 stringValue = OSDynamicCast(OSString, value);
3123 if (!stringValue) {
3124 goto finish;
3125 }
3126
3127 symbolValue = OSSymbol::withString(stringValue);
3128 if (!symbolValue) {
3129 goto finish;
3130 }
3131
3132 dict->setObject(key, symbolValue.get());
3133
3134 finish:
3135 return;
3136 }
3137
3138 void
uniquePersonalityProperties(OSDictionary * personalityDict)3139 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
3140 {
3141 OSKext::uniquePersonalityProperties(personalityDict, true);
3142 }
3143
3144 /*********************************************************************
3145 * Replace common personality property values with uniqued instances
3146 * to save on wired memory.
3147 *********************************************************************/
3148 /* static */
3149 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)3150 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
3151 {
3152 /* Properties every personality has.
3153 */
3154 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
3155 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
3156 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
3157 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
3158 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
3159 } else if (defaultAddKernelBundleIdentifier) {
3160 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
3161 }
3162
3163 /* Other commonly used properties.
3164 */
3165 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
3166 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
3167 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
3168
3169 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
3170 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
3171 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
3172 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
3173 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
3174 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
3175 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
3176 uniqueStringPlistProperty(personalityDict, "Vendor");
3177 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
3178 uniqueStringPlistProperty(personalityDict, "Vendor Name");
3179 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
3180 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
3181 uniqueStringPlistProperty(personalityDict, "idProduct");
3182
3183 return;
3184 }
3185
3186 /*********************************************************************
3187 *********************************************************************/
3188 void
free(void)3189 OSKext::free(void)
3190 {
3191 if (isLoaded()) {
3192 panic("Attempt to free loaded kext %s.", getIdentifierCString());
3193 }
3194
3195 if (isDriverKit()) {
3196 if (dextLaunchedCount > 0) {
3197 panic("Freeing dext %s but dextLaunchedCount is %d\n", getIdentifierCString(), dextLaunchedCount);
3198 }
3199 }
3200
3201 infoDict.reset();
3202 bundleID.reset();
3203 path.reset();
3204 executableRelPath.reset();
3205 userExecutableRelPath.reset();
3206 dependencies.reset();
3207 linkedExecutable.reset();
3208 metaClasses.reset();
3209 interfaceUUID.reset();
3210 driverKitUUID.reset();
3211 dextStatistics.reset();
3212 dextUniqueID.reset();
3213
3214 if (isInterface() && kmod_info) {
3215 kfree_type(kmod_info_t, kmod_info);
3216 }
3217
3218 super::free();
3219 return;
3220 }
3221
3222 #if PRAGMA_MARK
3223 #pragma mark Mkext files
3224 #endif
3225
3226 #if CONFIG_KXLD
3227 /*
3228 * mkext archives are really only relevant on kxld-enabled kernels.
3229 * Without a dynamic kernel linker, we don't need to support any mkexts.
3230 */
3231
3232 /*********************************************************************
3233 *********************************************************************/
3234 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)3235 OSKext::readMkextArchive(OSData * mkextData,
3236 uint32_t * checksumPtr)
3237 {
3238 OSReturn result = kOSKextReturnBadData;
3239 uint32_t mkextLength = 0;
3240 mkext_header * mkextHeader = NULL; // do not free
3241 uint32_t mkextVersion = 0;
3242
3243 /* Note default return of kOSKextReturnBadData above.
3244 */
3245 mkextLength = mkextData->getLength();
3246 if (mkextLength < sizeof(mkext_basic_header)) {
3247 OSKextLog(/* kext */ NULL,
3248 kOSKextLogErrorLevel |
3249 kOSKextLogArchiveFlag,
3250 "Mkext archive too small to be valid.");
3251 goto finish;
3252 }
3253
3254 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
3255
3256 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
3257 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
3258 OSKextLog(/* kext */ NULL,
3259 kOSKextLogErrorLevel |
3260 kOSKextLogArchiveFlag,
3261 "Mkext archive has invalid magic or signature.");
3262 goto finish;
3263 }
3264
3265 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
3266 OSKextLog(/* kext */ NULL,
3267 kOSKextLogErrorLevel |
3268 kOSKextLogArchiveFlag,
3269 "Mkext archive recorded length doesn't match actual file length.");
3270 goto finish;
3271 }
3272
3273 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3274
3275 if (mkextVersion == MKEXT_VERS_2) {
3276 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
3277 } else {
3278 OSKextLog(/* kext */ NULL,
3279 kOSKextLogErrorLevel |
3280 kOSKextLogArchiveFlag,
3281 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3282 result = kOSKextReturnUnsupported;
3283 }
3284
3285 finish:
3286 return result;
3287 }
3288
3289 /*********************************************************************
3290 * Assumes magic, signature, version, length have been checked.
3291 * xxx - need to add further bounds checking for each file entry
3292 *
3293 * Should keep track of all kexts created so far, and if we hit a
3294 * fatal error halfway through, remove those kexts. If we've dropped
3295 * an older version that had already been read, whoops! Might want to
3296 * add a level of buffering?
3297 *********************************************************************/
3298 /* static */
3299 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3300 OSKext::readMkext2Archive(
3301 OSData * mkextData,
3302 OSDictionary ** mkextPlistOut,
3303 uint32_t * checksumPtr)
3304 {
3305 OSReturn result = kOSReturnError;
3306 uint32_t mkextLength;
3307 mkext2_header * mkextHeader = NULL; // do not free
3308 void * mkextEnd = NULL; // do not free
3309 uint32_t mkextVersion;
3310 uint8_t * crc_address = NULL;
3311 size_t crc_buffer_size = 0;
3312 uint32_t checksum;
3313 uint32_t mkextPlistOffset;
3314 uint32_t mkextPlistCompressedSize;
3315 char * mkextPlistEnd = NULL; // do not free
3316 uint32_t mkextPlistFullSize;
3317 OSSharedPtr<OSString> errorString;
3318 OSSharedPtr<OSData> mkextPlistUncompressedData;
3319 const char * mkextPlistDataBuffer = NULL; // do not free
3320 OSSharedPtr<OSObject> parsedXML;
3321 OSDictionary * mkextPlist = NULL; // do not release
3322 OSArray * mkextInfoDictArray = NULL; // do not release
3323 uint32_t count, i;
3324 kc_format_t kc_format;
3325
3326 if (!PE_get_primary_kc_format(&kc_format)) {
3327 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3328 "Unable to determine primary KC format");
3329 goto finish;
3330 }
3331
3332 mkextLength = mkextData->getLength();
3333 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3334 mkextEnd = (char *)mkextHeader + mkextLength;
3335 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3336
3337 crc_address = (u_int8_t *)&mkextHeader->version;
3338 crc_buffer_size = (uintptr_t)mkextHeader +
3339 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3340 if (crc_buffer_size > INT32_MAX) {
3341 OSKextLog(/* kext */ NULL,
3342 kOSKextLogErrorLevel |
3343 kOSKextLogArchiveFlag,
3344 "Mkext archive size is too large (%lu > INT32_MAX).",
3345 crc_buffer_size);
3346 result = kOSKextReturnBadData;
3347 goto finish;
3348 }
3349 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3350
3351 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3352 OSKextLog(/* kext */ NULL,
3353 kOSKextLogErrorLevel |
3354 kOSKextLogArchiveFlag,
3355 "Mkext archive has bad checksum.");
3356 result = kOSKextReturnBadData;
3357 goto finish;
3358 }
3359
3360 if (checksumPtr) {
3361 *checksumPtr = checksum;
3362 }
3363
3364 /* Check that the CPU type & subtype match that of the running kernel. */
3365 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3366 OSKextLog(/* kext */ NULL,
3367 kOSKextLogErrorLevel |
3368 kOSKextLogArchiveFlag,
3369 "Mkext archive must have a specific CPU type.");
3370 result = kOSKextReturnBadData;
3371 goto finish;
3372 } else {
3373 if ((UInt32)_mh_execute_header.cputype !=
3374 MKEXT_GET_CPUTYPE(mkextHeader)) {
3375 OSKextLog(/* kext */ NULL,
3376 kOSKextLogErrorLevel |
3377 kOSKextLogArchiveFlag,
3378 "Mkext archive does not match the running kernel's CPU type.");
3379 result = kOSKextReturnArchNotFound;
3380 goto finish;
3381 }
3382 }
3383
3384 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3385 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3386 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3387 mkextPlistCompressedSize;
3388 if (mkextPlistEnd > mkextEnd) {
3389 OSKextLog(/* kext */ NULL,
3390 kOSKextLogErrorLevel |
3391 kOSKextLogArchiveFlag,
3392 "Mkext archive file overrun.");
3393 result = kOSKextReturnBadData;
3394 }
3395
3396 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3397 if (mkextPlistCompressedSize) {
3398 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3399 (UInt8 *)mkextHeader + mkextPlistOffset,
3400 "plist",
3401 mkextPlistCompressedSize, mkextPlistFullSize);
3402 if (!mkextPlistUncompressedData) {
3403 goto finish;
3404 }
3405 mkextPlistDataBuffer = (const char *)
3406 mkextPlistUncompressedData->getBytesNoCopy();
3407 } else {
3408 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3409 }
3410
3411 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3412 */
3413 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3414 if (parsedXML) {
3415 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3416 }
3417 if (!mkextPlist) {
3418 const char * errorCString = "(unknown error)";
3419
3420 if (errorString && errorString->getCStringNoCopy()) {
3421 errorCString = errorString->getCStringNoCopy();
3422 } else if (parsedXML) {
3423 errorCString = "not a dictionary";
3424 }
3425 OSKextLog(/* kext */ NULL,
3426 kOSKextLogErrorLevel |
3427 kOSKextLogArchiveFlag,
3428 "Error unserializing mkext plist: %s.", errorCString);
3429 goto finish;
3430 }
3431
3432 mkextInfoDictArray = OSDynamicCast(OSArray,
3433 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3434 if (!mkextInfoDictArray) {
3435 OSKextLog(/* kext */ NULL,
3436 kOSKextLogErrorLevel |
3437 kOSKextLogArchiveFlag,
3438 "Mkext archive contains no kext info dictionaries.");
3439 goto finish;
3440 }
3441
3442 count = mkextInfoDictArray->getCount();
3443 for (i = 0; i < count; i++) {
3444 OSDictionary * infoDict;
3445
3446
3447 infoDict = OSDynamicCast(OSDictionary,
3448 mkextInfoDictArray->getObject(i));
3449
3450 /* Create the kext for the entry, then release it, because the
3451 * kext system keeps them around until explicitly removed.
3452 * Any creation/registration failures are already logged for us.
3453 */
3454 if (infoDict) {
3455 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3456
3457 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3458 if (kc_format == KCFormatFileset &&
3459 newKext &&
3460 !(newKext->isPrelinked()) &&
3461 newKext->declaresExecutable()) {
3462 result = kOSReturnError;
3463 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3464 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3465
3466 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3467 "Dynamic loading of kext denied for kext %s\n",
3468 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3469 goto finish;
3470 }
3471 }
3472 }
3473
3474 /* If the caller needs the plist, hand them back our copy
3475 */
3476 if (mkextPlistOut) {
3477 *mkextPlistOut = mkextPlist;
3478 parsedXML.detach();
3479 }
3480
3481 /* Even if we didn't keep any kexts from the mkext, we may have a load
3482 * request to process, so we are successful (no errors occurred).
3483 */
3484 result = kOSReturnSuccess;
3485
3486 finish:
3487 return result;
3488 }
3489
3490 /* static */
3491 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3492 OSKext::readMkext2Archive(
3493 OSData * mkextData,
3494 OSSharedPtr<OSDictionary> &mkextPlistOut,
3495 uint32_t * checksumPtr)
3496 {
3497 OSDictionary * mkextPlist = NULL;
3498 OSReturn ret;
3499
3500 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3501 &mkextPlist,
3502 checksumPtr))) {
3503 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3504 }
3505 return ret;
3506 }
3507
3508 /*********************************************************************
3509 *********************************************************************/
3510 /* static */
3511 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3512 OSKext::withMkext2Info(
3513 OSDictionary * anInfoDict,
3514 OSData * mkextData)
3515 {
3516 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3517
3518 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3519 return NULL;
3520 }
3521
3522 return newKext;
3523 }
3524
3525 /*********************************************************************
3526 *********************************************************************/
3527 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3528 OSKext::initWithMkext2Info(
3529 OSDictionary * anInfoDict,
3530 OSData * mkextData)
3531 {
3532 bool result = false;
3533 OSString * kextPath = NULL; // do not release
3534 OSNumber * executableOffsetNum = NULL; // do not release
3535 OSSharedPtr<OSData> executable;
3536
3537 if (anInfoDict == NULL || !super::init()) {
3538 goto finish;
3539 }
3540
3541 /* Get the path. Don't look for an arch-specific path property.
3542 */
3543 kextPath = OSDynamicCast(OSString,
3544 anInfoDict->getObject(kMKEXTBundlePathKey));
3545
3546 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3547 goto finish;
3548 }
3549
3550 /* If we have a path to the executable, save it.
3551 */
3552 executableRelPath.reset(OSDynamicCast(OSString,
3553 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3554
3555 /* Don't need the paths to be in the info dictionary any more.
3556 */
3557 anInfoDict->removeObject(kMKEXTBundlePathKey);
3558 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3559
3560 executableOffsetNum = OSDynamicCast(OSNumber,
3561 infoDict->getObject(kMKEXTExecutableKey));
3562 if (executableOffsetNum) {
3563 executable = createMkext2FileEntry(mkextData,
3564 executableOffsetNum, "executable");
3565 infoDict->removeObject(kMKEXTExecutableKey);
3566 if (!executable) {
3567 goto finish;
3568 }
3569 if (!setExecutable(executable.get(), mkextData, true)) {
3570 goto finish;
3571 }
3572 }
3573
3574 result = (registerIdentifier() == kOSKextInitialized);
3575 finish:
3576 return result;
3577 }
3578
3579 /*********************************************************************
3580 *********************************************************************/
3581 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3582 OSKext::createMkext2FileEntry(
3583 OSData * mkextData,
3584 OSNumber * offsetNum,
3585 const char * name)
3586 {
3587 OSSharedPtr<OSData> result;
3588 MkextEntryRef entryRef;
3589 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3590 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3591
3592 result = OSData::withCapacity(sizeof(entryRef));
3593 if (!result) {
3594 goto finish;
3595 }
3596
3597 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3598 entryRef.fileinfo = mkextBuffer + entryOffset;
3599 if (!result->appendValue(entryRef)) {
3600 result.reset();
3601 goto finish;
3602 }
3603
3604 finish:
3605 if (!result) {
3606 OSKextLog(this,
3607 kOSKextLogErrorLevel |
3608 kOSKextLogArchiveFlag,
3609 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3610 name, getIdentifierCString());
3611 }
3612 return result;
3613 }
3614
3615 /*********************************************************************
3616 *********************************************************************/
3617 extern "C" {
3618 static void * z_alloc(void *, u_int items, u_int size);
3619 static void z_free(void *, void *ptr);
3620
3621 typedef struct z_mem {
3622 uint32_t alloc_size;
3623 uint8_t data[0];
3624 } z_mem;
3625
3626 /*
3627 * Space allocation and freeing routines for use by zlib routines.
3628 */
3629 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3630 z_alloc(void * notused __unused, u_int num_items, u_int size)
3631 {
3632 void * result = NULL;
3633 z_mem * zmem = NULL;
3634
3635 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3636 //Check for overflow due to multiplication
3637 if (total > UINT32_MAX) {
3638 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3639 notused, num_items, size, num_items, size);
3640 }
3641
3642 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3643 //Check for overflow due to addition
3644 if (allocSize64 > UINT32_MAX) {
3645 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3646 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3647 }
3648 uint32_t allocSize = (uint32_t)allocSize64;
3649
3650 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3651 VM_KERN_MEMORY_OSKEXT);
3652 if (!zmem) {
3653 goto finish;
3654 }
3655 zmem->alloc_size = allocSize;
3656 result = (void *)&(zmem->data);
3657 finish:
3658 return result;
3659 }
3660
3661 void
z_free(void * notused __unused,void * ptr)3662 z_free(void * notused __unused, void * ptr)
3663 {
3664 uint32_t * skipper = (uint32_t *)ptr - 1;
3665 z_mem * zmem = (z_mem *)skipper;
3666 kfree_data(zmem, zmem->alloc_size);
3667 }
3668 };
3669
3670 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3671 OSKext::extractMkext2FileData(
3672 UInt8 * data,
3673 const char * name,
3674 uint32_t compressedSize,
3675 uint32_t fullSize)
3676 {
3677 OSSharedPtr<OSData> result;
3678 OSSharedPtr<OSData> uncompressedData; // release on error
3679
3680 uint8_t * uncompressedDataBuffer = NULL; // do not free
3681 unsigned long uncompressedSize;
3682 z_stream zstream;
3683 bool zstream_inited = false;
3684 int zlib_result;
3685
3686 /* If the file isn't compressed, we want to make a copy
3687 * so that we don't have the tie to the larger mkext file buffer any more.
3688 */
3689 if (!compressedSize) {
3690 uncompressedData = OSData::withBytes(data, fullSize);
3691 // xxx - no check for failure?
3692 result = uncompressedData;
3693 goto finish;
3694 }
3695
3696 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3697 (vm_offset_t*)&uncompressedDataBuffer, fullSize,
3698 KMA_DATA, VM_KERN_MEMORY_OSKEXT)) {
3699 /* How's this for cheesy? The kernel is only asked to extract
3700 * kext plists so we tailor the log messages.
3701 */
3702 if (isKernel()) {
3703 OSKextLog(this,
3704 kOSKextLogErrorLevel |
3705 kOSKextLogArchiveFlag,
3706 "Allocation failure extracting %s from mkext.", name);
3707 } else {
3708 OSKextLog(this,
3709 kOSKextLogErrorLevel |
3710 kOSKextLogArchiveFlag,
3711 "Allocation failure extracting %s from mkext for kext %s.",
3712 name, getIdentifierCString());
3713 }
3714
3715 goto finish;
3716 }
3717 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3718 if (!uncompressedData) {
3719 if (isKernel()) {
3720 OSKextLog(this,
3721 kOSKextLogErrorLevel |
3722 kOSKextLogArchiveFlag,
3723 "Allocation failure extracting %s from mkext.", name);
3724 } else {
3725 OSKextLog(this,
3726 kOSKextLogErrorLevel |
3727 kOSKextLogArchiveFlag,
3728 "Allocation failure extracting %s from mkext for kext %s.",
3729 name, getIdentifierCString());
3730 }
3731 goto finish;
3732 }
3733 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3734
3735 if (isKernel()) {
3736 OSKextLog(this,
3737 kOSKextLogDetailLevel |
3738 kOSKextLogArchiveFlag,
3739 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3740 name, compressedSize, fullSize);
3741 } else {
3742 OSKextLog(this,
3743 kOSKextLogDetailLevel |
3744 kOSKextLogArchiveFlag,
3745 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3746 getIdentifierCString(), name, compressedSize, fullSize);
3747 }
3748
3749 bzero(&zstream, sizeof(zstream));
3750 zstream.next_in = (UInt8 *)data;
3751 zstream.avail_in = compressedSize;
3752
3753 zstream.next_out = uncompressedDataBuffer;
3754 zstream.avail_out = fullSize;
3755
3756 zstream.zalloc = z_alloc;
3757 zstream.zfree = z_free;
3758
3759 zlib_result = inflateInit(&zstream);
3760 if (Z_OK != zlib_result) {
3761 if (isKernel()) {
3762 OSKextLog(this,
3763 kOSKextLogErrorLevel |
3764 kOSKextLogArchiveFlag,
3765 "Mkext error; zlib inflateInit failed (%d) for %s.",
3766 zlib_result, name);
3767 } else {
3768 OSKextLog(this,
3769 kOSKextLogErrorLevel |
3770 kOSKextLogArchiveFlag,
3771 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3772 getIdentifierCString(), zlib_result, name);
3773 }
3774 goto finish;
3775 } else {
3776 zstream_inited = true;
3777 }
3778
3779 zlib_result = inflate(&zstream, Z_FINISH);
3780
3781 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3782 uncompressedSize = zstream.total_out;
3783 } else {
3784 if (isKernel()) {
3785 OSKextLog(this,
3786 kOSKextLogErrorLevel |
3787 kOSKextLogArchiveFlag,
3788 "Mkext error; zlib inflate failed (%d) for %s.",
3789 zlib_result, name);
3790 } else {
3791 OSKextLog(this,
3792 kOSKextLogErrorLevel |
3793 kOSKextLogArchiveFlag,
3794 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3795 getIdentifierCString(), zlib_result, name);
3796 }
3797 if (zstream.msg) {
3798 OSKextLog(this,
3799 kOSKextLogErrorLevel |
3800 kOSKextLogArchiveFlag,
3801 "zlib error: %s.", zstream.msg);
3802 }
3803 goto finish;
3804 }
3805
3806 if (uncompressedSize != fullSize) {
3807 if (isKernel()) {
3808 OSKextLog(this,
3809 kOSKextLogErrorLevel |
3810 kOSKextLogArchiveFlag,
3811 "Mkext error; zlib inflate discrepancy for %s, "
3812 "uncompressed size != original size.", name);
3813 } else {
3814 OSKextLog(this,
3815 kOSKextLogErrorLevel |
3816 kOSKextLogArchiveFlag,
3817 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3818 "uncompressed size != original size.",
3819 getIdentifierCString(), name);
3820 }
3821 goto finish;
3822 }
3823
3824 result = os::move(uncompressedData);
3825
3826 finish:
3827 /* Don't bother checking return, nothing we can do on fail.
3828 */
3829 if (zstream_inited) {
3830 inflateEnd(&zstream);
3831 }
3832
3833 return result;
3834 }
3835
3836 /*********************************************************************
3837 *********************************************************************/
3838 /* static */
3839 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3840 OSKext::loadFromMkext(
3841 OSKextLogSpec clientLogFilter,
3842 char * mkextBuffer,
3843 uint32_t mkextBufferLength,
3844 char ** logInfoOut,
3845 uint32_t * logInfoLengthOut)
3846 {
3847 OSReturn result = kOSReturnError;
3848 OSReturn tempResult = kOSReturnError;
3849
3850 OSSharedPtr<OSData> mkextData;
3851 OSSharedPtr<OSDictionary> mkextPlist;
3852
3853 OSSharedPtr<OSArray> logInfoArray;
3854 OSSharedPtr<OSSerialize> serializer;
3855
3856 OSString * predicate = NULL; // do not release
3857 OSDictionary * requestArgs = NULL; // do not release
3858
3859 OSString * kextIdentifier = NULL; // do not release
3860 OSNumber * startKextExcludeNum = NULL; // do not release
3861 OSNumber * startMatchingExcludeNum = NULL; // do not release
3862 OSBoolean * delayAutounloadBool = NULL; // do not release
3863 OSArray * personalityNames = NULL; // do not release
3864
3865 /* Default values for these two options: regular autounload behavior,
3866 * load all kexts, send no personalities.
3867 */
3868 Boolean delayAutounload = false;
3869 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3870 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3871
3872 IORecursiveLockLock(sKextLock);
3873
3874 if (logInfoOut) {
3875 *logInfoOut = NULL;
3876 *logInfoLengthOut = 0;
3877 }
3878
3879 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3880
3881 OSKextLog(/* kext */ NULL,
3882 kOSKextLogDebugLevel |
3883 kOSKextLogIPCFlag,
3884 "Received kext load request from user space.");
3885
3886 /* Regardless of processing, the fact that we have gotten here means some
3887 * user-space program is up and talking to us, so we'll switch our kext
3888 * registration to reflect that.
3889 */
3890 if (!sUserLoadsActive) {
3891 OSKextLog(/* kext */ NULL,
3892 kOSKextLogProgressLevel |
3893 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3894 "Switching to late startup (user-space) kext loading policy.");
3895
3896 sUserLoadsActive = true;
3897 }
3898
3899 if (!sLoadEnabled) {
3900 OSKextLog(/* kext */ NULL,
3901 kOSKextLogErrorLevel |
3902 kOSKextLogLoadFlag,
3903 "Kext loading is disabled.");
3904 result = kOSKextReturnDisabled;
3905 goto finish;
3906 }
3907
3908 /* Note that we do not set a dealloc function on this OSData
3909 * object! No references to it can remain after the loadFromMkext()
3910 * call since we are in a MIG function, and will vm_deallocate()
3911 * the buffer.
3912 */
3913 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3914 mkextBufferLength);
3915 if (!mkextData) {
3916 OSKextLog(/* kext */ NULL,
3917 kOSKextLogErrorLevel |
3918 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3919 "Failed to create wrapper for kext load request.");
3920 result = kOSKextReturnNoMemory;
3921 goto finish;
3922 }
3923
3924 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3925 if (result != kOSReturnSuccess) {
3926 OSKextLog(/* kext */ NULL,
3927 kOSKextLogErrorLevel |
3928 kOSKextLogLoadFlag,
3929 "Failed to read kext load request.");
3930 goto finish;
3931 }
3932
3933 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3934 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3935 OSKextLog(/* kext */ NULL,
3936 kOSKextLogErrorLevel |
3937 kOSKextLogLoadFlag,
3938 "Received kext load request with no predicate; skipping.");
3939 result = kOSKextReturnInvalidArgument;
3940 goto finish;
3941 }
3942
3943 requestArgs = OSDynamicCast(OSDictionary,
3944 mkextPlist->getObject(kKextRequestArgumentsKey));
3945 if (!requestArgs || !requestArgs->getCount()) {
3946 OSKextLog(/* kext */ NULL,
3947 kOSKextLogErrorLevel |
3948 kOSKextLogLoadFlag,
3949 "Received kext load request with no arguments.");
3950 result = kOSKextReturnInvalidArgument;
3951 goto finish;
3952 }
3953
3954 kextIdentifier = OSDynamicCast(OSString,
3955 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3956
3957 if (!kextIdentifier) {
3958 OSKextLog(/* kext */ NULL,
3959 kOSKextLogErrorLevel |
3960 kOSKextLogLoadFlag,
3961 "Received kext load request with no kext identifier.");
3962 result = kOSKextReturnInvalidArgument;
3963 goto finish;
3964 }
3965
3966 startKextExcludeNum = OSDynamicCast(OSNumber,
3967 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3968 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3969 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3970 delayAutounloadBool = OSDynamicCast(OSBoolean,
3971 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3972 personalityNames = OSDynamicCast(OSArray,
3973 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3974
3975 if (delayAutounloadBool) {
3976 delayAutounload = delayAutounloadBool->getValue();
3977 }
3978 if (startKextExcludeNum) {
3979 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3980 }
3981 if (startMatchingExcludeNum) {
3982 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3983 }
3984
3985 OSKextLog(/* kext */ NULL,
3986 kOSKextLogProgressLevel |
3987 kOSKextLogIPCFlag,
3988 "Received request from user space to load kext %s.",
3989 kextIdentifier->getCStringNoCopy());
3990
3991 /* Load the kext, with no deferral, since this is a load from outside
3992 * the kernel.
3993 * xxx - Would like a better way to handle the default values for the
3994 * xxx - start/match opt args.
3995 */
3996 result = OSKext::loadKextWithIdentifier(
3997 kextIdentifier,
3998 /* kextRef */ NULL,
3999 /* allowDefer */ false,
4000 delayAutounload,
4001 startKextExcludeLevel,
4002 startMatchingExcludeLevel,
4003 personalityNames);
4004 if (result != kOSReturnSuccess) {
4005 goto finish;
4006 }
4007 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
4008 * for matching via a separate IOKit calldown.
4009 */
4010
4011 finish:
4012
4013 /* Gather up the collected log messages for user space. Any
4014 * error messages past this call will not make it up as log messages
4015 * but will be in the system log.
4016 */
4017 logInfoArray = OSKext::clearUserSpaceLogFilter();
4018
4019 if (logInfoArray && logInfoOut && logInfoLengthOut) {
4020 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
4021 logInfoOut, logInfoLengthOut);
4022 if (tempResult != kOSReturnSuccess) {
4023 result = tempResult;
4024 }
4025 }
4026
4027 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
4028
4029 IORecursiveLockUnlock(sKextLock);
4030
4031 /* Note: mkextDataObject will have been retained by every kext w/an
4032 * executable in it. That should all have been flushed out at the
4033 * and of the load operation, but you never know....
4034 */
4035 if (mkextData && mkextData->getRetainCount() > 1) {
4036 OSKextLog(/* kext */ NULL,
4037 kOSKextLogErrorLevel |
4038 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4039 "Kext load request buffer from user space still retained by a kext; "
4040 "probable memory leak.");
4041 }
4042
4043 return result;
4044 }
4045
4046 #endif // CONFIG_KXLD
4047
4048 /*********************************************************************
4049 *********************************************************************/
4050 /* static */
4051 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)4052 OSKext::serializeLogInfo(
4053 OSArray * logInfoArray,
4054 char ** logInfoOut,
4055 uint32_t * logInfoLengthOut)
4056 {
4057 OSReturn result = kOSReturnError;
4058 char * buffer = NULL;
4059 kern_return_t kmem_result = KERN_FAILURE;
4060 OSSharedPtr<OSSerialize> serializer;
4061 char * logInfo = NULL; // returned by reference
4062 uint32_t logInfoLength = 0;
4063
4064 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
4065 OSKextLog(/* kext */ NULL,
4066 kOSKextLogErrorLevel |
4067 kOSKextLogIPCFlag,
4068 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
4069 /* Bad programmer. */
4070 result = kOSKextReturnInvalidArgument;
4071 goto finish;
4072 }
4073
4074 serializer = OSSerialize::withCapacity(0);
4075 if (!serializer) {
4076 OSKextLog(/* kext */ NULL,
4077 kOSKextLogErrorLevel |
4078 kOSKextLogIPCFlag,
4079 "Failed to create serializer on log info for request from user space.");
4080 /* Incidental error; we're going to (try to) allow the request
4081 * itself to succeed. */
4082 } else {
4083 if (!logInfoArray->serialize(serializer.get())) {
4084 OSKextLog(/* kext */ NULL,
4085 kOSKextLogErrorLevel |
4086 kOSKextLogIPCFlag,
4087 "Failed to serialize log info for request from user space.");
4088 /* Incidental error; we're going to (try to) allow the request
4089 * itself to succeed. */
4090 } else {
4091 logInfo = serializer->text();
4092 logInfoLength = serializer->getLength();
4093
4094 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength),
4095 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
4096 if (kmem_result != KERN_SUCCESS) {
4097 OSKextLog(/* kext */ NULL,
4098 kOSKextLogErrorLevel |
4099 kOSKextLogIPCFlag,
4100 "Failed to copy log info for request from user space.");
4101 /* Incidental error; we're going to (try to) allow the request
4102 * to succeed. */
4103 } else {
4104 /* 11981737 - clear uninitialized data in last page */
4105 bzero((void *)(buffer + logInfoLength),
4106 (round_page(logInfoLength) - logInfoLength));
4107 memcpy(buffer, logInfo, logInfoLength);
4108 *logInfoOut = buffer;
4109 *logInfoLengthOut = logInfoLength;
4110 }
4111 }
4112 }
4113
4114 result = kOSReturnSuccess;
4115 finish:
4116 return result;
4117 }
4118
4119 #if PRAGMA_MARK
4120 #pragma mark Instance Management Methods
4121 #endif
4122 /*********************************************************************
4123 *********************************************************************/
4124 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)4125 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
4126 {
4127 OSSharedPtr<OSKext> foundKext;
4128
4129 IORecursiveLockLock(sKextLock);
4130 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
4131 IORecursiveLockUnlock(sKextLock);
4132
4133 return foundKext;
4134 }
4135
4136 /*********************************************************************
4137 *********************************************************************/
4138 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)4139 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
4140 {
4141 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
4142 }
4143
4144 /*********************************************************************
4145 *********************************************************************/
4146 OSSharedPtr<OSKext>
lookupDextWithIdentifier(OSString * dextIdentifier,OSData * dextUniqueIdentifier)4147 OSKext::lookupDextWithIdentifier(OSString * dextIdentifier, OSData *dextUniqueIdentifier)
4148 {
4149 OSSharedPtr<OSKext> foundDext;
4150 foundDext.reset();
4151
4152 IORecursiveLockLock(sKextLock);
4153 OSKext *dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIdentifier->getCStringNoCopy()));
4154 if (dext != NULL && dext->isDriverKit()) {
4155 if (dext->dextUniqueID == NULL || dext->dextUniqueID->isEqualTo(dextUniqueIdentifier)) {
4156 foundDext.reset(dext, OSRetain);
4157 }
4158 }
4159 IORecursiveLockUnlock(sKextLock);
4160
4161 return foundDext;
4162 }
4163
4164 /*********************************************************************
4165 *********************************************************************/
4166 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)4167 OSKext::lookupKextWithLoadTag(uint32_t aTag)
4168 {
4169 OSSharedPtr<OSKext> foundKext; // returned
4170 uint32_t i, j;
4171 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4172 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4173
4174 IORecursiveLockLock(sKextLock);
4175
4176 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4177 for (i = 0; i < count[j]; i++) {
4178 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4179 if (thisKext->getLoadTag() == aTag) {
4180 foundKext.reset(thisKext, OSRetain);
4181 goto finish;
4182 }
4183 }
4184 }
4185
4186 finish:
4187 IORecursiveLockUnlock(sKextLock);
4188
4189 return foundKext;
4190 }
4191
4192 /*********************************************************************
4193 *********************************************************************/
4194 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)4195 OSKext::lookupKextWithAddress(vm_address_t address)
4196 {
4197 OSSharedPtr<OSKext> foundKext; // returned
4198 uint32_t count, i;
4199 kmod_info_t *kmod_info;
4200 vm_address_t originalAddress;
4201 #if defined(__arm64__)
4202 uint64_t textExecBase;
4203 size_t textExecSize;
4204 #endif /* defined(__arm64__) */
4205
4206 originalAddress = address;
4207 #if __has_feature(ptrauth_calls)
4208 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
4209 #endif /* __has_feature(ptrauth_calls) */
4210
4211 IORecursiveLockLock(sKextLock);
4212
4213 count = sLoadedKexts->getCount();
4214 for (i = 0; i < count; i++) {
4215 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
4216 if (thisKext == sKernelKext) {
4217 continue;
4218 }
4219 if (thisKext->kmod_info && thisKext->kmod_info->address) {
4220 kmod_info = thisKext->kmod_info;
4221 vm_address_t kext_start = kmod_info->address;
4222 vm_address_t kext_end = kext_start + kmod_info->size;
4223 if ((kext_start <= address) && (address < kext_end)) {
4224 foundKext.reset(thisKext, OSRetain);
4225 goto finish;
4226 }
4227 #if defined(__arm64__)
4228 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
4229 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4230 foundKext.reset(thisKext, OSRetain);
4231 goto finish;
4232 }
4233 #endif /* defined (__arm64__) */
4234 }
4235 }
4236 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4237 foundKext.reset(sKernelKext, OSRetain);
4238 goto finish;
4239 }
4240 /*
4241 * DriverKit userspace executables do not have a kernel linkedExecutable,
4242 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4243 * here, so use the original address passed to this method.
4244 *
4245 * This is supposed to be used for logging reasons only. When logd
4246 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4247 * remove it here before checking it against the LoadTag.
4248 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4249 */
4250
4251 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4252 count = sLoadedDriverKitKexts->getCount();
4253 for (i = 0; i < count; i++) {
4254 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4255 if (thisKext->getLoadTag() == address) {
4256 foundKext.reset(thisKext, OSRetain);
4257 }
4258 }
4259
4260 finish:
4261 IORecursiveLockUnlock(sKextLock);
4262
4263 return foundKext;
4264 }
4265
4266 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)4267 OSKext::copyKextUUIDForAddress(OSNumber *address)
4268 {
4269 OSSharedPtr<OSData> uuid;
4270 OSSharedPtr<OSKext> kext;
4271
4272 if (!address) {
4273 return NULL;
4274 }
4275
4276 #if CONFIG_MACF
4277 /* Is the calling process allowed to query kext info? */
4278 if (current_task() != kernel_task) {
4279 int macCheckResult = 0;
4280 kauth_cred_t cred = NULL;
4281
4282 cred = kauth_cred_get_with_ref();
4283 macCheckResult = mac_kext_check_query(cred);
4284 kauth_cred_unref(&cred);
4285
4286 if (macCheckResult != 0) {
4287 OSKextLog(/* kext */ NULL,
4288 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4289 "Failed to query kext UUID (MAC policy error 0x%x).",
4290 macCheckResult);
4291 return NULL;
4292 }
4293 }
4294 #endif
4295
4296 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4297 if (slidAddress != 0) {
4298 kext = lookupKextWithAddress(slidAddress);
4299 if (kext) {
4300 uuid = kext->copyTextUUID();
4301 }
4302 }
4303
4304 if (!uuid) {
4305 /*
4306 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4307 * a kext. This might have happened because the log message came from a dext.
4308 *
4309 * Try again with the original address.
4310 */
4311 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4312 if (kext && kext->isDriverKit()) {
4313 uuid = kext->copyTextUUID();
4314 }
4315 }
4316
4317 return uuid;
4318 }
4319
4320 /*********************************************************************
4321 *********************************************************************/
4322 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4323 OSKext::lookupKextWithUUID(uuid_t wanted)
4324 {
4325 OSSharedPtr<OSKext> foundKext; // returned
4326 uint32_t j, i;
4327 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4328 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4329
4330
4331 IORecursiveLockLock(sKextLock);
4332
4333 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4334 for (i = 0; i < count[j]; i++) {
4335 OSKext * thisKext = NULL;
4336
4337 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4338 if (!thisKext) {
4339 continue;
4340 }
4341
4342 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4343 if (!uuid_data) {
4344 continue;
4345 }
4346
4347 uuid_t uuid;
4348 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4349
4350 if (0 == uuid_compare(wanted, uuid)) {
4351 foundKext.reset(thisKext, OSRetain);
4352 goto finish;
4353 }
4354 }
4355 }
4356 finish:
4357 IORecursiveLockUnlock(sKextLock);
4358
4359 return foundKext;
4360 }
4361
4362
4363
4364
4365 /*********************************************************************
4366 *********************************************************************/
4367 /* static */
4368 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4369 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4370 {
4371 bool result = false;
4372 OSKext * foundKext = NULL; // returned
4373
4374 IORecursiveLockLock(sKextLock);
4375
4376 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4377 if (foundKext && foundKext->isLoaded()) {
4378 result = true;
4379 }
4380
4381 IORecursiveLockUnlock(sKextLock);
4382
4383 return result;
4384 }
4385
4386 /*********************************************************************
4387 * xxx - should spawn a separate thread so a kext can safely have
4388 * xxx - itself unloaded.
4389 *********************************************************************/
4390 /* static */
4391 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4392 OSKext::removeKext(
4393 OSKext * aKext,
4394 #if CONFIG_EMBEDDED
4395 __unused
4396 #endif
4397 bool terminateServicesAndRemovePersonalitiesFlag)
4398 {
4399 #if CONFIG_EMBEDDED
4400 if (!aKext->isDriverKit()) {
4401 OSKextLog(aKext,
4402 kOSKextLogErrorLevel |
4403 kOSKextLogKextBookkeepingFlag,
4404 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4405 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4406
4407 return kOSReturnSuccess;
4408 }
4409 #endif /* CONFIG_EMBEDDED */
4410 OSReturn result = kOSKextReturnInUse;
4411 OSKext * checkKext = NULL; // do not release
4412 #if CONFIG_MACF
4413 int macCheckResult = 0;
4414 kauth_cred_t cred = NULL;
4415 #endif
4416
4417 IORecursiveLockLock(sKextLock);
4418
4419 /* If the kext has no identifier, it failed to init
4420 * so isn't in sKextsByID and it isn't loaded.
4421 */
4422 if (!aKext->getIdentifier()) {
4423 result = kOSReturnSuccess;
4424 goto finish;
4425 }
4426
4427 checkKext = OSDynamicCast(OSKext,
4428 sKextsByID->getObject(aKext->getIdentifier()));
4429 if (checkKext != aKext) {
4430 result = kOSKextReturnNotFound;
4431 goto finish;
4432 }
4433
4434 if (aKext->isLoaded() || aKext->isDriverKit()) {
4435 #if CONFIG_MACF
4436 if (current_task() != kernel_task) {
4437 cred = kauth_cred_get_with_ref();
4438 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4439 kauth_cred_unref(&cred);
4440 }
4441
4442 if (macCheckResult != 0) {
4443 result = kOSReturnError;
4444 OSKextLog(aKext,
4445 kOSKextLogErrorLevel |
4446 kOSKextLogKextBookkeepingFlag,
4447 "Failed to remove kext %s (MAC policy error 0x%x).",
4448 aKext->getIdentifierCString(), macCheckResult);
4449 goto finish;
4450 }
4451 #endif
4452
4453 /* make sure there are no resource requests in flight - 17187548 */
4454 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4455 goto finish;
4456 }
4457 if (aKext->flags.unloadUnsupported) {
4458 result = kOSKextReturnInUse;
4459 OSKextLog(aKext,
4460 kOSKextLogErrorLevel |
4461 kOSKextLogKextBookkeepingFlag,
4462 "Can't remove kext %s; unsupported by cache.",
4463 aKext->getIdentifierCString());
4464 goto finish;
4465 }
4466
4467 /* If we are terminating, send the request to the IOCatalogue
4468 * (which will actually call us right back but that's ok we have
4469 * a recursive lock don't you know) but do not ask the IOCatalogue
4470 * to call back with an unload, we'll do that right here.
4471 */
4472 if (terminateServicesAndRemovePersonalitiesFlag) {
4473 result = gIOCatalogue->terminateDriversForModule(
4474 aKext->getIdentifierCString(), /* unload */ false);
4475 if (result != kOSReturnSuccess) {
4476 OSKextLog(aKext,
4477 kOSKextLogErrorLevel |
4478 kOSKextLogKextBookkeepingFlag,
4479 "Can't remove kext %s; services failed to terminate - 0x%x.",
4480 aKext->getIdentifierCString(), result);
4481 goto finish;
4482 }
4483 }
4484
4485 result = aKext->unload();
4486 if (result != kOSReturnSuccess) {
4487 OSKextLog(aKext,
4488 kOSKextLogErrorLevel |
4489 kOSKextLogKextBookkeepingFlag,
4490 "Can't remove kext %s; kext failed to unload - 0x%x.",
4491 aKext->getIdentifierCString(), result);
4492 goto finish;
4493 }
4494 }
4495
4496 /* Remove personalities as requested. This is a bit redundant for a loaded
4497 * kext as IOCatalogue::terminateDriversForModule() removes driver
4498 * personalities, but it doesn't restart matching, which we always want
4499 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4500 * that happens.
4501 */
4502 if (terminateServicesAndRemovePersonalitiesFlag) {
4503 aKext->removePersonalitiesFromCatalog();
4504 }
4505
4506 if (aKext->isInFileset()) {
4507 OSKextLog(aKext,
4508 kOSKextLogProgressLevel |
4509 kOSKextLogKextBookkeepingFlag,
4510 "Fileset kext %s unloaded.",
4511 aKext->getIdentifierCString());
4512 } else {
4513 OSKextLog(aKext,
4514 kOSKextLogProgressLevel |
4515 kOSKextLogKextBookkeepingFlag,
4516 "Removing kext %s.",
4517 aKext->getIdentifierCString());
4518
4519 sKextsByID->removeObject(aKext->getIdentifier());
4520 }
4521 result = kOSReturnSuccess;
4522
4523 finish:
4524 IORecursiveLockUnlock(sKextLock);
4525 return result;
4526 }
4527
4528 /*********************************************************************
4529 *********************************************************************/
4530 /* static */
4531 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4532 OSKext::removeKextWithIdentifier(
4533 const char * kextIdentifier,
4534 bool terminateServicesAndRemovePersonalitiesFlag)
4535 {
4536 OSReturn result = kOSReturnError;
4537
4538 IORecursiveLockLock(sKextLock);
4539
4540 OSKext * aKext = OSDynamicCast(OSKext,
4541 sKextsByID->getObject(kextIdentifier));
4542 if (!aKext) {
4543 result = kOSKextReturnNotFound;
4544 OSKextLog(/* kext */ NULL,
4545 kOSKextLogErrorLevel |
4546 kOSKextLogKextBookkeepingFlag,
4547 "Can't remove kext %s - not found.",
4548 kextIdentifier);
4549 goto finish;
4550 }
4551
4552 result = OSKext::removeKext(aKext,
4553 terminateServicesAndRemovePersonalitiesFlag);
4554
4555 finish:
4556 IORecursiveLockUnlock(sKextLock);
4557
4558 return result;
4559 }
4560
4561 /*********************************************************************
4562 *********************************************************************/
4563 /* static */
4564 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4565 OSKext::removeKextWithLoadTag(
4566 OSKextLoadTag loadTag,
4567 bool terminateServicesAndRemovePersonalitiesFlag)
4568 {
4569 OSReturn result = kOSReturnError;
4570 OSKext * foundKext = NULL;
4571 uint32_t i, j;
4572 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4573 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4574
4575
4576 IORecursiveLockLock(sKextLock);
4577
4578 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4579 for (i = 0; i < count[j]; i++) {
4580 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4581 if (thisKext->loadTag == loadTag) {
4582 foundKext = thisKext;
4583 break;
4584 }
4585 }
4586 }
4587
4588 if (!foundKext) {
4589 result = kOSKextReturnNotFound;
4590 OSKextLog(/* kext */ NULL,
4591 kOSKextLogErrorLevel |
4592 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4593 "Can't remove kext with load tag %d - not found.",
4594 loadTag);
4595 goto finish;
4596 }
4597
4598 result = OSKext::removeKext(foundKext,
4599 terminateServicesAndRemovePersonalitiesFlag);
4600
4601 finish:
4602 IORecursiveLockUnlock(sKextLock);
4603
4604 return result;
4605 }
4606
4607 /*********************************************************************
4608 *********************************************************************/
4609 OSSharedPtr<OSDictionary>
copyKexts(void)4610 OSKext::copyKexts(void)
4611 {
4612 OSSharedPtr<OSDictionary> result;
4613
4614 IORecursiveLockLock(sKextLock);
4615 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4616 IORecursiveLockUnlock(sKextLock);
4617
4618 return result;
4619 }
4620
4621 /*********************************************************************
4622 *********************************************************************/
4623 #define BOOTER_KEXT_PREFIX "Driver-"
4624
4625 typedef struct _DeviceTreeBuffer {
4626 uint32_t paddr;
4627 uint32_t length;
4628 } _DeviceTreeBuffer;
4629
4630 /*********************************************************************
4631 * Create a dictionary of excluded kexts from the given booter data.
4632 *********************************************************************/
4633 /* static */
4634 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4635 OSKext::createExcludeListFromBooterData(
4636 OSDictionary * theDictionary,
4637 OSCollectionIterator * theIterator )
4638 {
4639 OSString * deviceTreeName = NULL; // do not release
4640 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4641 char * booterDataPtr = NULL; // do not release
4642 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4643 char * infoDictAddr = NULL; // do not release
4644 OSSharedPtr<OSObject> parsedXML;
4645 OSDictionary * theInfoDict = NULL; // do not release
4646
4647 theIterator->reset();
4648
4649 /* look for AppleKextExcludeList.kext */
4650 while ((deviceTreeName =
4651 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4652 const char * devTreeNameCString;
4653 OSData * deviceTreeEntry; // do not release
4654 OSString * myBundleID; // do not release
4655
4656 deviceTreeEntry =
4657 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4658 if (!deviceTreeEntry) {
4659 continue;
4660 }
4661
4662 /* Make sure it is a kext */
4663 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4664 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4665 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4666 OSKextLog(NULL,
4667 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4668 "\"%s\" not a kext",
4669 devTreeNameCString);
4670 continue;
4671 }
4672
4673 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4674 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4675 if (!deviceTreeBuffer) {
4676 continue;
4677 }
4678
4679 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4680 if (!booterDataPtr) {
4681 continue;
4682 }
4683
4684 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4685 if (!kextFileInfo->infoDictPhysAddr ||
4686 !kextFileInfo->infoDictLength) {
4687 continue;
4688 }
4689
4690 infoDictAddr = (char *)
4691 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4692 if (!infoDictAddr) {
4693 continue;
4694 }
4695
4696 parsedXML = OSUnserializeXML(infoDictAddr);
4697 if (!parsedXML) {
4698 continue;
4699 }
4700
4701 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4702 if (!theInfoDict) {
4703 continue;
4704 }
4705
4706 myBundleID =
4707 OSDynamicCast(OSString,
4708 theInfoDict->getObject(kCFBundleIdentifierKey));
4709 if (myBundleID &&
4710 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4711 boolean_t updated = updateExcludeList(theInfoDict);
4712 if (!updated) {
4713 /* 25322874 */
4714 panic("Missing OSKextExcludeList dictionary");
4715 }
4716 break;
4717 }
4718 } // while ( (deviceTreeName = ...) )
4719
4720 return;
4721 }
4722
4723 /*********************************************************************
4724 * Create a dictionary of excluded kexts from the given prelink
4725 * info (kernelcache).
4726 *********************************************************************/
4727 /* static */
4728 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4729 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4730 {
4731 OSDictionary * myInfoDict = NULL; // do not release
4732 OSString * myBundleID; // do not release
4733 u_int i;
4734
4735 /* Find the Apple Kext Exclude List. */
4736 for (i = 0; i < theInfoArray->getCount(); i++) {
4737 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4738 if (!myInfoDict) {
4739 continue;
4740 }
4741 myBundleID =
4742 OSDynamicCast(OSString,
4743 myInfoDict->getObject(kCFBundleIdentifierKey));
4744 if (myBundleID &&
4745 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4746 boolean_t updated = updateExcludeList(myInfoDict);
4747 if (!updated) {
4748 /* 25322874 */
4749 panic("Missing OSKextExcludeList dictionary");
4750 }
4751 break;
4752 }
4753 } // for (i = 0; i < theInfoArray->getCount()...
4754
4755 return;
4756 }
4757
4758 /* static */
4759 boolean_t
updateExcludeList(OSDictionary * infoDict)4760 OSKext::updateExcludeList(OSDictionary *infoDict)
4761 {
4762 OSDictionary *myTempDict = NULL; // do not free
4763 OSString *myTempString = NULL; // do not free
4764 OSKextVersion newVersion = 0;
4765 boolean_t updated = false;
4766
4767 if (!infoDict) {
4768 return false;
4769 }
4770
4771 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4772 if (!myTempDict) {
4773 return false;
4774 }
4775
4776 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4777 if (!myTempString) {
4778 return false;
4779 }
4780
4781 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4782 if (newVersion == 0) {
4783 return false;
4784 }
4785
4786 IORecursiveLockLock(sKextLock);
4787
4788 if (newVersion > sExcludeListVersion) {
4789 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4790 sExcludeListVersion = newVersion;
4791 updated = true;
4792 }
4793
4794 IORecursiveLockUnlock(sKextLock);
4795 return updated;
4796 }
4797
4798 #if PRAGMA_MARK
4799 #pragma mark Accessors
4800 #endif
4801
4802 /*********************************************************************
4803 *********************************************************************/
4804 const OSObject *
getBundleExecutable(void)4805 OSKext::getBundleExecutable(void)
4806 {
4807 return infoDict->getObject(kCFBundleExecutableKey);
4808 }
4809
4810 /*********************************************************************
4811 *********************************************************************/
4812 const OSSymbol *
getIdentifier(void)4813 OSKext::getIdentifier(void)
4814 {
4815 return bundleID.get();
4816 }
4817
4818 /*********************************************************************
4819 * A kext must have a bundle identifier to even survive initialization;
4820 * this is guaranteed to exist past then.
4821 *********************************************************************/
4822 const char *
getIdentifierCString(void)4823 OSKext::getIdentifierCString(void)
4824 {
4825 return bundleID->getCStringNoCopy();
4826 }
4827
4828 /*********************************************************************
4829 *********************************************************************/
4830 OSKextVersion
getVersion(void)4831 OSKext::getVersion(void)
4832 {
4833 return version;
4834 }
4835
4836 /*********************************************************************
4837 *********************************************************************/
4838 OSKextVersion
getCompatibleVersion(void)4839 OSKext::getCompatibleVersion(void)
4840 {
4841 return compatibleVersion;
4842 }
4843
4844 /*********************************************************************
4845 *********************************************************************/
4846 bool
isLibrary(void)4847 OSKext::isLibrary(void)
4848 {
4849 return getCompatibleVersion() > 0;
4850 }
4851
4852 /*********************************************************************
4853 *********************************************************************/
4854 bool
isCompatibleWithVersion(OSKextVersion aVersion)4855 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4856 {
4857 if ((compatibleVersion > -1 && version > -1) &&
4858 (compatibleVersion <= version && aVersion <= version)) {
4859 return true;
4860 }
4861 return false;
4862 }
4863
4864 /*********************************************************************
4865 *********************************************************************/
4866 bool
declaresExecutable(void)4867 OSKext::declaresExecutable(void)
4868 {
4869 if (isDriverKit()) {
4870 return false;
4871 }
4872 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4873 }
4874
4875 /*********************************************************************
4876 *********************************************************************/
4877 OSData *
getExecutable(void)4878 OSKext::getExecutable(void)
4879 {
4880 OSData * result = NULL;
4881 OSSharedPtr<OSData> extractedExecutable;
4882
4883 if (flags.builtin) {
4884 return sKernelKext->linkedExecutable.get();
4885 }
4886
4887 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4888 if (result) {
4889 return result;
4890 }
4891
4892 #if CONFIG_KXLD
4893 OSData * mkextExecutableRef = NULL; // do not release
4894 mkextExecutableRef = OSDynamicCast(OSData,
4895 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4896
4897 if (mkextExecutableRef) {
4898 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4899 mkextExecutableRef->getBytesNoCopy();
4900 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4901 if (mkextVersion == MKEXT_VERS_2) {
4902 mkext2_file_entry * fileinfo =
4903 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4904 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4905 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4906 extractedExecutable = extractMkext2FileData(
4907 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4908 compressedSize, fullSize);
4909 } else {
4910 OSKextLog(this, kOSKextLogErrorLevel |
4911 kOSKextLogArchiveFlag,
4912 "Kext %s - unknown mkext version 0x%x for executable.",
4913 getIdentifierCString(), mkextVersion);
4914 }
4915
4916 /* Regardless of success, remove the mkext executable,
4917 * and drop one reference on the mkext. (setExecutable() does not
4918 * replace, it removes, or panics if asked to replace.)
4919 */
4920 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4921 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4922
4923 if (extractedExecutable && extractedExecutable->getLength()) {
4924 if (!setExecutable(extractedExecutable.get())) {
4925 goto finish;
4926 }
4927 result = extractedExecutable.get();
4928 } else {
4929 goto finish;
4930 }
4931 }
4932
4933 finish:
4934 #endif // CONFIG_KXLD
4935 return result;
4936 }
4937
4938 /*********************************************************************
4939 *********************************************************************/
4940 bool
isInterface(void)4941 OSKext::isInterface(void)
4942 {
4943 return flags.interface;
4944 }
4945
4946 /*********************************************************************
4947 *********************************************************************/
4948 bool
isKernel(void)4949 OSKext::isKernel(void)
4950 {
4951 return this == sKernelKext;
4952 }
4953
4954 /*********************************************************************
4955 *********************************************************************/
4956 bool
isKernelComponent(void)4957 OSKext::isKernelComponent(void)
4958 {
4959 return flags.kernelComponent ? true : false;
4960 }
4961
4962 /*********************************************************************
4963 *********************************************************************/
4964 bool
isExecutable(void)4965 OSKext::isExecutable(void)
4966 {
4967 return !isKernel() && !isInterface() && declaresExecutable();
4968 }
4969
4970 /*********************************************************************
4971 * We might want to check this recursively for all dependencies,
4972 * since a subtree of dependencies could get loaded before we hit
4973 * a dependency that isn't safe-boot-loadable.
4974 *
4975 * xxx - Might want to return false if OSBundleEnableKextLogging or
4976 * OSBundleDebugLevel
4977 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4978 * the point except it's usually development drivers, which might
4979 * cause panics on startup, that have those properties). Heh; could
4980 * use a "kx" boot-arg!
4981 *********************************************************************/
4982 bool
isLoadableInSafeBoot(void)4983 OSKext::isLoadableInSafeBoot(void)
4984 {
4985 bool result = false;
4986 OSString * required = NULL; // do not release
4987
4988 if (isKernel()) {
4989 result = true;
4990 goto finish;
4991 }
4992
4993 if (isDriverKit()) {
4994 result = true;
4995 goto finish;
4996 }
4997
4998 required = OSDynamicCast(OSString,
4999 getPropertyForHostArch(kOSBundleRequiredKey));
5000 if (!required) {
5001 goto finish;
5002 }
5003 if (required->isEqualTo(kOSBundleRequiredRoot) ||
5004 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
5005 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
5006 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
5007 required->isEqualTo(kOSBundleRequiredConsole)) {
5008 result = true;
5009 }
5010
5011 finish:
5012 return result;
5013 }
5014
5015 /*********************************************************************
5016 *********************************************************************/
5017 bool
isPrelinked(void)5018 OSKext::isPrelinked(void)
5019 {
5020 return flags.prelinked ? true : false;
5021 }
5022
5023 /*********************************************************************
5024 *********************************************************************/
5025 bool
isLoaded(void)5026 OSKext::isLoaded(void)
5027 {
5028 return flags.loaded ? true : false;
5029 }
5030
5031 /*********************************************************************
5032 *********************************************************************/
5033 bool
isStarted(void)5034 OSKext::isStarted(void)
5035 {
5036 return flags.started ? true : false;
5037 }
5038
5039 /*********************************************************************
5040 *********************************************************************/
5041 bool
isCPPInitialized(void)5042 OSKext::isCPPInitialized(void)
5043 {
5044 return flags.CPPInitialized;
5045 }
5046
5047 /*********************************************************************
5048 *********************************************************************/
5049 void
setCPPInitialized(bool initialized)5050 OSKext::setCPPInitialized(bool initialized)
5051 {
5052 flags.CPPInitialized = initialized;
5053 }
5054
5055 /*********************************************************************
5056 *********************************************************************/
5057 uint32_t
getLoadTag(void)5058 OSKext::getLoadTag(void)
5059 {
5060 return loadTag;
5061 }
5062
5063 /*********************************************************************
5064 *********************************************************************/
5065 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)5066 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5067 {
5068 if (linkedExecutable) {
5069 *loadSize = linkedExecutable->getLength();
5070
5071 /* If we have a kmod_info struct, calculated the wired size
5072 * from that. Otherwise it's the full load size.
5073 */
5074 if (kmod_info) {
5075 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5076 } else {
5077 *wiredSize = *loadSize;
5078 }
5079 } else {
5080 *wiredSize = 0;
5081 *loadSize = 0;
5082 }
5083 }
5084
5085 /*********************************************************************
5086 *********************************************************************/
5087 OSSharedPtr<OSData>
copyUUID(void)5088 OSKext::copyUUID(void)
5089 {
5090 OSSharedPtr<OSData> result;
5091 OSData * theExecutable = NULL; // do not release
5092 const kernel_mach_header_t * header;
5093
5094 /* An interface kext doesn't have a linked executable with an LC_UUID,
5095 * we create one when it's linked.
5096 */
5097 if (interfaceUUID) {
5098 result = interfaceUUID;
5099 goto finish;
5100 }
5101
5102 if (flags.builtin || isInterface()) {
5103 return sKernelKext->copyUUID();
5104 }
5105
5106 if (isDriverKit() && infoDict) {
5107 return driverKitUUID;
5108 }
5109
5110 /* For real kexts, try to get the UUID from the linked executable,
5111 * or if is hasn't been linked yet, the unrelocated executable.
5112 */
5113 theExecutable = linkedExecutable.get();
5114 if (!theExecutable) {
5115 theExecutable = getExecutable();
5116 }
5117
5118 if (!theExecutable) {
5119 goto finish;
5120 }
5121
5122 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5123 result = copyMachoUUID(header);
5124
5125 finish:
5126 return result;
5127 }
5128
5129 /*********************************************************************
5130 *********************************************************************/
5131 OSSharedPtr<OSData>
copyTextUUID(void)5132 OSKext::copyTextUUID(void)
5133 {
5134 if (flags.builtin) {
5135 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
5136 }
5137 return copyUUID();
5138 }
5139
5140 /*********************************************************************
5141 *********************************************************************/
5142 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)5143 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5144 {
5145 OSSharedPtr<OSData> result;
5146 const struct load_command * load_cmd = NULL;
5147 const struct uuid_command * uuid_cmd = NULL;
5148 uint32_t i;
5149
5150 load_cmd = (const struct load_command *)&header[1];
5151
5152 if (header->magic != MH_MAGIC_KERNEL) {
5153 OSKextLog(NULL,
5154 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5155 "%s: bad header %p",
5156 __func__,
5157 header);
5158 goto finish;
5159 }
5160
5161 for (i = 0; i < header->ncmds; i++) {
5162 if (load_cmd->cmd == LC_UUID) {
5163 uuid_cmd = (struct uuid_command *)load_cmd;
5164 result = OSData::withValue(uuid_cmd->uuid);
5165 goto finish;
5166 }
5167 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5168 }
5169
5170 finish:
5171 return result;
5172 }
5173
5174 void
setDriverKitUUID(OSData * uuid)5175 OSKext::setDriverKitUUID(OSData *uuid)
5176 {
5177 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5178 OSSafeReleaseNULL(uuid);
5179 }
5180 }
5181
5182 OSData *
getDextUniqueID(void)5183 OSKext::getDextUniqueID(void)
5184 {
5185 if (isDriverKit() && dextUniqueID != NULL) {
5186 return dextUniqueID.get();
5187 }
5188
5189 return NULL;
5190 }
5191
5192 /*
5193 * In case a DextUniqueID exists this function returns
5194 * an allocated char* with the hexadecimal represantition of
5195 * DextUniqueID.
5196 * The returned pinter needs to be freed with kfree_data, the
5197 * size of the allocated buffer is returned in size.
5198 */
5199 static const char *
getDextUniqueIDCString(OSData * dextUniqueID,unsigned int * size)5200 getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5201 {
5202 if (dextUniqueID != NULL) {
5203 char *s_buffer = NULL;
5204 unsigned int d_length = dextUniqueID->getLength();
5205 /*
5206 * We are converting in hex, so for every byte we will have
5207 * 2 hex chars and one last \0.
5208 */
5209 unsigned int s_length = d_length * 2 + 1;
5210 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5211
5212 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5213 int cpos = 0;
5214 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5215 int ret = snprintf(s_buffer + cpos, s_length - cpos - 1, "%02X", uid[i]);
5216 if (ret <= 0) {
5217 break;
5218 }
5219 cpos += ret;
5220 }
5221 *size = s_length;
5222
5223 return s_buffer;
5224 }
5225
5226 return NULL;
5227 }
5228
5229 /*
5230 * Atomically swaps the olddext with newdext.
5231 * olddext will be unloaded, so it might be freed
5232 * after this call unless it was previously retained.
5233 *
5234 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5235 */
5236 void
replaceDextInternal(OSKext * olddext,OSKext * newdext)5237 OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5238 {
5239 OSReturn result;
5240 const OSSymbol * dextID = olddext->getIdentifier();
5241 OSSharedPtr<OSArray> new_personalities;
5242 OSSharedPtr<OSString> kextIdentifier;
5243 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5244 assert(lock_held);
5245
5246 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5247 dextID->retain();
5248
5249 if (newdext != NULL) {
5250 __assert_only bool eq = dextID->isEqualTo(newdext->getIdentifier());
5251 assert(eq);
5252 }
5253
5254 if (newdext != NULL) {
5255 /*
5256 * Swap the catalog personalities.
5257 */
5258 new_personalities = newdext->copyPersonalitiesArray();
5259 olddext->updatePersonalitiesInCatalog(new_personalities.get());
5260 }
5261
5262 /*
5263 * Unload the dext.
5264 */
5265 result = olddext->unload();
5266 if (result != kOSReturnSuccess) {
5267 OSKextLog(NULL,
5268 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5269 "Cannot unload dext for upgrade %s: %d\n",
5270 dextID->getCStringNoCopy(), result);
5271 }
5272
5273 if (newdext != NULL) {
5274 /*
5275 * Swap the dexts on the OSKext dictionary.
5276 * This might free the dext.
5277 */
5278 sKextsByID->setObject(dextID, newdext);
5279 } else {
5280 /*
5281 * Remove the old dext
5282 */
5283 removeKext(olddext, true);
5284 }
5285
5286 /*
5287 * Inform userspace.
5288 */
5289 if (newdext != NULL) {
5290 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), newdext->getDextUniqueID());
5291 if (result != kOSReturnSuccess) {
5292 OSKextLog(NULL,
5293 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5294 "Cannot send upgrade notification for %s\n",
5295 dextID->getCStringNoCopy());
5296 }
5297 } else {
5298 // notify dext removal
5299 queueKextNotification(kKextRequestPredicateUnloadNotification, OSDynamicCast(OSString, dextID));
5300 }
5301
5302 OSSafeReleaseNULL(dextID);
5303 }
5304
5305 /*
5306 * To be called with sKextLock held.
5307 * NOTE: this could unload the olddext.
5308 */
5309 bool
upgradeDext(OSKext * olddext,OSKext * newdext)5310 OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5311 {
5312 const char * dextIDCS = newdext->getIdentifierCString();
5313 __assert_only bool old_isDext = olddext->isDriverKit();
5314 __assert_only bool new_isDext = newdext->isDriverKit();
5315 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5316
5317 assert(old_isDext && new_isDext);
5318 assert(lock_held);
5319
5320 /*
5321 * New dext and old dext have the same ID.
5322 * We use this ID as key on the OSKext
5323 * dictionarys/arrays.
5324 */
5325 const OSSymbol * dextID = newdext->getIdentifier();
5326 __assert_only bool eq = dextID->isEqualTo(olddext->getIdentifier());
5327 assert(eq);
5328
5329 /*
5330 * Set this OSKect as to update.
5331 * Note that this flags will never be removed once set.
5332 * When a OSKext is marked, it will be substitued by a new
5333 * OSKext, and every subsystem having a reference on this
5334 * OSKext need to know they have check if they can use
5335 * this OSKext or look for a new one.
5336 */
5337 olddext->flags.dextToReplace = 1;
5338
5339 /*
5340 * Check if the current OSKext has any
5341 * userspace processes launched.
5342 * In this case we cannot upgrade and we have to
5343 * delay the upgrade until all processes
5344 * are done.
5345 */
5346 if (olddext->dextLaunchedCount == 0) {
5347 /*
5348 * Be sure that if there are no launched dexts, no
5349 * pending upgrades exist.
5350 * This is an error if it happens, as the decrement
5351 * should have removed the dext from sDriverKitToUpgradeByID
5352 * in case it reached 0.
5353 */
5354 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(dextID);
5355 if (pending_upgdare != NULL) {
5356 OSKextLog(NULL,
5357 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5358 "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5359 dextIDCS);
5360 goto out;
5361 }
5362
5363 replaceDextInternal(olddext, newdext);
5364 return true;
5365 }
5366
5367 out:
5368
5369 /*
5370 * Delay the upgrade.
5371 * Make the new dext available in sDriverKitToUpgradeByID.
5372 * In case there was already a pending upgrade, this will
5373 * overwrite it.
5374 */
5375 sDriverKitToUpgradeByID->setObject(dextID, newdext);
5376 return false;
5377 }
5378
5379 /*
5380 * To be called with sKextLock held.
5381 * NOTE: this could unload the dext.
5382 */
5383 bool
removeDext(OSKext * dext)5384 OSKext::removeDext(OSKext *dext)
5385 {
5386 __assert_only bool dext_isDext = dext->isDriverKit();
5387 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5388 IOReturn result;
5389
5390 assert(dext_isDext);
5391 assert(lock_held);
5392
5393 /*
5394 * Set this OSKext to be unloaded when all running instances exit.
5395 */
5396 dext->flags.dextToReplace = 1;
5397
5398 result = gIOCatalogue->terminateDriversForModule(
5399 dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5400 if (result != kOSReturnSuccess) {
5401 OSKextLog(dext,
5402 kOSKextLogErrorLevel |
5403 kOSKextLogKextBookkeepingFlag,
5404 "%s services failed to terminate - 0x%x.",
5405 dext->getIdentifierCString(), result);
5406 }
5407
5408 dext->removePersonalitiesFromCatalog();
5409 sDriverKitToUpgradeByID->removeObject(dext->getIdentifier());
5410
5411 /*
5412 * Check if the current OSKext has any
5413 * userspace processes launched.
5414 * In this case we cannot unload and we have to
5415 * delay the unload until all processes
5416 * are done.
5417 */
5418 if (dext->dextLaunchedCount == 0) {
5419 replaceDextInternal(dext, NULL);
5420 return true;
5421 }
5422
5423 return false;
5424 }
5425
5426 bool
incrementDextLaunchCount(OSKext * dext,OSData * dextUniqueIDToMatch)5427 OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5428 {
5429 bool ret = false;
5430 __assert_only bool isDext = dext->isDriverKit();
5431 assert(isDext);
5432
5433 const char * dextIDCS = dext->getIdentifierCString();
5434 OSData *myDextUniqueID = dext->getDextUniqueID();
5435
5436 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5437 OSKextLog(dext,
5438 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5439 "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5440 dextIDCS);
5441 return ret;
5442 }
5443
5444 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5445 const char *dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5446 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueIDToMatch, &dextUniqueIDToMatchCStringSize);
5447 assert(dextUniqueIDCString != NULL);
5448 assert(dextUniqueIDToMatchCString != NULL);
5449
5450 IORecursiveLockLock(sKextLock);
5451
5452 /*
5453 * Check that the dext we are referencing is the same
5454 * looked for the match.
5455 */
5456 if (myDextUniqueID->isEqualTo(dextUniqueIDToMatch)) {
5457 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5458 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5459 OSKextLog(dext,
5460 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5461 "Too many dexts launched for %s UniqueID %s\n",
5462 dextIDCS, dextUniqueIDCString);
5463 } else {
5464 dext->dextLaunchedCount++;
5465 ret = true;
5466
5467 OSKextLog(dext,
5468 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5469 "New dext launched for %s UniqueID %s",
5470 dextIDCS, dextUniqueIDCString);
5471 }
5472 } else {
5473 OSKextLog(dext,
5474 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5475 "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5476 dextIDCS, dextUniqueIDCString);
5477 }
5478 } else {
5479 OSKextLog(dext,
5480 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5481 "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5482 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5483 }
5484
5485 IORecursiveLockUnlock(sKextLock);
5486
5487 if (dextUniqueIDCString != NULL) {
5488 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5489 }
5490 if (dextUniqueIDToMatchCString != NULL) {
5491 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5492 }
5493 return ret;
5494 }
5495
5496 bool
decrementDextLaunchCount(OSString * bundleID)5497 OSKext::decrementDextLaunchCount(OSString *bundleID)
5498 {
5499 bool ret = false;
5500 const char * dextIDCS;
5501 OSData *myDextUniqueID;
5502 unsigned int dextUniqueIDCStringSize = 0;
5503 const char * dextUniqueIDCString = NULL;
5504 OSKext* dext = NULL;
5505
5506 if (!bundleID) {
5507 return ret;
5508 }
5509 dextIDCS = bundleID->getCStringNoCopy();
5510
5511 IORecursiveLockLock(sKextLock);
5512
5513 /*
5514 * Look for the dext with the bundle it. This
5515 * call is triggered only if a previous increment was
5516 * performed. It means that the dext could have not
5517 * been upgraded as its dextLaunchedCount was at least 1.
5518 * Because of this it still needs to be available
5519 * in sKextsByID.
5520 */
5521 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5522 if (!dext || !dext->isDriverKit()) {
5523 OSKextLog(NULL,
5524 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5525 "Cannot find dext for %s, cannot decrement dext launches\n",
5526 dextIDCS);
5527
5528 goto out_locked;
5529 }
5530
5531 myDextUniqueID = dext->getDextUniqueID();
5532 if (!myDextUniqueID) {
5533 OSKextLog(dext,
5534 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5535 "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5536 dextIDCS);
5537
5538 goto out_locked;
5539 }
5540 dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5541 assert(dextUniqueIDCString != NULL);
5542
5543 if (dext->dextLaunchedCount == 0) {
5544 OSKextLog(dext,
5545 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5546 "Over decrementing dext launch for %s UniqueID %s\n",
5547 dextIDCS, dextUniqueIDCString);
5548
5549 goto out_locked;
5550 }
5551
5552 dext->dextLaunchedCount--;
5553
5554 OSKextLog(dext,
5555 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5556 "Dext terminated for %s UniqueID %s",
5557 dextIDCS, dextUniqueIDCString);
5558
5559 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5560 /*
5561 * Find the upgraded dext.
5562 */
5563 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5564 if (newdext) {
5565 OSKextLog(dext,
5566 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5567 "Dext upgrade for %s UniqueID %s",
5568 dextIDCS, dextUniqueIDCString);
5569 replaceDextInternal(dext, newdext);
5570 /* NOTE dext could have been freed past this point */
5571
5572 sDriverKitToUpgradeByID->removeObject(dextIDCS);
5573 } else {
5574 OSKextLog(dext,
5575 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5576 "Dext unload for %s UniqueID %s",
5577 dextIDCS, dextUniqueIDCString);
5578 replaceDextInternal(dext, NULL);
5579 }
5580
5581 ret = true;
5582 }
5583 out_locked:
5584 IORecursiveLockUnlock(sKextLock);
5585
5586 if (dextUniqueIDCString != NULL) {
5587 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5588 }
5589
5590 return ret;
5591 }
5592
5593 /*********************************************************************
5594 *********************************************************************/
5595 #if defined (__arm__)
5596 #include <arm/arch.h>
5597 #endif
5598
5599 #if defined (__x86_64__)
5600 #define ARCHNAME "x86_64"
5601 #elif defined (__arm64__)
5602 #define ARCHNAME "arm64"
5603 #elif defined (__arm__)
5604
5605 #if defined (__ARM_ARCH_7S__)
5606 #define ARCHNAME "armv7s"
5607 #elif defined (__ARM_ARCH_7F__)
5608 #define ARCHNAME "armv7f"
5609 #elif defined (__ARM_ARCH_7K__)
5610 #define ARCHNAME "armv7k"
5611 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5612 #define ARCHNAME "armv7"
5613 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5614 #define ARCHNAME "armv6"
5615 #endif
5616
5617 #elif defined (__arm64__)
5618 #define ARCHNAME "arm64"
5619 #else
5620 #error architecture not supported
5621 #endif
5622
5623 #define ARCH_SEPARATOR_CHAR '_'
5624
5625 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)5626 makeHostArchKey(const char * key, size_t * keySizeOut)
5627 {
5628 char * result = NULL;
5629 size_t keyLength = strlen(key);
5630 size_t keySize;
5631
5632 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5633 */
5634 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5635 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5636
5637 if (!result) {
5638 goto finish;
5639 }
5640 strlcpy(result, key, keySize);
5641 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5642 result[keyLength] = '\0';
5643 strlcat(result, ARCHNAME, keySize);
5644 *keySizeOut = keySize;
5645
5646 finish:
5647 return result;
5648 }
5649
5650 /*********************************************************************
5651 *********************************************************************/
5652 OSObject *
getPropertyForHostArch(const char * key)5653 OSKext::getPropertyForHostArch(const char * key)
5654 {
5655 OSObject * result = NULL;// do not release
5656 size_t hostArchKeySize = 0;
5657 char * hostArchKey = NULL;// must kfree
5658
5659 if (!key || !infoDict) {
5660 goto finish;
5661 }
5662
5663 /* Some properties are not allowed to be arch-variant:
5664 * - Any CFBundle... property.
5665 * - OSBundleIsInterface.
5666 * - OSKernelResource.
5667 */
5668 if (STRING_HAS_PREFIX(key, "OS") ||
5669 STRING_HAS_PREFIX(key, "IO")) {
5670 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
5671 if (!hostArchKey) {
5672 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5673 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5674 "Allocation failure.");
5675 goto finish;
5676 }
5677 result = infoDict->getObject(hostArchKey);
5678 }
5679
5680 if (!result) {
5681 result = infoDict->getObject(key);
5682 }
5683
5684 finish:
5685 if (hostArchKey) {
5686 kfree_data(hostArchKey, hostArchKeySize);
5687 }
5688 return result;
5689 }
5690
5691 #if PRAGMA_MARK
5692 #pragma mark Load/Start/Stop/Unload
5693 #endif
5694
5695 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5696
5697 /*********************************************************************
5698 * sExcludeListByID is a dictionary with keys / values of:
5699 * key = bundleID string of kext we will not allow to load
5700 * value = version string(s) of the kext that is to be denied loading.
5701 * The version strings can be comma delimited. For example if kext
5702 * com.foocompany.fookext has two versions that we want to deny
5703 * loading then the version strings might look like:
5704 * 1.0.0, 1.0.1
5705 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5706 * not load the kext.
5707 *
5708 * Value may also be in the form of "LE 2.0.0" (version numbers
5709 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5710 * number less than 2.0.0 will not load)
5711 *
5712 * NOTE - we cannot use the characters "<=" or "<" because we have code
5713 * that serializes plists and treats '<' as a special character.
5714 *********************************************************************/
5715 bool
isInExcludeList(void)5716 OSKext::isInExcludeList(void)
5717 {
5718 OSString * versionString = NULL; // do not release
5719 char * versionCString = NULL; // do not free
5720 size_t i;
5721 boolean_t wantLessThan = false;
5722 boolean_t wantLessThanEqualTo = false;
5723 boolean_t isInExcludeList = true;
5724 char myBuffer[32];
5725
5726 IORecursiveLockLock(sKextLock);
5727
5728 if (!sExcludeListByID) {
5729 isInExcludeList = false;
5730 } else {
5731 /* look up by bundleID in our exclude list and if found get version
5732 * string (or strings) that we will not allow to load
5733 */
5734 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5735 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5736 isInExcludeList = false;
5737 }
5738 }
5739
5740 IORecursiveLockUnlock(sKextLock);
5741
5742 if (!isInExcludeList) {
5743 return false;
5744 }
5745
5746 /* parse version strings */
5747 versionCString = (char *) versionString->getCStringNoCopy();
5748
5749 /* look for "LT" or "LE" form of version string, must be in first two
5750 * positions.
5751 */
5752 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5753 wantLessThan = true;
5754 versionCString += 2;
5755 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5756 wantLessThanEqualTo = true;
5757 versionCString += 2;
5758 }
5759
5760 for (i = 0; *versionCString != 0x00; versionCString++) {
5761 /* skip whitespace */
5762 if (isWhiteSpace(*versionCString)) {
5763 continue;
5764 }
5765
5766 /* peek ahead for version string separator or null terminator */
5767 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5768 /* OK, we have a version string */
5769 myBuffer[i++] = *versionCString;
5770 myBuffer[i] = 0x00;
5771
5772 OSKextVersion excludeVers;
5773 excludeVers = OSKextParseVersionString(myBuffer);
5774
5775 if (wantLessThanEqualTo) {
5776 if (version <= excludeVers) {
5777 return true;
5778 }
5779 } else if (wantLessThan) {
5780 if (version < excludeVers) {
5781 return true;
5782 }
5783 } else if (version == excludeVers) {
5784 return true;
5785 }
5786
5787 /* reset for the next (if any) version string */
5788 i = 0;
5789 wantLessThan = false;
5790 wantLessThanEqualTo = false;
5791 } else {
5792 /* save valid version character */
5793 myBuffer[i++] = *versionCString;
5794
5795 /* make sure bogus version string doesn't overrun local buffer */
5796 if (i >= sizeof(myBuffer)) {
5797 break;
5798 }
5799 }
5800 }
5801
5802 return false;
5803 }
5804
5805 /*********************************************************************
5806 * sNonLoadableKextsByID is a dictionary with keys / values of:
5807 * key = bundleID string of kext we will not allow to load
5808 * value = boolean (true == loadable, false == not loadable)
5809 *
5810 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5811 * i.e., the value for the kext's bundleID will be false. All kexts in
5812 * the primary and system KCs will always be marked as "loadable."
5813 *
5814 * This list ultimately comes from kexts which have been uninstalled
5815 * in user space by deleting the kext from disk, but which have not
5816 * yet been removed from the AuxKC. Because the user could choose to
5817 * re-install the exact same version of the kext, we need to keep
5818 * a dictionary of boolean values so that user space only needs to
5819 * keep a simple list of "uninstalled" or "missing" bundles. When
5820 * a bundle is re-installed, the iokit daemon can use the
5821 * AucKCBundleAvailable predicate to set the individual kext's
5822 * availability to true.
5823 *********************************************************************/
5824 bool
isLoadable(void)5825 OSKext::isLoadable(void)
5826 {
5827 bool isLoadable = true;
5828
5829 if (kc_type != KCKindAuxiliary) {
5830 /* this filtering only applies to kexts in the auxkc */
5831 return true;
5832 }
5833
5834 IORecursiveLockLock(sKextLock);
5835
5836 if (sNonLoadableKextsByID) {
5837 /* look up by bundleID in our exclude list and if found get version
5838 * string (or strings) that we will not allow to load
5839 */
5840 OSBoolean *loadableVal;
5841 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5842 if (loadableVal && !loadableVal->getValue()) {
5843 isLoadable = false;
5844 }
5845 }
5846 IORecursiveLockUnlock(sKextLock);
5847
5848 return isLoadable;
5849 }
5850
5851 /*********************************************************************
5852 *********************************************************************/
5853 /* static */
5854 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5855 OSKext::loadKextWithIdentifier(
5856 const char * kextIdentifierCString,
5857 Boolean allowDeferFlag,
5858 Boolean delayAutounloadFlag,
5859 OSKextExcludeLevel startOpt,
5860 OSKextExcludeLevel startMatchingOpt,
5861 OSArray * personalityNames)
5862 {
5863 OSReturn result = kOSReturnError;
5864 OSSharedPtr<OSString> kextIdentifier;
5865
5866 kextIdentifier = OSString::withCString(kextIdentifierCString);
5867 if (!kextIdentifier) {
5868 result = kOSKextReturnNoMemory;
5869 goto finish;
5870 }
5871 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5872 NULL /* kextRef */,
5873 allowDeferFlag, delayAutounloadFlag,
5874 startOpt, startMatchingOpt, personalityNames);
5875
5876 finish:
5877 return result;
5878 }
5879
5880 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5881 OSKext::loadKextWithIdentifier(
5882 OSString * kextIdentifier,
5883 OSSharedPtr<OSObject> &kextRef,
5884 Boolean allowDeferFlag,
5885 Boolean delayAutounloadFlag,
5886 OSKextExcludeLevel startOpt,
5887 OSKextExcludeLevel startMatchingOpt,
5888 OSArray * personalityNames)
5889 {
5890 OSObject * kextRefRaw = NULL;
5891 OSReturn result;
5892
5893 result = loadKextWithIdentifier(kextIdentifier,
5894 &kextRefRaw,
5895 allowDeferFlag,
5896 delayAutounloadFlag,
5897 startOpt,
5898 startMatchingOpt,
5899 personalityNames);
5900 if ((kOSReturnSuccess == result) && kextRefRaw) {
5901 kextRef.reset(kextRefRaw, OSNoRetain);
5902 }
5903 return result;
5904 }
5905
5906 /*********************************************************************
5907 *********************************************************************/
5908 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5909 OSKext::loadKextWithIdentifier(
5910 OSString * kextIdentifier,
5911 OSObject ** kextRef,
5912 Boolean allowDeferFlag,
5913 Boolean delayAutounloadFlag,
5914 OSKextExcludeLevel startOpt,
5915 OSKextExcludeLevel startMatchingOpt,
5916 OSArray * personalityNames)
5917 {
5918 OSReturn result = kOSReturnError;
5919 OSReturn pingResult = kOSReturnError;
5920 OSKext * theKext = NULL; // do not release
5921 OSSharedPtr<OSDictionary> loadRequest;
5922 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5923
5924 if (kextRef) {
5925 *kextRef = NULL;
5926 }
5927
5928 IORecursiveLockLock(sKextLock);
5929
5930 if (!kextIdentifier) {
5931 result = kOSKextReturnInvalidArgument;
5932 goto finish;
5933 }
5934
5935 OSKext::recordIdentifierRequest(kextIdentifier);
5936
5937 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5938 if (!theKext) {
5939 if (!allowDeferFlag) {
5940 OSKextLog(/* kext */ NULL,
5941 kOSKextLogErrorLevel |
5942 kOSKextLogLoadFlag,
5943 "Can't load kext %s - not found.",
5944 kextIdentifier->getCStringNoCopy());
5945 goto finish;
5946 }
5947
5948 if (!sKernelRequestsEnabled) {
5949 OSKextLog(theKext,
5950 kOSKextLogErrorLevel |
5951 kOSKextLogLoadFlag,
5952 "Can't load kext %s - requests to user space are disabled.",
5953 kextIdentifier->getCStringNoCopy());
5954 result = kOSKextReturnDisabled;
5955 goto finish;
5956 }
5957
5958 /* Create a new request unless one is already sitting
5959 * in sKernelRequests for this bundle identifier
5960 */
5961 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5962 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5963 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5964 loadRequest);
5965 if (result != kOSReturnSuccess) {
5966 goto finish;
5967 }
5968 if (!_OSKextSetRequestArgument(loadRequest.get(),
5969 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5970 result = kOSKextReturnNoMemory;
5971 goto finish;
5972 }
5973 if (!sKernelRequests->setObject(loadRequest.get())) {
5974 result = kOSKextReturnNoMemory;
5975 goto finish;
5976 }
5977
5978 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5979 result = kOSKextReturnNoMemory;
5980 goto finish;
5981 }
5982
5983 OSKextLog(theKext,
5984 kOSKextLogDebugLevel |
5985 kOSKextLogLoadFlag,
5986 "Kext %s not found; queued load request to user space.",
5987 kextIdentifier->getCStringNoCopy());
5988 }
5989
5990 pingResult = OSKext::pingIOKitDaemon();
5991 if (pingResult == kOSKextReturnDisabled) {
5992 OSKextLog(/* kext */ NULL,
5993 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5994 kOSKextLogLoadFlag,
5995 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5996 kextIdentifier->getCStringNoCopy());
5997 }
5998
5999 result = kOSKextReturnDeferred;
6000 goto finish;
6001 }
6002
6003 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
6004
6005 if (result != kOSReturnSuccess) {
6006 OSKextLog(theKext,
6007 kOSKextLogErrorLevel |
6008 kOSKextLogLoadFlag,
6009 "Failed to load kext %s (error 0x%x).",
6010 kextIdentifier->getCStringNoCopy(), (int)result);
6011
6012 if (theKext->kc_type == KCKindUnknown) {
6013 OSKext::removeKext(theKext,
6014 /* terminateService/removePersonalities */ true);
6015 }
6016 goto finish;
6017 }
6018
6019 if (delayAutounloadFlag) {
6020 OSKextLog(theKext,
6021 kOSKextLogProgressLevel |
6022 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6023 "Setting delayed autounload for %s.",
6024 kextIdentifier->getCStringNoCopy());
6025 theKext->flags.delayAutounload = 1;
6026 }
6027
6028 finish:
6029 if ((kOSReturnSuccess == result) && kextRef) {
6030 *kextRef = theKext;
6031 theKext->matchingRefCount++;
6032 theKext->retain();
6033 }
6034
6035 IORecursiveLockUnlock(sKextLock);
6036
6037 return result;
6038 }
6039
6040 /*********************************************************************
6041 *********************************************************************/
6042 /* static */
6043 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)6044 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
6045 {
6046 OSReturn result = kOSReturnError;
6047
6048 OSBoolean *delayAutounloadBool = NULL; // do not release
6049 OSNumber *startKextExcludeNum = NULL; // do not release
6050 OSNumber *startMatchingExcludeNum = NULL; // do not release
6051 OSArray *personalityNames = NULL; // do not release
6052
6053 /*
6054 * Default values for these options:
6055 * regular autounload behavior
6056 * start the kext
6057 * send all personalities to the catalog
6058 */
6059 Boolean delayAutounload = false;
6060 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
6061 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
6062
6063 IORecursiveLockLock(sKextLock);
6064
6065 OSKextLog(/* kext */ NULL,
6066 kOSKextLogDebugLevel |
6067 kOSKextLogIPCFlag,
6068 "Received kext KC load request from user space.");
6069
6070 /* Regardless of processing, the fact that we have gotten here means some
6071 * user-space program is up and talking to us, so we'll switch our kext
6072 * registration to reflect that.
6073 */
6074 if (!sUserLoadsActive) {
6075 OSKextLog(/* kext */ NULL,
6076 kOSKextLogProgressLevel |
6077 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6078 "Switching to late startup (user-space) kext loading policy.");
6079 sUserLoadsActive = true;
6080 }
6081
6082 delayAutounloadBool = OSDynamicCast(OSBoolean,
6083 _OSKextGetRequestArgument(requestDict,
6084 kKextRequestArgumentDelayAutounloadKey));
6085 startKextExcludeNum = OSDynamicCast(OSNumber,
6086 _OSKextGetRequestArgument(requestDict,
6087 kKextRequestArgumentStartExcludeKey));
6088 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6089 _OSKextGetRequestArgument(requestDict,
6090 kKextRequestArgumentStartMatchingExcludeKey));
6091 personalityNames = OSDynamicCast(OSArray,
6092 _OSKextGetRequestArgument(requestDict,
6093 kKextRequestArgumentPersonalityNamesKey));
6094
6095 if (delayAutounloadBool) {
6096 delayAutounload = delayAutounloadBool->getValue();
6097 }
6098 if (startKextExcludeNum) {
6099 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6100 }
6101 if (startMatchingExcludeNum) {
6102 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6103 }
6104
6105 OSKextLog(/* kext */ NULL,
6106 kOSKextLogProgressLevel |
6107 kOSKextLogIPCFlag,
6108 "Received request from user space to load KC kext %s.",
6109 theKext->getIdentifierCString());
6110
6111 /* this could be in the Auxiliary KC, so record the load request */
6112 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6113
6114 /*
6115 * Load the kext
6116 */
6117 result = theKext->load(startKextExcludeLevel,
6118 startMatchingExcludeLevel, personalityNames);
6119
6120 if (result != kOSReturnSuccess) {
6121 OSKextLog(theKext,
6122 kOSKextLogErrorLevel |
6123 kOSKextLogLoadFlag,
6124 "Failed to load kext %s (error 0x%x).",
6125 theKext->getIdentifierCString(), (int)result);
6126
6127 OSKext::removeKext(theKext,
6128 /* terminateService/removePersonalities */ true);
6129 goto finish;
6130 } else {
6131 OSKextLog(theKext,
6132 kOSKextLogProgressLevel |
6133 kOSKextLogLoadFlag,
6134 "Kext %s Loaded successfully from %s KC",
6135 theKext->getIdentifierCString(), theKext->getKCTypeString());
6136 }
6137
6138 if (delayAutounload) {
6139 OSKextLog(theKext,
6140 kOSKextLogProgressLevel |
6141 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6142 "Setting delayed autounload for %s.",
6143 theKext->getIdentifierCString());
6144 theKext->flags.delayAutounload = 1;
6145 }
6146
6147 finish:
6148 IORecursiveLockUnlock(sKextLock);
6149
6150 return result;
6151 }
6152
6153 /*********************************************************************
6154 *********************************************************************/
6155 /* static */
6156 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)6157 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6158 {
6159 OSReturn result = kOSReturnError;
6160 OSDictionary *anInfoDict = NULL; // do not release
6161
6162 anInfoDict = OSDynamicCast(OSDictionary,
6163 _OSKextGetRequestArgument(requestDict,
6164 kKextRequestArgumentCodelessInfoKey));
6165 if (anInfoDict == NULL) {
6166 OSKextLog(/* kext */ NULL,
6167 kOSKextLogErrorLevel |
6168 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6169 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6170 kextIdentifier->getCStringNoCopy());
6171 return kOSKextReturnInvalidArgument;
6172 }
6173
6174 IORecursiveLockLock(sKextLock);
6175
6176 OSKextLog(/* kext */ NULL,
6177 kOSKextLogProgressLevel |
6178 kOSKextLogIPCFlag,
6179 "Received request from user space to load codeless kext %s.",
6180 kextIdentifier->getCStringNoCopy());
6181
6182 {
6183 // instantiate a new kext, and don't hold a reference
6184 // (the kext subsystem will hold one implicitly)
6185 OSKextInitResult ret;
6186 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, &ret);
6187 if (!newKext) {
6188 /*
6189 * We might have failed to create a new OSKext
6190 * because the old one should still be used.
6191 * Check if that is the case.
6192 */
6193 if (ret != kOSKextInitFailure) {
6194 result = kOSReturnSuccess;
6195 goto finish;
6196 }
6197 OSKextLog(/* kext */ NULL,
6198 kOSKextLogErrorLevel |
6199 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6200 "Could not instantiate codeless kext.");
6201 result = kOSKextReturnNotLoadable;
6202 goto finish;
6203 }
6204 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
6205 OSKextLog(/* kext */ NULL,
6206 kOSKextLogErrorLevel |
6207 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6208 "Codeless kext identifiers don't match '%s' != '%s'",
6209 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6210
6211 OSKext::removeKext(newKext.get(), false);
6212 result = kOSKextReturnInvalidArgument;
6213 goto finish;
6214 }
6215
6216 /* Record the request for the codeless kext */
6217 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6218
6219 result = kOSReturnSuccess;
6220 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6221 result = newKext->sendPersonalitiesToCatalog(true, NULL);
6222 }
6223
6224 finish:
6225 IORecursiveLockUnlock(sKextLock);
6226
6227 return result;
6228 }
6229
6230 /*********************************************************************
6231 *********************************************************************/
6232 /* static */
6233 void
dropMatchingReferences(OSSet * kexts)6234 OSKext::dropMatchingReferences(
6235 OSSet * kexts)
6236 {
6237 IORecursiveLockLock(sKextLock);
6238 kexts->iterateObjects(^bool (OSObject * obj) {
6239 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6240 if (!thisKext) {
6241 return false;
6242 }
6243 thisKext->matchingRefCount--;
6244 return false;
6245 });
6246 IORecursiveLockUnlock(sKextLock);
6247 }
6248
6249 /*********************************************************************
6250 *********************************************************************/
6251 /* static */
6252 void
recordIdentifierRequest(OSString * kextIdentifier)6253 OSKext::recordIdentifierRequest(
6254 OSString * kextIdentifier)
6255 {
6256 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6257 bool fail = false;
6258
6259 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6260 goto finish;
6261 }
6262
6263 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6264 if (!kextIdentifierSymbol) {
6265 // xxx - this is really a basic alloc failure
6266 fail = true;
6267 goto finish;
6268 }
6269
6270 IORecursiveLockLock(sKextLock);
6271 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6272 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6273 fail = true;
6274 } else {
6275 // xxx - need to find a way to associate this whole func w/the kext
6276 OSKextLog(/* kext */ NULL,
6277 // xxx - check level
6278 kOSKextLogStepLevel |
6279 kOSKextLogArchiveFlag,
6280 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6281 kextIdentifier->getCStringNoCopy());
6282 }
6283 }
6284 IORecursiveLockUnlock(sKextLock);
6285
6286 finish:
6287
6288 if (fail) {
6289 OSKextLog(/* kext */ NULL,
6290 kOSKextLogErrorLevel |
6291 kOSKextLogArchiveFlag,
6292 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6293 kextIdentifier->getCStringNoCopy());
6294 }
6295 return;
6296 }
6297
6298 /*********************************************************************
6299 *********************************************************************/
6300 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6301 OSKext::load(
6302 OSKextExcludeLevel startOpt,
6303 OSKextExcludeLevel startMatchingOpt,
6304 OSArray * personalityNames)
6305 {
6306 OSReturn result = kOSReturnError;
6307 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6308 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6309 unsigned int i, count;
6310 Boolean alreadyLoaded = false;
6311 OSKext * lastLoadedKext = NULL; // do not release
6312
6313 if (isInExcludeList()) {
6314 OSKextLog(this,
6315 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6316 kOSKextLogLoadFlag,
6317 "Kext %s is in exclude list, not loadable",
6318 getIdentifierCString());
6319
6320 result = kOSKextReturnNotLoadable;
6321 goto finish;
6322 }
6323 if (!isLoadable()) {
6324 OSKextLog(this,
6325 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6326 kOSKextLogLoadFlag,
6327 "Kext %s is not loadable",
6328 getIdentifierCString());
6329
6330 result = kOSKextReturnNotLoadable;
6331 goto finish;
6332 }
6333
6334 if (isLoaded()) {
6335 alreadyLoaded = true;
6336 result = kOSReturnSuccess;
6337
6338 OSKextLog(this,
6339 kOSKextLogDebugLevel |
6340 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6341 "Kext %s is already loaded.",
6342 getIdentifierCString());
6343 goto loaded;
6344 }
6345
6346 #if CONFIG_MACF
6347 /*
6348 * On kxld and on embedded, only call into the MAC hook when on a
6349 * user thread, for access control over userspace kextloads.
6350 *
6351 * On non-kxld systems, additionally check the MAC hook for kexts in
6352 * the Pageable and Aux KCs, regardless of whether we are on a user
6353 * thread or not. This means on Apple silicon devices that the MAC
6354 * hook will only be useful to block 3rd party kexts loaded via
6355 * matching, and any kexts loaded from userspace kextloads.
6356 *
6357 * Note that this should _not_ be called on kexts loaded from the
6358 * kernel bootstrap thread as the kernel proc's cred struct is not
6359 * yet initialized! This won't happen on macOS because all the kexts
6360 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6361 */
6362 if (current_task() != kernel_task
6363 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6364 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6365 #endif
6366 ) {
6367 int macCheckResult = 0;
6368 kauth_cred_t cred = NULL;
6369
6370 cred = kauth_cred_get_with_ref();
6371 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
6372 kauth_cred_unref(&cred);
6373
6374 if (macCheckResult != 0) {
6375 result = kOSReturnError;
6376 OSKextLog(this,
6377 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6378 "Failed to load kext %s (MAC policy error 0x%x).",
6379 getIdentifierCString(), macCheckResult);
6380 goto finish;
6381 }
6382 }
6383 #endif /* CONFIG_MACF */
6384
6385 if (!sLoadEnabled) {
6386 OSKextLog(this,
6387 kOSKextLogErrorLevel |
6388 kOSKextLogLoadFlag,
6389 "Kext loading is disabled (attempt to load kext %s).",
6390 getIdentifierCString());
6391 result = kOSKextReturnDisabled;
6392 goto finish;
6393 }
6394
6395 /* If we've pushed the next available load tag to the invalid value,
6396 * we can't load any more kexts.
6397 */
6398 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6399 OSKextLog(this,
6400 kOSKextLogErrorLevel |
6401 kOSKextLogLoadFlag,
6402 "Can't load kext %s - no more load tags to assign.",
6403 getIdentifierCString());
6404 result = kOSKextReturnNoResources;
6405 goto finish;
6406 }
6407
6408 /* This is a bit of a hack, because we shouldn't be handling
6409 * personalities within the load function.
6410 */
6411 if (!declaresExecutable()) {
6412 /* There is a special case where a non-executable kext can be loaded: the
6413 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6414 * load its metadata into the global data structures, if appropriate
6415 */
6416 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6417 boolean_t updated = updateExcludeList(infoDict.get());
6418 if (updated) {
6419 OSKextLog(this,
6420 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6421 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6422 }
6423 }
6424
6425 if (isDriverKit()) {
6426 if (loadTag == 0) {
6427 sLoadedDriverKitKexts->setObject(this);
6428 loadTag = sNextLoadTag++;
6429 }
6430 }
6431 result = kOSReturnSuccess;
6432 goto loaded;
6433 }
6434
6435 /* Are we in safe boot?
6436 */
6437 if (sSafeBoot && !isLoadableInSafeBoot()) {
6438 OSKextLog(this,
6439 kOSKextLogErrorLevel |
6440 kOSKextLogLoadFlag,
6441 "Can't load kext %s - not loadable during safe boot.",
6442 getIdentifierCString());
6443 result = kOSKextReturnBootLevel;
6444 goto finish;
6445 }
6446
6447 OSKextLog(this,
6448 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6449 "Loading kext %s.",
6450 getIdentifierCString());
6451
6452 #if !VM_MAPPED_KEXTS
6453 if (isPrelinked() == false) {
6454 OSKextLog(this,
6455 kOSKextLogErrorLevel |
6456 kOSKextLogLoadFlag,
6457 "Can't load kext %s - not in a kext collection.",
6458 getIdentifierCString());
6459 result = kOSKextReturnDisabled;
6460 goto finish;
6461 }
6462 #endif /* defined(__x86_64__) */
6463
6464 #if CONFIG_KXLD
6465 if (!sKxldContext) {
6466 kern_return_t kxldResult;
6467 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6468 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6469 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6470 if (kxldResult) {
6471 OSKextLog(this,
6472 kOSKextLogErrorLevel |
6473 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6474 "Can't load kext %s - failed to create link context.",
6475 getIdentifierCString());
6476 result = kOSKextReturnNoMemory;
6477 goto finish;
6478 }
6479 }
6480 #endif // CONFIG_KXLD
6481
6482 /* We only need to resolve dependencies once for the whole graph, but
6483 * resolveDependencies will just return if there's no work to do, so it's
6484 * safe to call it more than once.
6485 */
6486 if (!resolveDependencies()) {
6487 // xxx - check resolveDependencies() for log msg
6488 OSKextLog(this,
6489 kOSKextLogErrorLevel |
6490 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6491 "Can't load kext %s - failed to resolve library dependencies.",
6492 getIdentifierCString());
6493 result = kOSKextReturnDependencies;
6494 goto finish;
6495 }
6496
6497 /* If we are excluding just the kext being loaded now (and not its
6498 * dependencies), drop the exclusion level to none so dependencies
6499 * start and/or add their personalities.
6500 */
6501 if (dependenciesStartOpt == kOSKextExcludeKext) {
6502 dependenciesStartOpt = kOSKextExcludeNone;
6503 }
6504
6505 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6506 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6507 }
6508
6509 /* Load the dependencies, recursively.
6510 */
6511 count = getNumDependencies();
6512 for (i = 0; i < count; i++) {
6513 OSKext * dependency = OSDynamicCast(OSKext,
6514 dependencies->getObject(i));
6515 if (dependency == NULL) {
6516 OSKextLog(this,
6517 kOSKextLogErrorLevel |
6518 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6519 "Internal error loading kext %s; dependency disappeared.",
6520 getIdentifierCString());
6521 result = kOSKextReturnInternalError;
6522 goto finish;
6523 }
6524
6525 /* Dependencies must be started accorting to the opt,
6526 * but not given the personality names of the main kext.
6527 */
6528 result = dependency->load(dependenciesStartOpt,
6529 dependenciesStartMatchingOpt,
6530 /* personalityNames */ NULL);
6531 if (result != KERN_SUCCESS) {
6532 OSKextLog(this,
6533 kOSKextLogErrorLevel |
6534 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6535 "Dependency %s of kext %s failed to load.",
6536 dependency->getIdentifierCString(),
6537 getIdentifierCString());
6538
6539 OSKext::removeKext(dependency,
6540 /* terminateService/removePersonalities */ true);
6541 result = kOSKextReturnDependencyLoadError;
6542
6543 goto finish;
6544 }
6545 }
6546
6547 result = loadExecutable();
6548 if (result != KERN_SUCCESS) {
6549 goto finish;
6550 }
6551
6552 pendingPgoHead.next = &pendingPgoHead;
6553 pendingPgoHead.prev = &pendingPgoHead;
6554
6555 // The kernel PRNG is not initialized when the first kext is
6556 // loaded, so use early random
6557 uuid_generate_early_random(instance_uuid);
6558 account = IOMallocType(OSKextAccount);
6559
6560 account->loadTag = kmod_info->id;
6561 account->site.refcount = 0;
6562 account->site.flags = VM_TAG_KMOD;
6563
6564 #if DEVELOPMENT || DEBUG
6565 /* Setup the task reference group. */
6566 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6567 "task_%s", getIdentifierCString());
6568 account->task_refgrp.grp_name = account->task_refgrp_name;
6569 account->task_refgrp.grp_parent = &task_external_refgrp;
6570 account->task_refgrp.grp_flags = OS_REFGRP_F_ALWAYS_ENABLED;
6571 os_ref_log_init(&account->task_refgrp);
6572 #endif /* DEVELOPMENT || DEBUG */
6573
6574 account->kext = this;
6575 if (gIOSurfaceIdentifier == bundleID) {
6576 vm_tag_alloc(&account->site);
6577 gIOSurfaceTag = account->site.tag;
6578 }
6579
6580 flags.loaded = true;
6581
6582 /* Add the kext to the list of loaded kexts and update the kmod_info
6583 * struct to point to that of the last loaded kext (which is the way
6584 * it's always been done, though I'd rather do them in order now).
6585 */
6586 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6587 sLoadedKexts->setObject(this);
6588
6589 /* Keep the kernel itself out of the kmod list.
6590 */
6591 if (lastLoadedKext->isKernel()) {
6592 lastLoadedKext = NULL;
6593 }
6594
6595 if (lastLoadedKext) {
6596 kmod_info->next = lastLoadedKext->kmod_info;
6597 }
6598
6599 notifyKextLoadObservers(this, kmod_info);
6600
6601 /* Make the global kmod list point at the just-loaded kext. Note that the
6602 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6603 * although we do report it in kextstat these days by using the newer
6604 * OSArray of loaded kexts, which does contain it.
6605 *
6606 * (The OSKext object representing the kernel doesn't even have a kmod_info
6607 * struct, though I suppose we could stick a pointer to it from the
6608 * static struct in OSRuntime.cpp.)
6609 */
6610 kmod = kmod_info;
6611
6612 /* Save the list of loaded kexts in case we panic.
6613 */
6614 OSKext::saveLoadedKextPanicList();
6615
6616 if (isExecutable()) {
6617 OSKext::updateLoadedKextSummaries();
6618 savePanicString(/* isLoading */ true);
6619
6620 #if CONFIG_DTRACE
6621 registerWithDTrace();
6622 #else
6623 jettisonLinkeditSegment();
6624 #endif /* CONFIG_DTRACE */
6625
6626 #if !VM_MAPPED_KEXTS
6627 /* If there is a page (or more) worth of padding after the end
6628 * of the last data section but before the end of the data segment
6629 * then free it in the same manner the LinkeditSegment is freed
6630 */
6631 jettisonDATASegmentPadding();
6632 #endif
6633 }
6634
6635 loaded:
6636 if (isExecutable() && !flags.started) {
6637 if (startOpt == kOSKextExcludeNone) {
6638 result = start();
6639 if (result != kOSReturnSuccess) {
6640 OSKextLog(this,
6641 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6642 "Kext %s start failed (result 0x%x).",
6643 getIdentifierCString(), result);
6644 result = kOSKextReturnStartStopError;
6645 }
6646 }
6647 }
6648
6649 /* If not excluding matching, send the personalities to the kernel.
6650 * This never affects the result of the load operation.
6651 * This is a bit of a hack, because we shouldn't be handling
6652 * personalities within the load function.
6653 */
6654 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6655 result = sendPersonalitiesToCatalog(true, personalityNames);
6656 }
6657
6658 finish:
6659
6660 if (result != kOSReturnSuccess) {
6661 OSKextLog(this,
6662 kOSKextLogErrorLevel |
6663 kOSKextLogLoadFlag,
6664 "Kext %s failed to load (0x%x).",
6665 getIdentifierCString(), (int)result);
6666 } else if (!alreadyLoaded) {
6667 OSKextLog(this,
6668 kOSKextLogProgressLevel |
6669 kOSKextLogLoadFlag,
6670 "Kext %s loaded.",
6671 getIdentifierCString());
6672
6673 queueKextNotification(kKextRequestPredicateLoadNotification,
6674 OSDynamicCast(OSString, bundleID.get()));
6675 }
6676 return result;
6677 }
6678
6679 #if CONFIG_KXLD
6680 /*********************************************************************
6681 *
6682 *********************************************************************/
6683 static char *
strdup(const char * string)6684 strdup(const char * string)
6685 {
6686 char * result = NULL;
6687 size_t size;
6688
6689 if (!string) {
6690 goto finish;
6691 }
6692
6693 size = 1 + strlen(string);
6694 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6695 if (!result) {
6696 goto finish;
6697 }
6698
6699 memcpy(result, string, size);
6700
6701 finish:
6702 return result;
6703 }
6704 #endif // CONFIG_KXLD
6705
6706 /*********************************************************************
6707 *
6708 *********************************************************************/
6709
6710 kernel_section_t *
lookupSection(const char * segname,const char * secname)6711 OSKext::lookupSection(const char *segname, const char *secname)
6712 {
6713 kernel_section_t * found_section = NULL;
6714 kernel_mach_header_t * mh = NULL;
6715 kernel_segment_command_t * seg = NULL;
6716 kernel_section_t * sec = NULL;
6717
6718 if (!linkedExecutable) {
6719 return NULL;
6720 }
6721
6722 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6723
6724 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6725 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
6726 continue;
6727 }
6728
6729 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6730 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
6731 found_section = sec;
6732 goto out;
6733 }
6734 }
6735 }
6736
6737 out:
6738 return found_section;
6739 }
6740
6741 /*********************************************************************
6742 *
6743 *********************************************************************/
6744
6745 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6746 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6747 {
6748 OSReturn result = kOSKextReturnBadData;
6749 kernel_mach_header_t * mh = NULL;
6750 kernel_segment_command_t * seg = NULL;
6751 kernel_segment_command_t * linkeditSeg = NULL;
6752 kernel_section_t * sec = NULL;
6753 char * linkeditBase = NULL;
6754 bool haveLinkeditBase = false;
6755 char * relocBase = NULL;
6756 bool haveRelocBase = false;
6757 struct dysymtab_command * dysymtab = NULL;
6758 struct linkedit_data_command * segmentSplitInfo = NULL;
6759 struct symtab_command * symtab = NULL;
6760 kernel_nlist_t * sym = NULL;
6761 struct relocation_info * reloc = NULL;
6762 uint32_t i = 0;
6763 int reloc_size;
6764 vm_offset_t new_kextsize;
6765 kc_format format = KCFormatUnknown;
6766
6767 if (linkedExecutable == NULL || flags.builtin) {
6768 result = kOSReturnSuccess;
6769 goto finish;
6770 }
6771
6772 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6773 if (kernel_mach_header_is_in_fileset(mh)) {
6774 // kexts in filesets are slid as part of collection sliding
6775 result = kOSReturnSuccess;
6776 goto finish;
6777 }
6778
6779 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6780
6781 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6782 if (!seg->vmaddr) {
6783 continue;
6784 }
6785
6786 seg->vmaddr = ml_static_slide(seg->vmaddr);
6787
6788 #if KASLR_KEXT_DEBUG
6789 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6790 seg->segname,
6791 (unsigned long)ml_static_unslide(seg->vmaddr),
6792 (unsigned long)seg->vmaddr);
6793 #endif
6794
6795 if (!haveRelocBase) {
6796 relocBase = (char *) seg->vmaddr;
6797 haveRelocBase = true;
6798 }
6799 if (!strcmp(seg->segname, "__LINKEDIT")) {
6800 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6801 haveLinkeditBase = true;
6802 linkeditSeg = seg;
6803 }
6804 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6805 sec->addr = ml_static_slide(sec->addr);
6806
6807 #if KASLR_KEXT_DEBUG
6808 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6809 sec->sectname,
6810 (unsigned long)ml_static_unslide(sec->addr),
6811 (unsigned long)sec->addr);
6812 #endif
6813 }
6814 }
6815
6816 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6817
6818 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6819
6820 if (symtab != NULL && doCoalescedSlides == false) {
6821 /* Some pseudo-kexts have symbol tables without segments.
6822 * Ignore them. */
6823 if (symtab->nsyms > 0 && haveLinkeditBase) {
6824 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6825 for (i = 0; i < symtab->nsyms; i++) {
6826 if (sym[i].n_type & N_STAB) {
6827 continue;
6828 }
6829 sym[i].n_value = ml_static_slide(sym[i].n_value);
6830
6831 #if KASLR_KEXT_DEBUG
6832 #define MAX_SYMS_TO_LOG 5
6833 if (i < MAX_SYMS_TO_LOG) {
6834 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6835 (unsigned long)ml_static_unslide(sym[i].n_value),
6836 (unsigned long)sym[i].n_value);
6837 }
6838 #endif
6839 }
6840 }
6841 }
6842
6843 if (dysymtab != NULL && doCoalescedSlides == false) {
6844 if (dysymtab->nextrel > 0) {
6845 OSKextLog(this,
6846 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6847 kOSKextLogLinkFlag,
6848 "Sliding kext %s: External relocations found.",
6849 getIdentifierCString());
6850 goto finish;
6851 }
6852
6853 if (dysymtab->nlocrel > 0) {
6854 if (!haveLinkeditBase) {
6855 OSKextLog(this,
6856 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6857 kOSKextLogLinkFlag,
6858 "Sliding kext %s: No linkedit segment.",
6859 getIdentifierCString());
6860 goto finish;
6861 }
6862
6863 if (!haveRelocBase) {
6864 OSKextLog(this,
6865 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6866 kOSKextLogLinkFlag,
6867 #if __x86_64__
6868 "Sliding kext %s: No writable segments.",
6869 #else
6870 "Sliding kext %s: No segments.",
6871 #endif
6872 getIdentifierCString());
6873 goto finish;
6874 }
6875
6876 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6877 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6878
6879 for (i = 0; i < dysymtab->nlocrel; i++) {
6880 if (reloc[i].r_extern != 0
6881 || reloc[i].r_type != 0
6882 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6883 ) {
6884 OSKextLog(this,
6885 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6886 kOSKextLogLinkFlag,
6887 "Sliding kext %s: Unexpected relocation found.",
6888 getIdentifierCString());
6889 goto finish;
6890 }
6891 if (reloc[i].r_pcrel != 0) {
6892 continue;
6893 }
6894 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6895 *relocAddr = ml_static_slide(*relocAddr);
6896
6897 #if KASLR_KEXT_DEBUG
6898 #define MAX_DYSYMS_TO_LOG 5
6899 if (i < MAX_DYSYMS_TO_LOG) {
6900 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6901 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6902 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6903 }
6904 #endif
6905 }
6906
6907 /* We should free these relocations, not just delete the reference to them.
6908 * <rdar://problem/10535549> Free relocations from PIE kexts.
6909 *
6910 * For now, we do not free LINKEDIT for kexts with split segments.
6911 */
6912 new_kextsize = round_page(kmod_info->size - reloc_size);
6913 if (new_kextsize > UINT_MAX) {
6914 OSKextLog(this,
6915 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6916 kOSKextLogLinkFlag,
6917 "Kext %s: new kext size is too large.",
6918 getIdentifierCString());
6919 goto finish;
6920 }
6921 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6922 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6923 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6924 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6925 size_t bytes_remaining = endofkext - endofrelocInfo;
6926 OSSharedPtr<OSData> new_osdata;
6927
6928 /* fix up symbol offsets if they are after the dsymtab local relocs */
6929 if (symtab) {
6930 if (dysymtab->locreloff < symtab->symoff) {
6931 symtab->symoff -= reloc_size;
6932 }
6933 if (dysymtab->locreloff < symtab->stroff) {
6934 symtab->stroff -= reloc_size;
6935 }
6936 }
6937 if (dysymtab->locreloff < dysymtab->extreloff) {
6938 dysymtab->extreloff -= reloc_size;
6939 }
6940
6941 /* move data behind reloc info down to new offset */
6942 if (endofrelocInfo < endofkext) {
6943 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6944 }
6945
6946 /* Create a new OSData for the smaller kext object and reflect
6947 * new linkedit segment size.
6948 */
6949 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6950 linkeditSeg->filesize = linkeditSeg->vmsize;
6951
6952 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6953 if (new_osdata) {
6954 /* Fix up kmod info and linkedExecutable.
6955 */
6956 kmod_info->size = new_kextsize;
6957 /*
6958 * Fileset KCs are mapped as a whole by iBoot.
6959 * Individual kext executables should not be unmapped
6960 * by xnu.
6961 * Doing so may result in panics like rdar://85419651
6962 */
6963 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
6964 new_osdata->setDeallocFunction(NULL);
6965 } else { // Not from a Fileset KC
6966 #if VM_MAPPED_KEXTS
6967 new_osdata->setDeallocFunction(osdata_kext_free);
6968 #else
6969 new_osdata->setDeallocFunction(osdata_phys_free);
6970 #endif
6971 }
6972 linkedExecutable->setDeallocFunction(NULL);
6973 linkedExecutable = os::move(new_osdata);
6974
6975 #if VM_MAPPED_KEXTS
6976 kext_free(new_endofkext, (endofkext - new_endofkext));
6977 #else
6978 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6979 #endif
6980 }
6981 }
6982 dysymtab->nlocrel = 0;
6983 dysymtab->locreloff = 0;
6984 }
6985 }
6986
6987 result = kOSReturnSuccess;
6988 finish:
6989 return result;
6990 }
6991
6992 /*********************************************************************
6993 * called only by load()
6994 *********************************************************************/
6995 OSReturn
loadExecutable()6996 OSKext::loadExecutable()
6997 {
6998 OSReturn result = kOSReturnError;
6999 OSSharedPtr<OSArray> linkDependencies;
7000 uint32_t num_kmod_refs = 0;
7001 OSData * theExecutable = NULL; // do not release
7002 OSString * versString = NULL; // do not release
7003 const char * versCString = NULL; // do not free
7004 const char * string = NULL; // do not free
7005
7006 #if CONFIG_KXLD
7007 unsigned int i;
7008 uint32_t numDirectDependencies = 0;
7009 kern_return_t kxldResult;
7010 KXLDDependency * kxlddeps = NULL; // must kfree
7011 uint32_t num_kxlddeps = 0;
7012 struct mach_header ** kxldHeaderPtr = NULL; // do not free
7013 struct mach_header * kxld_header = NULL; // xxx - need to free here?
7014 #endif // CONFIG_KXLD
7015
7016 /* We need the version string for a variety of bits below.
7017 */
7018 versString = OSDynamicCast(OSString,
7019 getPropertyForHostArch(kCFBundleVersionKey));
7020 if (!versString) {
7021 goto finish;
7022 }
7023 versCString = versString->getCStringNoCopy();
7024
7025 if (isKernelComponent()) {
7026 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
7027 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
7028 OSKextLog(this,
7029 kOSKextLogErrorLevel |
7030 kOSKextLogLoadFlag,
7031 "Kernel component %s has incorrect version %s; "
7032 "expected %s.",
7033 getIdentifierCString(),
7034 versCString, KERNEL6_VERSION);
7035 result = kOSKextReturnInternalError;
7036 goto finish;
7037 } else if (strcmp(versCString, osrelease)) {
7038 OSKextLog(this,
7039 kOSKextLogErrorLevel |
7040 kOSKextLogLoadFlag,
7041 "Kernel component %s has incorrect version %s; "
7042 "expected %s.",
7043 getIdentifierCString(),
7044 versCString, osrelease);
7045 result = kOSKextReturnInternalError;
7046 goto finish;
7047 }
7048 }
7049 }
7050
7051 #if defined(__x86_64__) || defined(__i386__)
7052 if (flags.resetSegmentsFromVnode) {
7053 /* Fixup the chains and slide the mach headers */
7054 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
7055
7056 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
7057 result = kOSKextReturnValidation;
7058 goto finish;
7059 }
7060 }
7061 #endif //(__x86_64__) || defined(__i386__)
7062
7063 if (isPrelinked()) {
7064 goto register_kmod;
7065 }
7066
7067 /* <rdar://problem/21444003> all callers must be entitled */
7068 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7069 OSKextLog(this,
7070 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7071 "Not entitled to link kext '%s'",
7072 getIdentifierCString());
7073 result = kOSKextReturnNotPrivileged;
7074 goto finish;
7075 }
7076
7077 theExecutable = getExecutable();
7078 if (!theExecutable) {
7079 if (declaresExecutable()) {
7080 OSKextLog(this,
7081 kOSKextLogErrorLevel |
7082 kOSKextLogLoadFlag,
7083 "Can't load kext %s - executable is missing.",
7084 getIdentifierCString());
7085 result = kOSKextReturnValidation;
7086 goto finish;
7087 }
7088 goto register_kmod;
7089 }
7090
7091 if (isInterface()) {
7092 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
7093 if (executableCopy) {
7094 setLinkedExecutable(executableCopy.get());
7095 }
7096 goto register_kmod;
7097 }
7098
7099 #if CONFIG_KXLD
7100 numDirectDependencies = getNumDependencies();
7101
7102 if (flags.hasBleedthrough) {
7103 linkDependencies = dependencies;
7104 } else {
7105 linkDependencies = OSArray::withArray(dependencies.get());
7106 if (!linkDependencies) {
7107 OSKextLog(this,
7108 kOSKextLogErrorLevel |
7109 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7110 "Can't allocate link dependencies to load kext %s.",
7111 getIdentifierCString());
7112 goto finish;
7113 }
7114
7115 for (i = 0; i < numDirectDependencies; ++i) {
7116 OSKext * dependencyKext = OSDynamicCast(OSKext,
7117 dependencies->getObject(i));
7118 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7119 }
7120 }
7121
7122 num_kxlddeps = linkDependencies->getCount();
7123 if (!num_kxlddeps) {
7124 OSKextLog(this,
7125 kOSKextLogErrorLevel |
7126 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7127 "Can't load kext %s - it has no library dependencies.",
7128 getIdentifierCString());
7129 goto finish;
7130 }
7131
7132 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7133 if (!kxlddeps) {
7134 OSKextLog(this,
7135 kOSKextLogErrorLevel |
7136 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7137 "Can't allocate link context to load kext %s.",
7138 getIdentifierCString());
7139 goto finish;
7140 }
7141 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7142
7143 for (i = 0; i < num_kxlddeps; ++i) {
7144 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7145
7146 if (dependency->isInterface()) {
7147 OSKext *interfaceTargetKext = NULL; //do not release
7148 OSData * interfaceTarget = NULL; //do not release
7149
7150 if (dependency->isKernelComponent()) {
7151 interfaceTargetKext = sKernelKext;
7152 interfaceTarget = sKernelKext->linkedExecutable.get();
7153 } else {
7154 interfaceTargetKext = OSDynamicCast(OSKext,
7155 dependency->dependencies->getObject(0));
7156
7157 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7158 }
7159
7160 if (!interfaceTarget) {
7161 // panic?
7162 goto finish;
7163 }
7164
7165 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7166 * it will be useful to have them in the debugger.
7167 * strdup() failing isn't critical right here so we don't check that.
7168 */
7169 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7170 kxlddeps[i].kext_size = interfaceTarget->getLength();
7171 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7172
7173 if (dependency->linkedExecutable != NULL) {
7174 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7175 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7176 } else {
7177 kxlddeps[i].interface = (u_char *) NULL;
7178 kxlddeps[i].interface_size = 0;
7179 }
7180 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7181 } else {
7182 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7183 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7184 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7185 }
7186
7187 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7188 }
7189
7190 kxldHeaderPtr = &kxld_header;
7191
7192 #if DEBUG
7193 OSKextLog(this,
7194 kOSKextLogExplicitLevel |
7195 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7196 "Kext %s - calling kxld_link_file:\n"
7197 " kxld_context: %p\n"
7198 " executable: %p executable_length: %d\n"
7199 " user_data: %p\n"
7200 " kxld_dependencies: %p num_dependencies: %d\n"
7201 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7202 getIdentifierCString(), sKxldContext,
7203 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7204 this, kxlddeps, num_kxlddeps,
7205 kxldHeaderPtr, &kmod_info);
7206 #endif
7207
7208 /* After this call, the linkedExecutable instance variable
7209 * should exist.
7210 */
7211 kxldResult = kxld_link_file(sKxldContext,
7212 (u_char *)theExecutable->getBytesNoCopy(),
7213 theExecutable->getLength(),
7214 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7215 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7216
7217 if (kxldResult != KERN_SUCCESS) {
7218 // xxx - add kxldResult here?
7219 OSKextLog(this,
7220 kOSKextLogErrorLevel |
7221 kOSKextLogLoadFlag,
7222 "Can't load kext %s - link failed.",
7223 getIdentifierCString());
7224 result = kOSKextReturnLinkError;
7225 goto finish;
7226 }
7227
7228 /* We've written data & instructions into kernel memory, so flush the data
7229 * cache and invalidate the instruction cache.
7230 * I/D caches are coherent on x86
7231 */
7232 #if !defined(__i386__) && !defined(__x86_64__)
7233 flush_dcache(kmod_info->address, kmod_info->size, false);
7234 invalidate_icache(kmod_info->address, kmod_info->size, false);
7235 #endif
7236
7237 #else // !CONFIG_KXLD
7238 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7239 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7240 result = kOSKextReturnLinkError;
7241 goto finish;
7242 #endif // CONFIG_KXLD
7243
7244 register_kmod:
7245
7246 if (isInterface()) {
7247 /* Whip up a fake kmod_info entry for the interface kext.
7248 */
7249 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7250 if (!kmod_info) {
7251 result = KERN_MEMORY_ERROR;
7252 goto finish;
7253 }
7254
7255 /* A pseudokext has almost nothing in its kmod_info struct.
7256 */
7257 kmod_info->info_version = KMOD_INFO_VERSION;
7258
7259 /* An interface kext doesn't have a linkedExecutable, so save a
7260 * copy of the UUID out of the original executable via copyUUID()
7261 * while we still have the original executable.
7262 */
7263 interfaceUUID = copyUUID();
7264 }
7265
7266 kmod_info->id = loadTag = sNextLoadTag++;
7267 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7268
7269 /* Stamp the bundle ID and version from the OSKext over anything
7270 * resident inside the kmod_info.
7271 */
7272 string = getIdentifierCString();
7273 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
7274
7275 string = versCString;
7276 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
7277
7278 /* Add the dependencies' kmod_info structs as kmod_references.
7279 */
7280 num_kmod_refs = getNumDependencies();
7281 if (num_kmod_refs) {
7282 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7283 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7284 if (!kmod_info->reference_list) {
7285 result = KERN_MEMORY_ERROR;
7286 goto finish;
7287 }
7288 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7289 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7290 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7291 ref->info = refKext->kmod_info;
7292 ref->info->reference_count++;
7293
7294 if (refIndex + 1 < num_kmod_refs) {
7295 ref->next = kmod_info->reference_list + refIndex + 1;
7296 }
7297 }
7298 }
7299
7300 if (kmod_info->hdr_size > UINT32_MAX) {
7301 OSKextLog(this,
7302 kOSKextLogErrorLevel |
7303 kOSKextLogLoadFlag,
7304 #if __LP64__
7305 "Kext %s header size is too large (%lu > UINT32_MAX).",
7306 #else
7307 "Kext %s header size is too large (%u > UINT32_MAX).",
7308 #endif
7309 kmod_info->name,
7310 kmod_info->hdr_size);
7311 result = KERN_FAILURE;
7312 goto finish;
7313 }
7314
7315 if (kmod_info->size > UINT32_MAX) {
7316 OSKextLog(this,
7317 kOSKextLogErrorLevel |
7318 kOSKextLogLoadFlag,
7319 #if __LP64__
7320 "Kext %s size is too large (%lu > UINT32_MAX).",
7321 #else
7322 "Kext %s size is too large (%u > UINT32_MAX).",
7323 #endif
7324 kmod_info->name,
7325 kmod_info->size);
7326 result = KERN_FAILURE;
7327 goto finish;
7328 }
7329
7330 if (!isInterface() && linkedExecutable) {
7331 OSKextLog(this,
7332 kOSKextLogProgressLevel |
7333 kOSKextLogLoadFlag,
7334 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7335 kmod_info->name,
7336 (unsigned)kmod_info->size / PAGE_SIZE,
7337 (unsigned long)ml_static_unslide(kmod_info->address),
7338 (unsigned)kmod_info->id);
7339 }
7340
7341 /* VM protections and wiring for the Aux KC are done at collection loading time */
7342 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7343 /* if prelinked and primary KC, VM protections are already set */
7344 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
7345 if (result != KERN_SUCCESS) {
7346 goto finish;
7347 }
7348 }
7349
7350 #if KASAN
7351 if (linkedExecutable) {
7352 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7353 linkedExecutable->getLength(), getIdentifierCString());
7354 }
7355 #else
7356 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7357 OSKextLog(this,
7358 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7359 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7360 getIdentifierCString()
7361 );
7362 result = KERN_FAILURE;
7363 goto finish;
7364 }
7365 #endif
7366
7367 result = kOSReturnSuccess;
7368
7369 finish:
7370
7371 #if CONFIG_KXLD
7372 /* Clear up locally allocated dependency info.
7373 */
7374 for (i = 0; i < num_kxlddeps; ++i) {
7375 size_t size;
7376
7377 if (kxlddeps[i].kext_name) {
7378 size = 1 + strlen(kxlddeps[i].kext_name);
7379 kfree_data(kxlddeps[i].kext_name, size);
7380 }
7381 if (kxlddeps[i].interface_name) {
7382 size = 1 + strlen(kxlddeps[i].interface_name);
7383 kfree_data(kxlddeps[i].interface_name, size);
7384 }
7385 }
7386 if (kxlddeps) {
7387 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7388 }
7389 #endif // CONFIG_KXLD
7390
7391 /* We no longer need the unrelocated executable (which the linker
7392 * has altered anyhow).
7393 */
7394 setExecutable(NULL);
7395
7396 if (result != kOSReturnSuccess) {
7397 OSKextLog(this,
7398 kOSKextLogErrorLevel |
7399 kOSKextLogLoadFlag,
7400 "Failed to load executable for kext %s.",
7401 getIdentifierCString());
7402
7403 if (kmod_info && kmod_info->reference_list) {
7404 kfree_type(kmod_reference_t, num_kmod_refs,
7405 kmod_info->reference_list);
7406 }
7407 if (isInterface()) {
7408 kfree_type(kmod_info_t, kmod_info);
7409 kmod_info = NULL;
7410 }
7411 if (kc_type == KCKindUnknown) {
7412 kmod_info = NULL;
7413 if (linkedExecutable) {
7414 linkedExecutable.reset();
7415 }
7416 }
7417 }
7418
7419 return result;
7420 }
7421
7422 /* static */
7423 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)7424 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7425 {
7426 kernel_segment_command_t *linkeditseg = NULL;
7427
7428 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
7429 if (linkeditseg == NULL) {
7430 panic("FileSet booted with no Linkedit segment");
7431 }
7432
7433 #if VM_MAPPED_KEXTS
7434 /* BootKC on x86_64 is not vm mapped */
7435 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7436
7437 OSKextLog(/* kext */ NULL,
7438 kOSKextLogProgressLevel |
7439 kOSKextLogGeneralFlag,
7440 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7441 linkeditseg->vmaddr, linkeditseg->vmsize);
7442 #else
7443 /* BootKC on arm64 is not vm mapped, but is slid */
7444 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7445
7446 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7447
7448 OSKextLog(/* kext */ NULL,
7449 kOSKextLogProgressLevel |
7450 kOSKextLogGeneralFlag,
7451 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7452 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7453 #endif /* VM_MAPPED_KEXTS */
7454 }
7455
7456 /*********************************************************************
7457 * The linkedit segment is used by the kext linker for dependency
7458 * resolution, and by dtrace for probe initialization. We can free it
7459 * for non-library kexts, since no kexts depend on non-library kexts
7460 * by definition, once dtrace has been initialized.
7461 *********************************************************************/
7462 void
jettisonLinkeditSegment(void)7463 OSKext::jettisonLinkeditSegment(void)
7464 {
7465 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7466 kernel_segment_command_t * linkedit = NULL;
7467 vm_offset_t start;
7468 vm_size_t linkeditsize, kextsize;
7469 OSSharedPtr<OSData> data;
7470 kc_format format = KCFormatUnknown;
7471
7472 if (isInFileset()) {
7473 return;
7474 }
7475
7476 #if NO_KEXTD
7477 /* We can free symbol tables for all embedded kexts because we don't
7478 * support runtime kext linking.
7479 */
7480 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7481 #else
7482 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7483 #endif
7484 goto finish;
7485 }
7486
7487 /* Find the linkedit segment. If it's not the last segment, then freeing
7488 * it will fragment the kext into multiple VM regions, which OSKext is not
7489 * designed to handle, so we'll have to skip it.
7490 */
7491 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
7492 if (!linkedit) {
7493 goto finish;
7494 }
7495
7496 if (round_page(kmod_info->address + kmod_info->size) !=
7497 round_page(linkedit->vmaddr + linkedit->vmsize)) {
7498 goto finish;
7499 }
7500
7501 /* Create a new OSData for the smaller kext object.
7502 */
7503 linkeditsize = round_page(linkedit->vmsize);
7504 kextsize = kmod_info->size - linkeditsize;
7505 start = linkedit->vmaddr;
7506
7507 if (kextsize > UINT_MAX) {
7508 goto finish;
7509 }
7510 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
7511 if (!data) {
7512 goto finish;
7513 }
7514
7515 /* Fix the kmod info and linkedExecutable.
7516 */
7517 kmod_info->size = kextsize;
7518
7519 /*
7520 * Fileset KCs are mapped as a whole by iBoot.
7521 * Individual kext executables should not be unmapped by xnu
7522 * Doing so may result in panics like rdar://85419651
7523 */
7524 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7525 data->setDeallocFunction(NULL);
7526 } else { // Not from a Fileset KC
7527 #if VM_MAPPED_KEXTS
7528 data->setDeallocFunction(osdata_kext_free);
7529 #else
7530 data->setDeallocFunction(osdata_phys_free);
7531 #endif
7532 }
7533 linkedExecutable->setDeallocFunction(NULL);
7534 linkedExecutable = os::move(data);
7535 flags.jettisonLinkeditSeg = 1;
7536
7537 /* Free the linkedit segment.
7538 */
7539 #if VM_MAPPED_KEXTS
7540 kext_free(start, linkeditsize);
7541 #else
7542 ml_static_mfree(start, linkeditsize);
7543 #endif
7544
7545 finish:
7546 return;
7547 }
7548
7549 /*********************************************************************
7550 * If there are whole pages that are unused betweem the last section
7551 * of the DATA segment and the end of the DATA segment then we can free
7552 * them
7553 *********************************************************************/
7554 void
7555 OSKext::jettisonDATASegmentPadding(void)
7556 {
7557 kernel_mach_header_t * mh;
7558 kernel_segment_command_t * dataSeg;
7559 kernel_section_t * sec, * lastSec;
7560 vm_offset_t dataSegEnd, lastSecEnd;
7561 vm_size_t padSize;
7562
7563 if (flags.builtin) {
7564 return;
7565 }
7566 mh = (kernel_mach_header_t *)kmod_info->address;
7567
7568 if (isInFileset()) {
7569 return;
7570 }
7571
7572 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
7573 if (dataSeg == NULL) {
7574 return;
7575 }
7576
7577 lastSec = NULL;
7578 sec = firstsect(dataSeg);
7579 while (sec != NULL) {
7580 lastSec = sec;
7581 sec = nextsect(dataSeg, sec);
7582 }
7583
7584 if (lastSec == NULL) {
7585 return;
7586 }
7587
7588 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
7589 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
7590 return;
7591 }
7592
7593 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7594 lastSecEnd = round_page(lastSec->addr + lastSec->size);
7595
7596 if (dataSegEnd <= lastSecEnd) {
7597 return;
7598 }
7599
7600 padSize = dataSegEnd - lastSecEnd;
7601
7602 if (padSize >= PAGE_SIZE) {
7603 #if VM_MAPPED_KEXTS
7604 kext_free(lastSecEnd, padSize);
7605 #else
7606 ml_static_mfree(lastSecEnd, padSize);
7607 #endif
7608 }
7609 }
7610
7611 /*********************************************************************
7612 *********************************************************************/
7613 void
7614 OSKext::setLinkedExecutable(OSData * anExecutable)
7615 {
7616 if (linkedExecutable) {
7617 panic("Attempt to set linked executable on kext "
7618 "that already has one (%s).\n",
7619 getIdentifierCString());
7620 }
7621 linkedExecutable.reset(anExecutable, OSRetain);
7622 return;
7623 }
7624
7625 #if CONFIG_DTRACE
7626 /*********************************************************************
7627 * Go through all loaded kexts and tell them to register with dtrace.
7628 * The instance method only registers if necessary.
7629 *********************************************************************/
7630 /* static */
7631 void
7632 OSKext::registerKextsWithDTrace(void)
7633 {
7634 uint32_t count = sLoadedKexts->getCount();
7635 uint32_t i;
7636
7637 IORecursiveLockLock(sKextLock);
7638
7639 for (i = 0; i < count; i++) {
7640 OSKext * thisKext = NULL; // do not release
7641
7642 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7643 if (!thisKext || !thisKext->isExecutable()) {
7644 continue;
7645 }
7646
7647 thisKext->registerWithDTrace();
7648 }
7649
7650 IORecursiveLockUnlock(sKextLock);
7651
7652 return;
7653 }
7654
7655 extern "C" {
7656 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7657 extern int (*dtrace_modunload)(struct kmod_info *);
7658 };
7659
7660 /*********************************************************************
7661 *********************************************************************/
7662 void
7663 OSKext::registerWithDTrace(void)
7664 {
7665 /* Register kext with dtrace. A dtrace_modload failure should not
7666 * prevent a kext from loading, so we ignore the return code.
7667 */
7668 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7669 uint32_t modflag = 0;
7670 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
7671
7672 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7673 if (forceInit == kOSBooleanTrue) {
7674 OSKextLog(this,
7675 kOSKextLogBasicLevel |
7676 kOSKextLogGeneralFlag,
7677 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7678 getIdentifierCString());
7679 forceInit = kOSBooleanFalse;
7680 }
7681 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7682 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7683 }
7684
7685 if (forceInit == kOSBooleanTrue) {
7686 modflag |= KMOD_DTRACE_FORCE_INIT;
7687 }
7688 if (flags.builtin) {
7689 modflag |= KMOD_DTRACE_STATIC_KEXT;
7690 }
7691
7692 (void)(*dtrace_modload)(kmod_info, modflag);
7693 flags.dtraceInitialized = true;
7694 jettisonLinkeditSegment();
7695 }
7696 return;
7697 }
7698 /*********************************************************************
7699 *********************************************************************/
7700 void
7701 OSKext::unregisterWithDTrace(void)
7702 {
7703 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7704 * prevent a kext from loading, so we ignore the return code.
7705 */
7706 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7707 (void)(*dtrace_modunload)(kmod_info);
7708 flags.dtraceInitialized = false;
7709 }
7710 return;
7711 }
7712 #endif /* CONFIG_DTRACE */
7713
7714
7715 /*********************************************************************
7716 * called only by loadExecutable()
7717 *********************************************************************/
7718 #if !VM_MAPPED_KEXTS
7719 #if defined(__arm__) || defined(__arm64__)
7720 static inline kern_return_t
7721 OSKext_protect(
7722 kernel_mach_header_t *kext_mh,
7723 vm_map_t map,
7724 vm_map_offset_t start,
7725 vm_map_offset_t end,
7726 vm_prot_t new_prot,
7727 boolean_t set_max,
7728 kc_kind_t kc_type)
7729 {
7730 #pragma unused(kext_mh,map,kc_type)
7731 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7732 assert(start <= end);
7733 if (start >= end) {
7734 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7735 } else if (set_max) {
7736 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7737 } else {
7738 return ml_static_protect(start, end - start, new_prot);
7739 }
7740 }
7741
7742 static inline kern_return_t
7743 OSKext_wire(
7744 kernel_mach_header_t *kext_mh,
7745 vm_map_t map,
7746 vm_map_offset_t start,
7747 vm_map_offset_t end,
7748 vm_prot_t access_type,
7749 boolean_t user_wire,
7750 kc_kind_t kc_type)
7751 {
7752 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7753 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7754 }
7755 #else
7756 #error Unrecognized architecture
7757 #endif
7758 #else
7759 static inline kern_return_t
7760 OSKext_protect(
7761 kernel_mach_header_t *kext_mh,
7762 vm_map_t map,
7763 vm_map_offset_t start,
7764 vm_map_offset_t end,
7765 vm_prot_t new_prot,
7766 boolean_t set_max,
7767 kc_kind_t kc_type)
7768 {
7769 if (start == end) { // 10538581
7770 return KERN_SUCCESS;
7771 }
7772 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7773 /*
7774 * XXX: This will probably need to be different for AuxKC and
7775 * pageableKC!
7776 */
7777 return ml_static_protect(start, end - start, new_prot);
7778 }
7779 return vm_map_protect(map, start, end, new_prot, set_max);
7780 }
7781
7782 static inline kern_return_t
7783 OSKext_wire(
7784 kernel_mach_header_t *kext_mh,
7785 vm_map_t map,
7786 vm_map_offset_t start,
7787 vm_map_offset_t end,
7788 vm_prot_t access_type,
7789 boolean_t user_wire,
7790 kc_kind_t kc_type)
7791 {
7792 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7793 /* TODO: we may need to hook this for the pageableKC */
7794 return KERN_SUCCESS;
7795 }
7796 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7797 }
7798 #endif
7799
7800 OSReturn
7801 OSKext::setVMAttributes(bool protect, bool wire)
7802 {
7803 vm_map_t kext_map = NULL;
7804 kernel_segment_command_t * seg = NULL;
7805 vm_map_offset_t start_protect = 0;
7806 vm_map_offset_t start_wire = 0;
7807 vm_map_offset_t end_protect = 0;
7808 vm_map_offset_t end_wire = 0;
7809 OSReturn result = kOSReturnError;
7810
7811 if (isInterface() || !declaresExecutable() || flags.builtin) {
7812 result = kOSReturnSuccess;
7813 goto finish;
7814 }
7815
7816 /* Get the kext's vm map */
7817 kext_map = kext_get_vm_map(kmod_info);
7818 if (!kext_map) {
7819 result = KERN_MEMORY_ERROR;
7820 goto finish;
7821 }
7822
7823 #if !VM_MAPPED_KEXTS
7824 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7825 /* This is a split kext in a prelinked kernelcache; we'll let the
7826 * platform code take care of protecting it. It is already wired.
7827 */
7828 /* TODO: Should this still allow protections for the first segment
7829 * to go through, in the event that we have a mix of split and
7830 * unsplit kexts?
7831 */
7832 result = KERN_SUCCESS;
7833 goto finish;
7834 }
7835
7836 if (isInFileset() && kc_type != KCKindPageable) {
7837 // kexts in filesets have protections setup as part of collection loading
7838 result = KERN_SUCCESS;
7839 goto finish;
7840 }
7841 #endif
7842
7843 /* Protect the headers as read-only; they do not need to be wired */
7844 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7845 kext_map, kmod_info->address,
7846 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7847 : KERN_SUCCESS;
7848 if (result != KERN_SUCCESS) {
7849 goto finish;
7850 }
7851
7852 /* Set the VM protections and wire down each of the segments */
7853 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7854 while (seg) {
7855 #if __arm__
7856 /* We build all ARM kexts, so we can ensure they are aligned */
7857 assert((seg->vmaddr & PAGE_MASK) == 0);
7858 assert((seg->vmsize & PAGE_MASK) == 0);
7859 #endif
7860
7861 /*
7862 * For the non page aligned segments, the range calculation for protection
7863 * and wiring differ as follows:
7864 *
7865 * Protection: The non page aligned data at the start or at the end of the
7866 * segment is excluded from the protection. This exclusion is needed to make
7867 * sure OSKext_protect is not called twice on same page, if the page is shared
7868 * between two segments.
7869 *
7870 * Wiring: The non page aligned data at the start or at the end of the
7871 * segment is included in the wiring range, this inclusion is needed to make sure
7872 * all the data of the segment is wired.
7873 */
7874 start_protect = round_page(seg->vmaddr);
7875 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7876
7877 start_wire = trunc_page(seg->vmaddr);
7878 end_wire = round_page(seg->vmaddr + seg->vmsize);
7879
7880 /*
7881 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7882 * across kexts and data from kexts is not page aligned
7883 */
7884 if (protect && (end_protect > start_protect) &&
7885 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7886 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7887 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7888 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7889 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7890 if (result != KERN_SUCCESS) {
7891 OSKextLog(this,
7892 kOSKextLogErrorLevel |
7893 kOSKextLogLoadFlag,
7894 "Kext %s failed to set maximum VM protections "
7895 "for segment %s - 0x%x.",
7896 getIdentifierCString(), seg->segname, (int)result);
7897 goto finish;
7898 }
7899
7900 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7901 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7902 if (result != KERN_SUCCESS) {
7903 OSKextLog(this,
7904 kOSKextLogErrorLevel |
7905 kOSKextLogLoadFlag,
7906 "Kext %s failed to set initial VM protections "
7907 "for segment %s - 0x%x.",
7908 getIdentifierCString(), seg->segname, (int)result);
7909 goto finish;
7910 }
7911 }
7912
7913 if (segmentShouldBeWired(seg) && wire) {
7914 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7915 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7916 if (result != KERN_SUCCESS) {
7917 goto finish;
7918 }
7919 }
7920
7921 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7922 }
7923
7924 finish:
7925 return result;
7926 }
7927
7928 /*********************************************************************
7929 *********************************************************************/
7930 boolean_t
7931 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7932 {
7933 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7934 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7935 }
7936
7937 /*********************************************************************
7938 *********************************************************************/
7939 OSReturn
7940 OSKext::validateKextMapping(bool startFlag)
7941 {
7942 OSReturn result = kOSReturnError;
7943 const char * whichOp = startFlag ? "start" : "stop";
7944 kern_return_t kern_result = 0;
7945 vm_map_t kext_map = NULL;
7946 kernel_segment_command_t * seg = NULL;
7947 mach_vm_address_t address = 0;
7948 mach_vm_size_t size = 0;
7949 uint32_t depth = 0;
7950 uint64_t kext_segbase = 0;
7951 uint64_t kext_segsize = 0;
7952 mach_msg_type_number_t count;
7953 vm_region_submap_short_info_data_64_t info;
7954 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7955
7956 if (flags.builtin) {
7957 return kOSReturnSuccess;
7958 }
7959
7960 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7961 bzero(&info, sizeof(info));
7962
7963 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7964 // xxx - sufficient?
7965
7966 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7967 */
7968 if (!kmod_info) {
7969 OSKextLog(this,
7970 kOSKextLogErrorLevel |
7971 kOSKextLogLoadFlag,
7972 "Kext %s - NULL kmod_info pointer.",
7973 getIdentifierCString());
7974 result = kOSKextReturnBadData;
7975 goto finish;
7976 }
7977
7978 if (startFlag) {
7979 address = (mach_vm_address_t)kmod_info->start;
7980 } else {
7981 address = (mach_vm_address_t)kmod_info->stop;
7982 }
7983
7984 if (!address) {
7985 OSKextLog(this,
7986 kOSKextLogErrorLevel |
7987 kOSKextLogLoadFlag,
7988 "Kext %s - NULL module %s pointer.",
7989 getIdentifierCString(), whichOp);
7990 result = kOSKextReturnBadData;
7991 goto finish;
7992 }
7993
7994 kext_map = kext_get_vm_map(kmod_info);
7995 depth = (kernel_map == kext_map) ? 1 : 2;
7996 if (isInFileset()) {
7997 #if defined(HAS_APPLE_PAC)
7998 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7999 #endif /* defined(HAS_APPLE_PAC) */
8000 }
8001
8002 /* Verify that the start/stop function lies within the kext's address range.
8003 */
8004 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
8005 isInFileset()) {
8006 /* This will likely be how we deal with split kexts; walk the segments to
8007 * check that the function lies inside one of the segments of this kext.
8008 */
8009 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8010 seg != NULL;
8011 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
8012 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
8013 kext_segbase = seg->vmaddr;
8014 kext_segsize = seg->vmsize;
8015 break;
8016 }
8017 }
8018
8019 if (!seg) {
8020 OSKextLog(this,
8021 kOSKextLogErrorLevel |
8022 kOSKextLogLoadFlag,
8023 "Kext %s module %s pointer is outside of kext range "
8024 "(%s %p - kext starts at %p).",
8025 getIdentifierCString(),
8026 whichOp,
8027 whichOp,
8028 (void *)(((uintptr_t)address) - kext_slide),
8029 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
8030 result = kOSKextReturnBadData;
8031 goto finish;
8032 }
8033
8034 seg = NULL;
8035 } else {
8036 if (address < kmod_info->address + kmod_info->hdr_size ||
8037 kmod_info->address + kmod_info->size <= address) {
8038 OSKextLog(this,
8039 kOSKextLogErrorLevel |
8040 kOSKextLogLoadFlag,
8041 "Kext %s module %s pointer is outside of kext range "
8042 "(%s %p - kext at %p-%p).",
8043 getIdentifierCString(),
8044 whichOp,
8045 whichOp,
8046 (void *)(((uintptr_t)address) - kext_slide),
8047 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
8048 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
8049 result = kOSKextReturnBadData;
8050 goto finish;
8051 }
8052 }
8053
8054 /* Only do these checks before calling the start function;
8055 * If anything goes wrong with the mapping while the kext is running,
8056 * we'll likely have panicked well before any attempt to stop the kext.
8057 */
8058 if (startFlag) {
8059 if (!isInFileset() || kc_type != KCKindPrimary) {
8060 /*
8061 * Verify that the start/stop function is executable.
8062 */
8063 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
8064 (vm_region_recurse_info_t)&info, &count);
8065 if (kern_result != KERN_SUCCESS) {
8066 OSKextLog(this,
8067 kOSKextLogErrorLevel |
8068 kOSKextLogLoadFlag,
8069 "Kext %s - bad %s pointer %p.",
8070 getIdentifierCString(),
8071 whichOp, (void *)ml_static_unslide(address));
8072 result = kOSKextReturnBadData;
8073 goto finish;
8074 }
8075 } else {
8076 /*
8077 * Since kexts loaded from the primary KC are held in memory
8078 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8079 * discover that memory's protection flags. Instead, we need to
8080 * get that information from the kernel pmap itself. Above, we
8081 * (potentially) saved the size of the segment in which the address
8082 * in question was located. If we have a non-zero size, verify
8083 * that all pages in the (address, address + kext_segsize) range
8084 * are marked executable. If we somehow did not record the size
8085 * (or the base) just verify the single page that includes the address.
8086 */
8087 if (kext_segbase == 0 || kext_segsize == 0) {
8088 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8089 kext_segsize = PAGE_SIZE;
8090 }
8091 }
8092
8093 #if VM_MAPPED_KEXTS
8094 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8095 ((isInFileset() && kc_type == KCKindPrimary) &&
8096 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8097 OSKextLog(this,
8098 kOSKextLogErrorLevel |
8099 kOSKextLogLoadFlag,
8100 "Kext %s - memory region containing module %s function "
8101 "is not executable.",
8102 getIdentifierCString(), whichOp);
8103 result = kOSKextReturnBadData;
8104 goto finish;
8105 }
8106 #endif
8107
8108 /* Verify that the kext's segments are backed by physical memory.
8109 */
8110 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8111 while (seg) {
8112 if (!verifySegmentMapping(seg)) {
8113 result = kOSKextReturnBadData;
8114 goto finish;
8115 }
8116
8117 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8118 }
8119 }
8120
8121 result = kOSReturnSuccess;
8122 finish:
8123 return result;
8124 }
8125
8126 /*********************************************************************
8127 *********************************************************************/
8128 boolean_t
8129 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8130 {
8131 mach_vm_address_t address = 0;
8132
8133 if (seg->vmsize > UINT32_MAX) {
8134 return false;
8135 }
8136
8137 if (!segmentShouldBeWired(seg)) {
8138 return true;
8139 }
8140
8141 for (address = seg->vmaddr;
8142 address < round_page(seg->vmaddr + seg->vmsize);
8143 address += PAGE_SIZE) {
8144 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
8145 OSKextLog(this,
8146 kOSKextLogErrorLevel |
8147 kOSKextLogLoadFlag,
8148 "Kext %s - page %p is not backed by physical memory.",
8149 getIdentifierCString(),
8150 (void *)address);
8151 return false;
8152 }
8153 }
8154
8155 return true;
8156 }
8157
8158 /*********************************************************************
8159 *********************************************************************/
8160 static void
8161 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8162 {
8163 uint64_t stamp = 0;
8164 firehose_tracepoint_id_u trace_id;
8165 struct firehose_trace_uuid_info_s uuid_info_s;
8166 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8167 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8168 OSSharedPtr<OSData> uuid_data;
8169
8170 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
8171 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8172
8173 uuid_data = aKext->copyTextUUID();
8174 if (uuid_data) {
8175 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
8176 }
8177
8178 uuid_info->ftui_size = size;
8179 if (aKext->isDriverKit()) {
8180 uuid_info->ftui_address = address;
8181 } else {
8182 uuid_info->ftui_address = ml_static_unslide(address);
8183 }
8184 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
8185 return;
8186 }
8187
8188 void
8189 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8190 {
8191 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
8192 }
8193
8194 /*********************************************************************
8195 *********************************************************************/
8196 OSReturn
8197 OSKext::start(bool startDependenciesFlag)
8198 {
8199 OSReturn result = kOSReturnError;
8200 kern_return_t (* startfunc)(kmod_info_t *, void *);
8201 unsigned int i, count;
8202 void * kmodStartData = NULL;
8203
8204 if (isStarted() || isInterface() || isKernelComponent()) {
8205 result = kOSReturnSuccess;
8206 goto finish;
8207 }
8208
8209 if (!isLoaded()) {
8210 OSKextLog(this,
8211 kOSKextLogErrorLevel |
8212 kOSKextLogLoadFlag,
8213 "Attempt to start nonloaded kext %s.",
8214 getIdentifierCString());
8215 result = kOSKextReturnInvalidArgument;
8216 goto finish;
8217 }
8218
8219 if (!sLoadEnabled) {
8220 OSKextLog(this,
8221 kOSKextLogErrorLevel |
8222 kOSKextLogLoadFlag,
8223 "Kext loading is disabled (attempt to start kext %s).",
8224 getIdentifierCString());
8225 result = kOSKextReturnDisabled;
8226 goto finish;
8227 }
8228
8229 result = validateKextMapping(/* start? */ true);
8230 if (result != kOSReturnSuccess) {
8231 goto finish;
8232 }
8233
8234 startfunc = kmod_info->start;
8235
8236 count = getNumDependencies();
8237 for (i = 0; i < count; i++) {
8238 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8239 if (dependency == NULL) {
8240 OSKextLog(this,
8241 kOSKextLogErrorLevel |
8242 kOSKextLogLoadFlag,
8243 "Kext %s start - internal error, dependency disappeared.",
8244 getIdentifierCString());
8245 goto finish;
8246 }
8247 if (!dependency->isStarted()) {
8248 if (startDependenciesFlag) {
8249 OSReturn dependencyResult =
8250 dependency->start(startDependenciesFlag);
8251 if (dependencyResult != KERN_SUCCESS) {
8252 OSKextLog(this,
8253 kOSKextLogErrorLevel |
8254 kOSKextLogLoadFlag,
8255 "Kext %s start - dependency %s failed to start (error 0x%x).",
8256 getIdentifierCString(),
8257 dependency->getIdentifierCString(),
8258 dependencyResult);
8259 goto finish;
8260 }
8261 } else {
8262 OSKextLog(this,
8263 kOSKextLogErrorLevel |
8264 kOSKextLogLoadFlag,
8265 "Not starting %s - dependency %s not started yet.",
8266 getIdentifierCString(),
8267 dependency->getIdentifierCString());
8268 result = kOSKextReturnStartStopError; // xxx - make new return?
8269 goto finish;
8270 }
8271 }
8272 }
8273
8274 OSKextLog(this,
8275 kOSKextLogDetailLevel |
8276 kOSKextLogLoadFlag,
8277 "Kext %s calling module start function.",
8278 getIdentifierCString());
8279
8280 flags.starting = 1;
8281
8282 // Drop a log message so logd can grab the needed information to decode this kext
8283 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
8284 result = OSRuntimeInitializeCPP(this);
8285 if (result == KERN_SUCCESS) {
8286 result = startfunc(kmod_info, kmodStartData);
8287 }
8288
8289 flags.starting = 0;
8290
8291 /* On success overlap the setting of started/starting. On failure just
8292 * clear starting.
8293 */
8294 if (result == KERN_SUCCESS) {
8295 flags.started = 1;
8296
8297 // xxx - log start error from kernel?
8298 OSKextLog(this,
8299 kOSKextLogProgressLevel |
8300 kOSKextLogLoadFlag,
8301 "Kext %s is now started.",
8302 getIdentifierCString());
8303 } else {
8304 invokeOrCancelRequestCallbacks(
8305 /* result not actually used */ kOSKextReturnStartStopError,
8306 /* invokeFlag */ false);
8307 OSKextLog(this,
8308 kOSKextLogWarningLevel |
8309 kOSKextLogLoadFlag,
8310 "Kext %s did not start (return code 0x%x).",
8311 getIdentifierCString(), result);
8312 }
8313
8314 finish:
8315 return result;
8316 }
8317
8318 /*********************************************************************
8319 *********************************************************************/
8320 /* static */
8321 bool
8322 OSKext::canUnloadKextWithIdentifier(
8323 OSString * kextIdentifier,
8324 bool checkClassesFlag)
8325 {
8326 bool result = false;
8327 OSKext * aKext = NULL; // do not release
8328
8329 IORecursiveLockLock(sKextLock);
8330
8331 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8332
8333 if (!aKext) {
8334 goto finish; // can't unload what's not loaded
8335 }
8336
8337 if (aKext->isLoaded()) {
8338 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8339 goto finish;
8340 }
8341 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8342 goto finish;
8343 }
8344 }
8345
8346 result = true;
8347
8348 finish:
8349 IORecursiveLockUnlock(sKextLock);
8350 return result;
8351 }
8352
8353 /*********************************************************************
8354 *********************************************************************/
8355 OSReturn
8356 OSKext::stop(void)
8357 {
8358 OSReturn result = kOSReturnError;
8359 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8360
8361 if (!isStarted() || isInterface()) {
8362 result = kOSReturnSuccess;
8363 goto finish;
8364 }
8365
8366 if (!isLoaded()) {
8367 OSKextLog(this,
8368 kOSKextLogErrorLevel |
8369 kOSKextLogLoadFlag,
8370 "Attempt to stop nonloaded kext %s.",
8371 getIdentifierCString());
8372 result = kOSKextReturnInvalidArgument;
8373 goto finish;
8374 }
8375
8376 /* Refuse to stop if we have clients or instances. It is up to
8377 * the caller to make sure those aren't true.
8378 */
8379 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8380 OSKextLog(this,
8381 kOSKextLogErrorLevel |
8382 kOSKextLogLoadFlag,
8383 "Kext %s - C++ instances; can't stop.",
8384 getIdentifierCString());
8385 result = kOSKextReturnInUse;
8386 goto finish;
8387 }
8388
8389 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8390 OSKextLog(this,
8391 kOSKextLogErrorLevel |
8392 kOSKextLogLoadFlag,
8393 "Kext %s - has references (linkage or tracking object); "
8394 "can't stop.",
8395 getIdentifierCString());
8396 result = kOSKextReturnInUse;
8397 goto finish;
8398 }
8399
8400 /* Note: If validateKextMapping fails on the stop & unload path,
8401 * we are in serious trouble and a kernel panic is likely whether
8402 * we stop & unload the kext or not.
8403 */
8404 result = validateKextMapping(/* start? */ false);
8405 if (result != kOSReturnSuccess) {
8406 goto finish;
8407 }
8408
8409 stopfunc = kmod_info->stop;
8410 if (stopfunc) {
8411 OSKextLog(this,
8412 kOSKextLogDetailLevel |
8413 kOSKextLogLoadFlag,
8414 "Kext %s calling module stop function.",
8415 getIdentifierCString());
8416
8417 flags.stopping = 1;
8418
8419 result = stopfunc(kmod_info, /* userData */ NULL);
8420 if (result == KERN_SUCCESS) {
8421 result = OSRuntimeFinalizeCPP(this);
8422 }
8423
8424 flags.stopping = 0;
8425
8426 if (result == KERN_SUCCESS) {
8427 flags.started = 0;
8428
8429 OSKextLog(this,
8430 kOSKextLogDetailLevel |
8431 kOSKextLogLoadFlag,
8432 "Kext %s is now stopped and ready to unload.",
8433 getIdentifierCString());
8434 } else {
8435 OSKextLog(this,
8436 kOSKextLogErrorLevel |
8437 kOSKextLogLoadFlag,
8438 "Kext %s did not stop (return code 0x%x).",
8439 getIdentifierCString(), result);
8440 result = kOSKextReturnStartStopError;
8441 }
8442 }
8443
8444 finish:
8445 // Drop a log message so logd can update this kext's metadata
8446 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
8447 return result;
8448 }
8449
8450 /*********************************************************************
8451 *********************************************************************/
8452 OSReturn
8453 OSKext::unload(void)
8454 {
8455 OSReturn result = kOSReturnError;
8456 unsigned int index;
8457 uint32_t num_kmod_refs = 0;
8458 OSKextAccount * freeAccount;
8459 bool in_fileset = false;
8460
8461 if (!sUnloadEnabled) {
8462 OSKextLog(this,
8463 kOSKextLogErrorLevel |
8464 kOSKextLogLoadFlag,
8465 "Kext unloading is disabled (%s).",
8466 this->getIdentifierCString());
8467
8468 result = kOSKextReturnDisabled;
8469 goto finish;
8470 }
8471
8472 // cache this result so we don't need to access the kmod_info after
8473 // it's been potentially free'd
8474 in_fileset = isInFileset();
8475
8476 /* Refuse to unload if we have clients or instances. It is up to
8477 * the caller to make sure those aren't true.
8478 */
8479 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8480 // xxx - Don't log under errors? this is more of an info thing
8481 OSKextLog(this,
8482 kOSKextLogErrorLevel |
8483 kOSKextLogKextBookkeepingFlag,
8484 "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8485 getIdentifierCString(), getRetainCount());
8486 result = kOSKextReturnInUse;
8487 goto finish;
8488 }
8489
8490 if (isDriverKit()) {
8491 index = sLoadedDriverKitKexts->getNextIndexOfObject(this, 0);
8492 if (index != (unsigned int)-1) {
8493 sLoadedDriverKitKexts->removeObject(index);
8494 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
8495 loadTag = 0;
8496 }
8497 }
8498
8499 if (!isLoaded()) {
8500 result = kOSReturnSuccess;
8501 goto finish;
8502 }
8503
8504 if (isKernelComponent()) {
8505 result = kOSKextReturnInvalidArgument;
8506 goto finish;
8507 }
8508
8509 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
8510 OSKextLog(this,
8511 kOSKextLogErrorLevel |
8512 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8513 "Can't unload kext %s; classes have instances:",
8514 getIdentifierCString());
8515 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8516 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8517 result = kOSKextReturnInUse;
8518 goto finish;
8519 }
8520
8521 /* Note that the kext is unloading before running any code that
8522 * might be in the kext (request callbacks, module stop function).
8523 * We will deny certain requests made against a kext in the process
8524 * of unloading.
8525 */
8526 flags.unloading = 1;
8527
8528 /* Update the string describing the last kext to unload in case we panic.
8529 */
8530 savePanicString(/* isLoading */ false);
8531
8532 if (isStarted()) {
8533 result = stop();
8534 if (result != KERN_SUCCESS) {
8535 OSKextLog(this,
8536 kOSKextLogErrorLevel |
8537 kOSKextLogLoadFlag,
8538 "Kext %s can't unload - module stop returned 0x%x.",
8539 getIdentifierCString(), (unsigned)result);
8540 result = kOSKextReturnStartStopError;
8541 goto finish;
8542 }
8543 }
8544
8545 OSKextLog(this,
8546 kOSKextLogProgressLevel |
8547 kOSKextLogLoadFlag,
8548 "Kext %s unloading.",
8549 getIdentifierCString());
8550
8551 {
8552 struct list_head *p;
8553 struct list_head *prev;
8554 struct list_head *next;
8555 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8556 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8557 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
8558 prev = p->prev;
8559 next = p->next;
8560 prev->next = next;
8561 next->prev = prev;
8562 p->prev = p;
8563 p->next = p;
8564 IORecursiveLockWakeup(sKextLock, s, false);
8565 }
8566 }
8567
8568
8569 /* Even if we don't call the stop function, we want to be sure we
8570 * have no OSMetaClass references before unloading the kext executable
8571 * from memory. OSMetaClasses may have pointers into the kext executable
8572 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8573 */
8574 if (metaClasses) {
8575 metaClasses->flushCollection();
8576 }
8577 (void) OSRuntimeFinalizeCPP(this);
8578
8579 /* Remove the kext from the list of loaded kexts, patch the gap
8580 * in the kmod_info_t linked list, and reset "kmod" to point to the
8581 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8582 */
8583 index = sLoadedKexts->getNextIndexOfObject(this, 0);
8584 if (index != (unsigned int)-1) {
8585 sLoadedKexts->removeObject(index);
8586
8587 OSKext * nextKext = OSDynamicCast(OSKext,
8588 sLoadedKexts->getObject(index));
8589
8590 if (nextKext) {
8591 if (index > 0) {
8592 OSKext * gapKext = OSDynamicCast(OSKext,
8593 sLoadedKexts->getObject(index - 1));
8594
8595 nextKext->kmod_info->next = gapKext->kmod_info;
8596 } else { /* index == 0 */
8597 nextKext->kmod_info->next = NULL;
8598 }
8599 }
8600
8601 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8602 if (lastKext && !lastKext->isKernel()) {
8603 kmod = lastKext->kmod_info;
8604 } else {
8605 kmod = NULL; // clear the global kmod variable
8606 }
8607 }
8608
8609 /* Clear out the kmod references that we're keeping for compatibility
8610 * with current panic backtrace code & kgmacros.
8611 * xxx - will want to update those bits sometime and remove this.
8612 */
8613 num_kmod_refs = getNumDependencies();
8614 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8615 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8616 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8617 ref->info->reference_count--;
8618 }
8619 kfree_type(kmod_reference_t, num_kmod_refs,
8620 kmod_info->reference_list);
8621 }
8622
8623 #if CONFIG_DTRACE
8624 unregisterWithDTrace();
8625 #endif /* CONFIG_DTRACE */
8626
8627 notifyKextUnloadObservers(this);
8628
8629 freeAccount = NULL;
8630 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
8631 account->kext = NULL;
8632 if (account->site.tag) {
8633 account->site.flags |= VM_TAG_UNLOAD;
8634 } else {
8635 freeAccount = account;
8636 }
8637
8638 #if DEVELOPMENT || DEBUG
8639 assertf(account->task_refgrp.grp_count == 0,
8640 "unloading a kext with active task references");
8641 #endif /* DEVELOPMENT || DEBUG */
8642
8643 lck_ticket_unlock(sKextAccountsLock);
8644 if (freeAccount) {
8645 IOFreeType(freeAccount, OSKextAccount);
8646 }
8647
8648 /* Unwire and free the linked executable.
8649 */
8650 if (linkedExecutable) {
8651 #if KASAN
8652 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8653 #endif
8654
8655 #if VM_MAPPED_KEXTS
8656 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8657 kernel_segment_command_t *seg = NULL;
8658 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8659
8660 if (!kext_map) {
8661 OSKextLog(this,
8662 kOSKextLogErrorLevel |
8663 kOSKextLogLoadFlag,
8664 "Failed to free kext %s; couldn't find the kext map.",
8665 getIdentifierCString());
8666 result = kOSKextReturnInternalError;
8667 goto finish;
8668 }
8669
8670 OSKextLog(this,
8671 kOSKextLogProgressLevel |
8672 kOSKextLogLoadFlag,
8673 "Kext %s unwiring and unmapping linked executable.",
8674 getIdentifierCString());
8675
8676 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8677 while (seg) {
8678 if (segmentShouldBeWired(seg)) {
8679 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8680 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8681
8682 result = vm_map_unwire(kext_map, start_wire,
8683 end_wire, FALSE);
8684 if (result != KERN_SUCCESS) {
8685 OSKextLog(this,
8686 kOSKextLogErrorLevel |
8687 kOSKextLogLoadFlag,
8688 "Failed to unwire kext %s.",
8689 getIdentifierCString());
8690 result = kOSKextReturnInternalError;
8691 goto finish;
8692 }
8693 }
8694
8695 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8696 }
8697 #if defined(__x86_64__) || defined(__i386__)
8698 if (in_fileset && flags.resetSegmentsFromVnode) {
8699 IORecursiveLockLock(sKextLock);
8700 resetKCFileSetSegments();
8701 IORecursiveLockUnlock(sKextLock);
8702 }
8703 #endif // (__x86_64__) || defined(__i386__)
8704 }
8705 #endif /* VM_MAPPED_KEXTS */
8706 if (flags.resetSegmentsFromImmutableCopy) {
8707 result = resetMutableSegments();
8708 if (result != kOSReturnSuccess) {
8709 OSKextLog(this,
8710 kOSKextLogErrorLevel |
8711 kOSKextLogLoadFlag,
8712 "Failed to reset kext %s.",
8713 getIdentifierCString());
8714 result = kOSKextReturnInternalError;
8715 goto finish;
8716 }
8717 }
8718 if (kc_type == KCKindUnknown) {
8719 linkedExecutable.reset();
8720 }
8721 }
8722
8723 /* An interface kext has a fake kmod_info that was allocated,
8724 * so we have to free it.
8725 */
8726 if (isInterface()) {
8727 kfree_type(kmod_info_t, kmod_info);
8728 kmod_info = NULL;
8729 }
8730
8731 if (!in_fileset) {
8732 kmod_info = NULL;
8733 }
8734
8735 flags.loaded = false;
8736 flushDependencies();
8737
8738 /* save a copy of the bundle ID for us to check when deciding to
8739 * rebuild the kernel cache file. If a kext was already in the kernel
8740 * cache and unloaded then later loaded we do not need to rebuild the
8741 * kernel cache. 9055303
8742 */
8743 if (isPrelinked()) {
8744 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
8745 IORecursiveLockLock(sKextLock);
8746 if (sUnloadedPrelinkedKexts) {
8747 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8748 }
8749 IORecursiveLockUnlock(sKextLock);
8750 }
8751 }
8752
8753 OSKextLog(this,
8754 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8755 "Kext %s unloaded.", getIdentifierCString());
8756
8757 queueKextNotification(kKextRequestPredicateUnloadNotification,
8758 OSDynamicCast(OSString, bundleID.get()));
8759
8760 finish:
8761 OSKext::saveLoadedKextPanicList();
8762 OSKext::updateLoadedKextSummaries();
8763
8764 flags.unloading = 0;
8765 return result;
8766 }
8767
8768 /*********************************************************************
8769 * Assumes sKextLock is held.
8770 *********************************************************************/
8771 /* static */
8772 OSReturn
8773 OSKext::queueKextNotification(
8774 const char * notificationName,
8775 OSString * kextIdentifier)
8776 {
8777 OSReturn result = kOSReturnError;
8778 OSSharedPtr<OSDictionary> loadRequest;
8779
8780 if (!kextIdentifier) {
8781 result = kOSKextReturnInvalidArgument;
8782 goto finish;
8783 }
8784
8785 /* Create a new request unless one is already sitting
8786 * in sKernelRequests for this bundle identifier
8787 */
8788 result = _OSKextCreateRequest(notificationName, loadRequest);
8789 if (result != kOSReturnSuccess) {
8790 goto finish;
8791 }
8792 if (!_OSKextSetRequestArgument(loadRequest.get(),
8793 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8794 result = kOSKextReturnNoMemory;
8795 goto finish;
8796 }
8797 if (!sKernelRequests->setObject(loadRequest.get())) {
8798 result = kOSKextReturnNoMemory;
8799 goto finish;
8800 }
8801
8802 /* We might want to only queue the notification if the IOKit daemon is active,
8803 * but that wouldn't work for embedded. Note that we don't care if
8804 * the ping immediately succeeds here so don't do anything with the
8805 * result of this call.
8806 */
8807 OSKext::pingIOKitDaemon();
8808
8809 result = kOSReturnSuccess;
8810
8811 finish:
8812 return result;
8813 }
8814
8815
8816 #if CONFIG_KXLD
8817 /*********************************************************************
8818 *********************************************************************/
8819 static void
8820 _OSKextConsiderDestroyingLinkContext(
8821 __unused thread_call_param_t p0,
8822 __unused thread_call_param_t p1)
8823 {
8824 /* Take multiple locks in the correct order.
8825 */
8826 IORecursiveLockLock(sKextLock);
8827 IORecursiveLockLock(sKextInnerLock);
8828
8829 /* The first time we destroy the kxldContext is in the first
8830 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8831 * before calling this function. Thereafter any call to this function
8832 * will actually destroy the context.
8833 */
8834 if (sConsiderUnloadsCalled && sKxldContext) {
8835 kxld_destroy_context(sKxldContext);
8836 sKxldContext = NULL;
8837 }
8838
8839 /* Free the thread_call that was allocated to execute this function.
8840 */
8841 if (sDestroyLinkContextThread) {
8842 if (!thread_call_free(sDestroyLinkContextThread)) {
8843 OSKextLog(/* kext */ NULL,
8844 kOSKextLogErrorLevel |
8845 kOSKextLogGeneralFlag,
8846 "thread_call_free() failed for kext link context.");
8847 }
8848 sDestroyLinkContextThread = NULL;
8849 }
8850
8851 IORecursiveLockUnlock(sKextInnerLock);
8852 IORecursiveLockUnlock(sKextLock);
8853
8854 return;
8855 }
8856
8857 /*********************************************************************
8858 * Destroying the kxldContext requires checking variables under both
8859 * sKextInnerLock and sKextLock, so we do it on a separate thread
8860 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8861 * call relationship.
8862 *
8863 * This function must be invoked with sKextInnerLock held.
8864 * Do not call any function that takes sKextLock here!
8865 *********************************************************************/
8866 /* static */
8867 void
8868 OSKext::considerDestroyingLinkContext(void)
8869 {
8870 IORecursiveLockLock(sKextInnerLock);
8871
8872 /* If we have already queued a thread to destroy the link context,
8873 * don't bother resetting; that thread will take care of it.
8874 */
8875 if (sDestroyLinkContextThread) {
8876 goto finish;
8877 }
8878
8879 /* The function to be invoked in the thread will deallocate
8880 * this thread_call, so don't share it around.
8881 */
8882 sDestroyLinkContextThread = thread_call_allocate(
8883 &_OSKextConsiderDestroyingLinkContext, NULL);
8884 if (!sDestroyLinkContextThread) {
8885 OSKextLog(/* kext */ NULL,
8886 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8887 "Can't create thread to destroy kext link context.");
8888 goto finish;
8889 }
8890
8891 thread_call_enter(sDestroyLinkContextThread);
8892
8893 finish:
8894 IORecursiveLockUnlock(sKextInnerLock);
8895 return;
8896 }
8897
8898 #else // !CONFIG_KXLD
8899
8900 /* static */
8901 void
8902 OSKext::considerDestroyingLinkContext(void)
8903 {
8904 return;
8905 }
8906
8907 #endif // CONFIG_KXLD
8908
8909 #if PRAGMA_MARK
8910 #pragma mark Autounload
8911 #endif
8912 /*********************************************************************
8913 * This is a static method because the kext will be deallocated if it
8914 * does unload!
8915 *********************************************************************/
8916 /* static */
8917 OSReturn
8918 OSKext::autounloadKext(OSKext * aKext)
8919 {
8920 OSReturn result = kOSKextReturnInUse;
8921
8922 #if NO_KEXTD
8923 /*
8924 * Do not unload prelinked kexts on platforms that do not have an
8925 * IOKit daemon as there is no way to reload the kext or restart
8926 * matching.
8927 */
8928 if (aKext->isPrelinked()) {
8929 goto finish;
8930 }
8931 #endif /* defined(__x86_64__) */
8932
8933 /* Check for external references to this kext (usu. dependents),
8934 * instances of defined classes (or classes derived from them),
8935 * outstanding requests.
8936 */
8937 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8938 !aKext->flags.autounloadEnabled ||
8939 aKext->isKernelComponent()) {
8940 goto finish;
8941 }
8942
8943 /* Skip a delay-autounload kext, once.
8944 */
8945 if (aKext->flags.delayAutounload) {
8946 OSKextLog(aKext,
8947 kOSKextLogProgressLevel |
8948 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8949 "Kext %s has delayed autounload set; skipping and clearing flag.",
8950 aKext->getIdentifierCString());
8951 aKext->flags.delayAutounload = 0;
8952 goto finish;
8953 }
8954
8955 if (aKext->hasOSMetaClassInstances() ||
8956 aKext->countRequestCallbacks()) {
8957 goto finish;
8958 }
8959
8960 result = OSKext::removeKext(aKext);
8961
8962 finish:
8963 return result;
8964 }
8965
8966 /*********************************************************************
8967 *********************************************************************/
8968 void
8969 _OSKextConsiderUnloads(
8970 __unused thread_call_param_t p0,
8971 __unused thread_call_param_t p1)
8972 {
8973 bool didUnload = false;
8974 unsigned int count, i;
8975
8976 /* Take multiple locks in the correct order
8977 * (note also sKextSummaries lock further down).
8978 */
8979 IORecursiveLockLock(sKextLock);
8980 IORecursiveLockLock(sKextInnerLock);
8981
8982 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8983
8984 /* If the system is powering down, don't try to unload anything.
8985 */
8986 if (sSystemSleep) {
8987 goto finish;
8988 }
8989
8990 OSKextLog(/* kext */ NULL,
8991 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8992 "Checking for unused kexts to autounload.");
8993
8994 /*****
8995 * Remove any request callbacks marked as stale,
8996 * and mark as stale any currently in flight.
8997 */
8998 count = sRequestCallbackRecords->getCount();
8999 if (count) {
9000 i = count - 1;
9001 do {
9002 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
9003 sRequestCallbackRecords->getObject(i));
9004 if (callbackRecord) {
9005 OSBoolean * stale = OSDynamicCast(OSBoolean,
9006 callbackRecord->getObject(kKextRequestStaleKey));
9007
9008 if (stale == kOSBooleanTrue) {
9009 OSKext::invokeRequestCallback(callbackRecord,
9010 kOSKextReturnTimeout);
9011 } else {
9012 callbackRecord->setObject(kKextRequestStaleKey,
9013 kOSBooleanTrue);
9014 }
9015 }
9016 } while (i--);
9017 }
9018
9019 /*****
9020 * Make multiple passes through the array of loaded kexts until
9021 * we don't unload any. This handles unwinding of dependency
9022 * chains. We have to go *backwards* through the array because
9023 * kexts are removed from it when unloaded, and we cannot make
9024 * a copy or we'll mess up the retain counts we rely on to
9025 * check whether a kext will unload. If only we could have
9026 * nonretaining collections like CF has....
9027 */
9028 do {
9029 didUnload = false;
9030
9031 count = sLoadedKexts->getCount();
9032 if (count) {
9033 i = count - 1;
9034 do {
9035 OSKext * thisKext = OSDynamicCast(OSKext,
9036 sLoadedKexts->getObject(i));
9037 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
9038 } while (i--);
9039 }
9040 } while (didUnload);
9041
9042 finish:
9043 sConsiderUnloadsPending = false;
9044 sConsiderUnloadsExecuted = true;
9045
9046 (void) OSKext::considerRebuildOfPrelinkedKernel();
9047
9048 IORecursiveLockUnlock(sKextInnerLock);
9049 IORecursiveLockUnlock(sKextLock);
9050
9051 return;
9052 }
9053
9054 /*********************************************************************
9055 * Do not call any function that takes sKextLock here!
9056 *********************************************************************/
9057 void
9058 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
9059 {
9060 AbsoluteTime when;
9061
9062 IORecursiveLockLock(sKextInnerLock);
9063
9064 if (!sUnloadCallout) {
9065 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
9066 }
9067
9068 /* we only reset delay value for unloading if we already have something
9069 * pending. rescheduleOnlyFlag should not start the count down.
9070 */
9071 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9072 goto finish;
9073 }
9074
9075 thread_call_cancel(sUnloadCallout);
9076 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9077 #if !NO_KEXTD
9078 && sIOKitDaemonActive
9079 #endif
9080 ) {
9081 clock_interval_to_deadline(sConsiderUnloadDelay,
9082 1000 * 1000 * 1000, &when);
9083
9084 OSKextLog(/* kext */ NULL,
9085 kOSKextLogProgressLevel |
9086 kOSKextLogLoadFlag,
9087 "%scheduling %sscan for unused kexts in %lu seconds.",
9088 sConsiderUnloadsPending ? "Res" : "S",
9089 sConsiderUnloadsCalled ? "" : "initial ",
9090 (unsigned long)sConsiderUnloadDelay);
9091
9092 sConsiderUnloadsPending = true;
9093 thread_call_enter_delayed(sUnloadCallout, when);
9094 }
9095
9096 finish:
9097 /* The kxld context should be reused throughout boot. We mark the end of
9098 * period as the first time considerUnloads() is called, and we destroy
9099 * the first kxld context in that function. Afterwards, it will be
9100 * destroyed in flushNonloadedKexts.
9101 */
9102 if (!sConsiderUnloadsCalled) {
9103 sConsiderUnloadsCalled = true;
9104 OSKext::considerDestroyingLinkContext();
9105 }
9106
9107 IORecursiveLockUnlock(sKextInnerLock);
9108 return;
9109 }
9110
9111 /*********************************************************************
9112 * Do not call any function that takes sKextLock here!
9113 *********************************************************************/
9114 extern "C" {
9115 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9116 IOReturn
9117 OSKextSystemSleepOrWake(UInt32 messageType)
9118 {
9119 IORecursiveLockLock(sKextInnerLock);
9120
9121 /* If the system is going to sleep, cancel the reaper thread timer,
9122 * and note that we're in a sleep state in case it just fired but hasn't
9123 * taken the lock yet. If we are coming back from sleep, just
9124 * clear the sleep flag; IOService's normal operation will cause
9125 * unloads to be considered soon enough.
9126 */
9127 if (messageType == kIOMessageSystemWillSleep) {
9128 if (sUnloadCallout) {
9129 thread_call_cancel(sUnloadCallout);
9130 }
9131 sSystemSleep = true;
9132 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9133 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9134 sSystemSleep = false;
9135 clock_get_uptime(&sLastWakeTime);
9136 }
9137 IORecursiveLockUnlock(sKextInnerLock);
9138
9139 return kIOReturnSuccess;
9140 }
9141 };
9142
9143
9144 #if PRAGMA_MARK
9145 #pragma mark Prelinked Kernel
9146 #endif
9147
9148 #ifdef CONFIG_KXLD
9149 /*********************************************************************
9150 * Do not access sConsiderUnloads... variables other than
9151 * sConsiderUnloadsExecuted in this function. They are guarded by a
9152 * different lock.
9153 *********************************************************************/
9154 /* static */
9155 void
9156 OSKext::considerRebuildOfPrelinkedKernel(void)
9157 {
9158 static bool requestedPrelink = false;
9159 OSReturn checkResult = kOSReturnError;
9160 OSSharedPtr<OSDictionary> prelinkRequest;
9161 OSSharedPtr<OSCollectionIterator> kextIterator;
9162 const OSSymbol * thisID = NULL; // do not release
9163 bool doRebuild = false;
9164 AbsoluteTime my_abstime;
9165 UInt64 my_ns;
9166 SInt32 delta_secs;
9167
9168 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9169 if (requestedPrelink || !sPrelinkBoot) {
9170 return;
9171 }
9172
9173 /* no direct return from this point */
9174 IORecursiveLockLock(sKextLock);
9175
9176 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9177 * and any new startup kexts loaded.
9178 */
9179 if (!sConsiderUnloadsExecuted ||
9180 !sDeferredLoadSucceeded) {
9181 goto finish;
9182 }
9183
9184 /* we really only care about boot / system start up related kexts so bail
9185 * if we're here after REBUILD_MAX_TIME.
9186 */
9187 if (!_OSKextInPrelinkRebuildWindow()) {
9188 OSKextLog(/* kext */ NULL,
9189 kOSKextLogArchiveFlag,
9190 "%s prebuild rebuild has expired",
9191 __FUNCTION__);
9192 requestedPrelink = true;
9193 goto finish;
9194 }
9195
9196 /* we do not want to trigger a rebuild if we get here too close to waking
9197 * up. (see radar 10233768)
9198 */
9199 IORecursiveLockLock(sKextInnerLock);
9200
9201 clock_get_uptime(&my_abstime);
9202 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9203 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9204 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9205 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9206 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9207 }
9208 IORecursiveLockUnlock(sKextInnerLock);
9209
9210 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9211 /* too close to time of last wake from sleep */
9212 goto finish;
9213 }
9214 requestedPrelink = true;
9215
9216 /* Now it's time to see if we have a reason to rebuild. We may have done
9217 * some loads and unloads but the kernel cache didn't actually change.
9218 * We will rebuild if any kext is not marked prelinked AND is not in our
9219 * list of prelinked kexts that got unloaded. (see radar 9055303)
9220 */
9221 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9222 if (!kextIterator) {
9223 goto finish;
9224 }
9225
9226 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9227 OSKext * thisKext; // do not release
9228
9229 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9230 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9231 continue;
9232 }
9233
9234 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9235 continue;
9236 }
9237 /* kext is loaded and was not in current kernel cache so let's rebuild
9238 */
9239 doRebuild = true;
9240 OSKextLog(/* kext */ NULL,
9241 kOSKextLogArchiveFlag,
9242 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9243 thisKext->bundleID->getCStringNoCopy());
9244 break;
9245 }
9246 sUnloadedPrelinkedKexts->flushCollection();
9247
9248 if (!doRebuild) {
9249 goto finish;
9250 }
9251
9252 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9253 prelinkRequest);
9254 if (checkResult != kOSReturnSuccess) {
9255 goto finish;
9256 }
9257
9258 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9259 goto finish;
9260 }
9261
9262 OSKext::pingIOKitDaemon();
9263
9264 finish:
9265 IORecursiveLockUnlock(sKextLock);
9266
9267 return;
9268 }
9269
9270 #else /* !CONFIG_KXLD */
9271
9272 void
9273 OSKext::considerRebuildOfPrelinkedKernel(void)
9274 {
9275 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9276 return;
9277 }
9278
9279 #endif /* CONFIG_KXLD */
9280
9281 #if PRAGMA_MARK
9282 #pragma mark Dependencies
9283 #endif
9284 /*********************************************************************
9285 *********************************************************************/
9286 bool
9287 OSKext::resolveDependencies(
9288 OSArray * loopStack)
9289 {
9290 bool result = false;
9291 OSSharedPtr<OSArray> localLoopStack;
9292 bool addedToLoopStack = false;
9293 OSDictionary * libraries = NULL; // do not release
9294 OSSharedPtr<OSCollectionIterator> libraryIterator;
9295 OSString * libraryID = NULL; // do not release
9296 OSKext * libraryKext = NULL; // do not release
9297 bool hasRawKernelDependency = false;
9298 bool hasKernelDependency = false;
9299 bool hasKPIDependency = false;
9300 bool hasPrivateKPIDependency = false;
9301 unsigned int count;
9302
9303 #if CONFIG_KXLD
9304 OSString * infoString = NULL; // do not release
9305 OSString * readableString = NULL; // do not release
9306 #endif // CONFIG_KXLD
9307
9308 /* A kernel component will automatically have this flag set,
9309 * and a loaded kext should also have it set (as should all its
9310 * loaded dependencies).
9311 */
9312 if (flags.hasAllDependencies) {
9313 result = true;
9314 goto finish;
9315 }
9316
9317 /* Check for loops in the dependency graph.
9318 */
9319 if (loopStack) {
9320 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
9321 OSKextLog(this,
9322 kOSKextLogErrorLevel |
9323 kOSKextLogDependenciesFlag,
9324 "Kext %s has a dependency loop; can't resolve dependencies.",
9325 getIdentifierCString());
9326 goto finish;
9327 }
9328 } else {
9329 OSKextLog(this,
9330 kOSKextLogStepLevel |
9331 kOSKextLogDependenciesFlag,
9332 "Kext %s resolving dependencies.",
9333 getIdentifierCString());
9334
9335 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
9336 if (!localLoopStack) {
9337 OSKextLog(this,
9338 kOSKextLogErrorLevel |
9339 kOSKextLogDependenciesFlag,
9340 "Kext %s can't create bookkeeping stack to resolve dependencies.",
9341 getIdentifierCString());
9342 goto finish;
9343 }
9344 loopStack = localLoopStack.get();
9345 }
9346 if (!loopStack->setObject(this)) {
9347 OSKextLog(this,
9348 kOSKextLogErrorLevel |
9349 kOSKextLogDependenciesFlag,
9350 "Kext %s - internal error resolving dependencies.",
9351 getIdentifierCString());
9352 goto finish;
9353 }
9354 addedToLoopStack = true;
9355
9356 /* Purge any existing kexts in the dependency list and start over.
9357 */
9358 flushDependencies();
9359 if (dependencies) {
9360 OSKextLog(this,
9361 kOSKextLogErrorLevel |
9362 kOSKextLogDependenciesFlag,
9363 "Kext %s - internal error resolving dependencies.",
9364 getIdentifierCString());
9365 }
9366
9367 libraries = OSDynamicCast(OSDictionary,
9368 getPropertyForHostArch(kOSBundleLibrariesKey));
9369 if (libraries == NULL || libraries->getCount() == 0) {
9370 OSKextLog(this,
9371 kOSKextLogErrorLevel |
9372 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9373 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9374 getIdentifierCString(), kOSBundleLibrariesKey);
9375 goto finish;
9376 }
9377
9378 /* Make a new array to hold the dependencies (flush freed the old one).
9379 */
9380 dependencies = OSArray::withCapacity(libraries->getCount());
9381 if (!dependencies) {
9382 OSKextLog(this,
9383 kOSKextLogErrorLevel |
9384 kOSKextLogDependenciesFlag,
9385 "Kext %s - can't allocate dependencies array.",
9386 getIdentifierCString());
9387 goto finish;
9388 }
9389
9390 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9391 // xxx - compat: if none were declared.
9392
9393 libraryIterator = OSCollectionIterator::withCollection(libraries);
9394 if (!libraryIterator) {
9395 OSKextLog(this,
9396 kOSKextLogErrorLevel |
9397 kOSKextLogDependenciesFlag,
9398 "Kext %s - can't allocate dependencies iterator.",
9399 getIdentifierCString());
9400 goto finish;
9401 }
9402
9403 while ((libraryID = OSDynamicCast(OSString,
9404 libraryIterator->getNextObject()))) {
9405 const char * library_id = libraryID->getCStringNoCopy();
9406
9407 OSString * libraryVersion = OSDynamicCast(OSString,
9408 libraries->getObject(libraryID));
9409 if (libraryVersion == NULL) {
9410 OSKextLog(this,
9411 kOSKextLogErrorLevel |
9412 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9413 "Kext %s - illegal type in OSBundleLibraries.",
9414 getIdentifierCString());
9415 goto finish;
9416 }
9417
9418 OSKextVersion libraryVers =
9419 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
9420 if (libraryVers == -1) {
9421 OSKextLog(this,
9422 kOSKextLogErrorLevel |
9423 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9424 "Kext %s - invalid library version %s.",
9425 getIdentifierCString(),
9426 libraryVersion->getCStringNoCopy());
9427 goto finish;
9428 }
9429
9430 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9431 if (libraryKext == NULL) {
9432 OSKextLog(this,
9433 kOSKextLogErrorLevel |
9434 kOSKextLogDependenciesFlag,
9435 "Kext %s - library kext %s not found.",
9436 getIdentifierCString(), library_id);
9437 goto finish;
9438 }
9439
9440 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
9441 OSKextLog(this,
9442 kOSKextLogErrorLevel |
9443 kOSKextLogDependenciesFlag,
9444 "Kext %s - library kext %s not compatible "
9445 "with requested version %s.",
9446 getIdentifierCString(), library_id,
9447 libraryVersion->getCStringNoCopy());
9448 goto finish;
9449 }
9450
9451 /* If a nonprelinked library somehow got into the mix for a
9452 * prelinked kext, at any point in the chain, we must fail
9453 * because the prelinked relocs for the library will be all wrong.
9454 */
9455 if (this->isPrelinked() &&
9456 libraryKext->declaresExecutable() &&
9457 !libraryKext->isPrelinked()) {
9458 OSKextLog(this,
9459 kOSKextLogErrorLevel |
9460 kOSKextLogDependenciesFlag,
9461 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9462 getIdentifierCString(), library_id,
9463 libraryVersion->getCStringNoCopy());
9464 goto finish;
9465 }
9466
9467 if (!libraryKext->resolveDependencies(loopStack)) {
9468 goto finish;
9469 }
9470
9471 /* Add the library directly only if it has an executable to link.
9472 * Otherwise it's just used to collect other dependencies, so put
9473 * *its* dependencies on the list for this kext.
9474 */
9475 // xxx - We are losing info here; would like to make fake entries or
9476 // xxx - keep these in the dependency graph for loaded kexts.
9477 // xxx - I really want to make kernel components not a special case!
9478 if (libraryKext->declaresExecutable() ||
9479 libraryKext->isInterface()) {
9480 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
9481 dependencies->setObject(libraryKext);
9482
9483 OSKextLog(this,
9484 kOSKextLogDetailLevel |
9485 kOSKextLogDependenciesFlag,
9486 "Kext %s added dependency %s.",
9487 getIdentifierCString(),
9488 libraryKext->getIdentifierCString());
9489 }
9490 } else {
9491 int numLibDependencies = libraryKext->getNumDependencies();
9492 OSArray * libraryDependencies = libraryKext->getDependencies();
9493 int index;
9494
9495 if (numLibDependencies) {
9496 // xxx - this msg level should be 1 lower than the per-kext one
9497 OSKextLog(this,
9498 kOSKextLogDetailLevel |
9499 kOSKextLogDependenciesFlag,
9500 "Kext %s pulling %d dependencies from codeless library %s.",
9501 getIdentifierCString(),
9502 numLibDependencies,
9503 libraryKext->getIdentifierCString());
9504 }
9505 for (index = 0; index < numLibDependencies; index++) {
9506 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9507 libraryDependencies->getObject(index));
9508 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
9509 dependencies->setObject(thisLibDependency);
9510 OSKextLog(this,
9511 kOSKextLogDetailLevel |
9512 kOSKextLogDependenciesFlag,
9513 "Kext %s added dependency %s from codeless library %s.",
9514 getIdentifierCString(),
9515 thisLibDependency->getIdentifierCString(),
9516 libraryKext->getIdentifierCString());
9517 }
9518 }
9519 }
9520
9521 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
9522 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
9523 hasRawKernelDependency = true;
9524 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9525 hasKernelDependency = true;
9526 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9527 hasKPIDependency = true;
9528 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
9529 hasPrivateKPIDependency = true;
9530 }
9531 }
9532 }
9533
9534 if (hasRawKernelDependency) {
9535 OSKextLog(this,
9536 kOSKextLogErrorLevel |
9537 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9538 "Error - kext %s declares a dependency on %s, which is not permitted.",
9539 getIdentifierCString(), KERNEL_LIB);
9540 goto finish;
9541 }
9542 #if __LP64__
9543 if (hasKernelDependency) {
9544 OSKextLog(this,
9545 kOSKextLogErrorLevel |
9546 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9547 "Error - kext %s declares %s dependencies. "
9548 "Only %s* dependencies are supported for 64-bit kexts.",
9549 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9550 goto finish;
9551 }
9552 if (!hasKPIDependency) {
9553 OSKextLog(this,
9554 kOSKextLogWarningLevel |
9555 kOSKextLogDependenciesFlag,
9556 "Warning - kext %s declares no %s* dependencies. "
9557 "If it uses any KPIs, the link may fail with undefined symbols.",
9558 getIdentifierCString(), KPI_LIB_PREFIX);
9559 }
9560 #else /* __LP64__ */
9561 // xxx - will change to flatly disallow "kernel" dependencies at some point
9562 // xxx - is it invalid to do both "com.apple.kernel" and any
9563 // xxx - "com.apple.kernel.*"?
9564
9565 if (hasKernelDependency && hasKPIDependency) {
9566 OSKextLog(this,
9567 kOSKextLogWarningLevel |
9568 kOSKextLogDependenciesFlag,
9569 "Warning - kext %s has immediate dependencies on both "
9570 "%s* and %s* components; use only one style.",
9571 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9572 }
9573
9574 if (!hasKernelDependency && !hasKPIDependency) {
9575 // xxx - do we want to use validation flag for these too?
9576 OSKextLog(this,
9577 kOSKextLogWarningLevel |
9578 kOSKextLogDependenciesFlag,
9579 "Warning - %s declares no kernel dependencies; using %s.",
9580 getIdentifierCString(), KERNEL6_LIB);
9581 OSKext * kernelKext = OSDynamicCast(OSKext,
9582 sKextsByID->getObject(KERNEL6_LIB));
9583 if (kernelKext) {
9584 dependencies->setObject(kernelKext);
9585 } else {
9586 OSKextLog(this,
9587 kOSKextLogErrorLevel |
9588 kOSKextLogDependenciesFlag,
9589 "Error - Library %s not found for %s.",
9590 KERNEL6_LIB, getIdentifierCString());
9591 }
9592 }
9593
9594 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9595 * its indirect dependencies to simulate old-style linking. XXX - Should
9596 * check for duplicates.
9597 */
9598 if (!hasKPIDependency) {
9599 unsigned int i;
9600
9601 flags.hasBleedthrough = true;
9602
9603 count = getNumDependencies();
9604
9605 /* We add to the dependencies array in this loop, but do not iterate
9606 * past its original count.
9607 */
9608 for (i = 0; i < count; i++) {
9609 OSKext * dependencyKext = OSDynamicCast(OSKext,
9610 dependencies->getObject(i));
9611 dependencyKext->addBleedthroughDependencies(dependencies.get());
9612 }
9613 }
9614 #endif /* __LP64__ */
9615
9616 #if CONFIG_KXLD
9617 /*
9618 * If we're not dynamically linking kexts, then we don't need to check
9619 * copyright strings. The linker in user space has already done this.
9620 */
9621 if (hasPrivateKPIDependency) {
9622 bool hasApplePrefix = false;
9623 bool infoCopyrightIsValid = false;
9624 bool readableCopyrightIsValid = false;
9625
9626 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9627 APPLE_KEXT_PREFIX);
9628
9629 infoString = OSDynamicCast(OSString,
9630 getPropertyForHostArch("CFBundleGetInfoString"));
9631 if (infoString) {
9632 infoCopyrightIsValid =
9633 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9634 }
9635
9636 readableString = OSDynamicCast(OSString,
9637 getPropertyForHostArch("NSHumanReadableCopyright"));
9638 if (readableString) {
9639 readableCopyrightIsValid =
9640 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9641 }
9642
9643 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9644 OSKextLog(this,
9645 kOSKextLogErrorLevel |
9646 kOSKextLogDependenciesFlag,
9647 "Error - kext %s declares a dependency on %s. "
9648 "Only Apple kexts may declare a dependency on %s.",
9649 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9650 goto finish;
9651 }
9652 }
9653 #endif // CONFIG_KXLD
9654
9655 result = true;
9656 flags.hasAllDependencies = 1;
9657
9658 finish:
9659
9660 if (addedToLoopStack) {
9661 count = loopStack->getCount();
9662 if (count > 0 && (this == loopStack->getObject(count - 1))) {
9663 loopStack->removeObject(count - 1);
9664 } else {
9665 OSKextLog(this,
9666 kOSKextLogErrorLevel |
9667 kOSKextLogDependenciesFlag,
9668 "Kext %s - internal error resolving dependencies.",
9669 getIdentifierCString());
9670 }
9671 }
9672
9673 if (result && localLoopStack) {
9674 OSKextLog(this,
9675 kOSKextLogStepLevel |
9676 kOSKextLogDependenciesFlag,
9677 "Kext %s successfully resolved dependencies.",
9678 getIdentifierCString());
9679 }
9680
9681 return result;
9682 }
9683
9684 /*********************************************************************
9685 *********************************************************************/
9686 bool
9687 OSKext::addBleedthroughDependencies(OSArray * anArray)
9688 {
9689 bool result = false;
9690 unsigned int dependencyIndex, dependencyCount;
9691
9692 dependencyCount = getNumDependencies();
9693
9694 for (dependencyIndex = 0;
9695 dependencyIndex < dependencyCount;
9696 dependencyIndex++) {
9697 OSKext * dependency = OSDynamicCast(OSKext,
9698 dependencies->getObject(dependencyIndex));
9699 if (!dependency) {
9700 OSKextLog(this,
9701 kOSKextLogErrorLevel |
9702 kOSKextLogDependenciesFlag,
9703 "Kext %s - internal error propagating compatibility dependencies.",
9704 getIdentifierCString());
9705 goto finish;
9706 }
9707 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
9708 anArray->setObject(dependency);
9709 }
9710 dependency->addBleedthroughDependencies(anArray);
9711 }
9712
9713 result = true;
9714
9715 finish:
9716 return result;
9717 }
9718
9719 /*********************************************************************
9720 *********************************************************************/
9721 bool
9722 OSKext::flushDependencies(bool forceFlag)
9723 {
9724 bool result = false;
9725
9726 /* Only clear the dependencies if the kext isn't loaded;
9727 * we need the info for loaded kexts to track references.
9728 */
9729 if (!isLoaded() || forceFlag) {
9730 if (dependencies) {
9731 // xxx - check level
9732 OSKextLog(this,
9733 kOSKextLogProgressLevel |
9734 kOSKextLogDependenciesFlag,
9735 "Kext %s flushing dependencies.",
9736 getIdentifierCString());
9737 dependencies.reset();
9738 }
9739 if (!isKernelComponent()) {
9740 flags.hasAllDependencies = 0;
9741 }
9742 result = true;
9743 }
9744
9745 return result;
9746 }
9747
9748 /*********************************************************************
9749 *********************************************************************/
9750 uint32_t
9751 OSKext::getNumDependencies(void)
9752 {
9753 if (!dependencies) {
9754 return 0;
9755 }
9756 return dependencies->getCount();
9757 }
9758
9759 /*********************************************************************
9760 *********************************************************************/
9761 OSArray *
9762 OSKext::getDependencies(void)
9763 {
9764 return dependencies.get();
9765 }
9766
9767 bool
9768 OSKext::hasDependency(const OSSymbol * depID)
9769 {
9770 bool result __block;
9771
9772 if (depID == getIdentifier()) {
9773 return true;
9774 }
9775 if (!dependencies) {
9776 return false;
9777 }
9778 result = false;
9779 dependencies->iterateObjects(^bool (OSObject * obj) {
9780 OSKext * kext;
9781 kext = OSDynamicCast(OSKext, obj);
9782 if (!kext) {
9783 return false;
9784 }
9785 result = (depID == kext->getIdentifier());
9786 return result;
9787 });
9788 return result;
9789 }
9790
9791 #if PRAGMA_MARK
9792 #pragma mark OSMetaClass Support
9793 #endif
9794 /*********************************************************************
9795 *********************************************************************/
9796 OSReturn
9797 OSKext::addClass(
9798 OSMetaClass * aClass,
9799 uint32_t numClasses)
9800 {
9801 OSReturn result = kOSMetaClassNoInsKModSet;
9802
9803 if (!metaClasses) {
9804 metaClasses = OSSet::withCapacity(numClasses);
9805 if (!metaClasses) {
9806 goto finish;
9807 }
9808 }
9809
9810 if (metaClasses->containsObject(aClass)) {
9811 OSKextLog(this,
9812 kOSKextLogWarningLevel |
9813 kOSKextLogLoadFlag,
9814 "Notice - kext %s has already registered class %s.",
9815 getIdentifierCString(),
9816 aClass->getClassName());
9817 result = kOSReturnSuccess;
9818 goto finish;
9819 }
9820
9821 if (!metaClasses->setObject(aClass)) {
9822 goto finish;
9823 } else {
9824 OSKextLog(this,
9825 kOSKextLogDetailLevel |
9826 kOSKextLogLoadFlag,
9827 "Kext %s registered class %s.",
9828 getIdentifierCString(),
9829 aClass->getClassName());
9830 }
9831
9832 if (!flags.autounloadEnabled) {
9833 const OSMetaClass * metaScan = NULL; // do not release
9834
9835 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9836 if (metaScan == OSTypeID(IOService)) {
9837 OSKextLog(this,
9838 kOSKextLogProgressLevel |
9839 kOSKextLogLoadFlag,
9840 "Kext %s has IOService subclass %s; enabling autounload.",
9841 getIdentifierCString(),
9842 aClass->getClassName());
9843
9844 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9845 break;
9846 }
9847 }
9848 }
9849
9850 notifyAddClassObservers(this, aClass, flags);
9851
9852 result = kOSReturnSuccess;
9853
9854 finish:
9855 if (result != kOSReturnSuccess) {
9856 OSKextLog(this,
9857 kOSKextLogErrorLevel |
9858 kOSKextLogLoadFlag,
9859 "Kext %s failed to register class %s.",
9860 getIdentifierCString(),
9861 aClass->getClassName());
9862 }
9863
9864 return result;
9865 }
9866
9867 /*********************************************************************
9868 *********************************************************************/
9869 OSReturn
9870 OSKext::removeClass(
9871 OSMetaClass * aClass)
9872 {
9873 OSReturn result = kOSMetaClassNoKModSet;
9874
9875 if (!metaClasses) {
9876 goto finish;
9877 }
9878
9879 if (!metaClasses->containsObject(aClass)) {
9880 OSKextLog(this,
9881 kOSKextLogWarningLevel |
9882 kOSKextLogLoadFlag,
9883 "Notice - kext %s asked to unregister unknown class %s.",
9884 getIdentifierCString(),
9885 aClass->getClassName());
9886 result = kOSReturnSuccess;
9887 goto finish;
9888 }
9889
9890 OSKextLog(this,
9891 kOSKextLogDetailLevel |
9892 kOSKextLogLoadFlag,
9893 "Kext %s unregistering class %s.",
9894 getIdentifierCString(),
9895 aClass->getClassName());
9896
9897 metaClasses->removeObject(aClass);
9898
9899 notifyRemoveClassObservers(this, aClass, flags);
9900
9901 result = kOSReturnSuccess;
9902
9903 finish:
9904 if (result != kOSReturnSuccess) {
9905 OSKextLog(this,
9906 kOSKextLogErrorLevel |
9907 kOSKextLogLoadFlag,
9908 "Failed to unregister kext %s class %s.",
9909 getIdentifierCString(),
9910 aClass->getClassName());
9911 }
9912 return result;
9913 }
9914
9915 /*********************************************************************
9916 *********************************************************************/
9917 OSSet *
9918 OSKext::getMetaClasses(void)
9919 {
9920 return metaClasses.get();
9921 }
9922
9923 /*********************************************************************
9924 *********************************************************************/
9925 bool
9926 OSKext::hasOSMetaClassInstances(void)
9927 {
9928 bool result = false;
9929 OSSharedPtr<OSCollectionIterator> classIterator;
9930 OSMetaClass * checkClass = NULL; // do not release
9931
9932 if (!metaClasses) {
9933 goto finish;
9934 }
9935
9936 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9937 if (!classIterator) {
9938 // xxx - log alloc failure?
9939 goto finish;
9940 }
9941 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9942 if (checkClass->getInstanceCount()) {
9943 result = true;
9944 goto finish;
9945 }
9946 }
9947
9948 finish:
9949 return result;
9950 }
9951
9952 /*********************************************************************
9953 *********************************************************************/
9954 /* static */
9955 void
9956 OSKext::reportOSMetaClassInstances(
9957 const char * kextIdentifier,
9958 OSKextLogSpec msgLogSpec)
9959 {
9960 OSSharedPtr<OSKext> theKext;
9961
9962 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9963 if (!theKext) {
9964 goto finish;
9965 }
9966
9967 theKext->reportOSMetaClassInstances(msgLogSpec);
9968 finish:
9969 return;
9970 }
9971
9972 /*********************************************************************
9973 *********************************************************************/
9974 void
9975 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9976 {
9977 OSSharedPtr<OSCollectionIterator> classIterator;
9978 OSMetaClass * checkClass = NULL; // do not release
9979
9980 if (!metaClasses) {
9981 goto finish;
9982 }
9983
9984 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9985 if (!classIterator) {
9986 goto finish;
9987 }
9988 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9989 if (checkClass->getInstanceCount()) {
9990 OSKextLog(this,
9991 msgLogSpec,
9992 " Kext %s class %s has %d instance%s.",
9993 getIdentifierCString(),
9994 checkClass->getClassName(),
9995 checkClass->getInstanceCount(),
9996 checkClass->getInstanceCount() == 1 ? "" : "s");
9997 }
9998 }
9999
10000 finish:
10001 return;
10002 }
10003
10004 #if PRAGMA_MARK
10005 #pragma mark User-Space Requests
10006 #endif
10007
10008 static kern_return_t
10009 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
10010 {
10011 OSReturn result = kOSReturnSuccess;
10012 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
10013 OSDictionary * request = NULL; //do not release
10014 IOUserServerCheckInToken * token = NULL; //do not release
10015 OSString * requestPredicate = NULL; //do not release
10016 OSSharedPtr<OSNumber> portNameNumber;
10017 mach_port_name_t portName = 0;
10018 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
10019 if (!request) {
10020 OSKextLog(/* kext */ NULL,
10021 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10022 "Elements of request should be of type OSDictionary");
10023 result = kOSKextReturnInternalError;
10024 goto finish;
10025 }
10026 requestPredicate = _OSKextGetRequestPredicate(request);
10027 if (!requestPredicate) {
10028 OSKextLog(/* kext */ NULL,
10029 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10030 "Failed to get request predicate");
10031 result = kOSKextReturnInternalError;
10032 goto finish;
10033 }
10034 // is this a dext launch?
10035 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
10036 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
10037 if (!token) {
10038 OSKextLog(/* kext */ NULL,
10039 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10040 "Could not find a IOUserServerCheckInToken in daemon launch request.");
10041 result = kOSKextReturnInternalError;
10042 goto finish;
10043 }
10044 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
10045 if (portName == 0 || portName == MACH_PORT_DEAD) {
10046 OSKextLog(/* kext */ NULL,
10047 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10048 "Could not create send right for object.");
10049 result = kOSKextReturnInternalError;
10050 goto finish;
10051 }
10052 // Store the mach port name as a OSNumber
10053 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
10054 if (!portNameNumber) {
10055 OSKextLog(/* kext */ NULL,
10056 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10057 "Could not create OSNumber object.");
10058 result = kOSKextReturnNoMemory;
10059 goto finish;
10060 }
10061 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
10062 OSKextLog(/* kext */ NULL,
10063 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10064 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
10065 result = kOSKextReturnNoMemory;
10066 goto finish;
10067 }
10068 }
10069 finish:
10070 if (result != kOSReturnSuccess) {
10071 break;
10072 }
10073 }
10074 return result;
10075 }
10076
10077 bool
10078 OSKext::iokitDaemonActive()
10079 {
10080 bool result;
10081 IORecursiveLockLock(sKextLock);
10082 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10083 IORecursiveLockUnlock(sKextLock);
10084 return result;
10085 }
10086
10087 /*********************************************************************
10088 * XXX - this function is a big ugly mess
10089 *********************************************************************/
10090 /* static */
10091 OSReturn
10092 OSKext::handleRequest(
10093 host_priv_t hostPriv,
10094 OSKextLogSpec clientLogFilter,
10095 char * requestBuffer,
10096 uint32_t requestLength,
10097 char ** responseOut,
10098 uint32_t * responseLengthOut,
10099 char ** logInfoOut,
10100 uint32_t * logInfoLengthOut)
10101 {
10102 OSReturn result = kOSReturnError;
10103 kern_return_t kmem_result = KERN_FAILURE;
10104
10105 char * response = NULL; // returned by reference
10106 uint32_t responseLength = 0;
10107
10108 bool taskCanManageAllKCs = false;
10109 bool taskOnlyManagesBootKC = false;
10110
10111 OSSharedPtr<OSObject> parsedXML;
10112 OSDictionary * requestDict = NULL; // do not release
10113 OSSharedPtr<OSString> errorString;
10114
10115 OSSharedPtr<OSObject> responseObject;
10116
10117 OSSharedPtr<OSSerialize> serializer;
10118
10119 OSSharedPtr<OSArray> logInfoArray;
10120
10121 OSString * predicate = NULL; // do not release
10122 OSString * kextIdentifier = NULL; // do not release
10123 OSArray * kextIdentifiers = NULL; // do not release
10124 OSKext * theKext = NULL; // do not release
10125 OSBoolean * boolArg = NULL; // do not release
10126
10127
10128 IORecursiveLockLock(sKextLock);
10129
10130 if (responseOut) {
10131 *responseOut = NULL;
10132 *responseLengthOut = 0;
10133 }
10134 if (logInfoOut) {
10135 *logInfoOut = NULL;
10136 *logInfoLengthOut = 0;
10137 }
10138
10139 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
10140
10141 /* XML must be nul-terminated.
10142 */
10143 if (requestBuffer[requestLength - 1] != '\0') {
10144 OSKextLog(/* kext */ NULL,
10145 kOSKextLogErrorLevel |
10146 kOSKextLogIPCFlag,
10147 "Invalid request from user space (not nul-terminated).");
10148 result = kOSKextReturnBadData;
10149 goto finish;
10150 }
10151 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
10152 if (parsedXML) {
10153 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10154 }
10155 if (!requestDict) {
10156 const char * errorCString = "(unknown error)";
10157
10158 if (errorString && errorString->getCStringNoCopy()) {
10159 errorCString = errorString->getCStringNoCopy();
10160 } else if (parsedXML) {
10161 errorCString = "not a dictionary";
10162 }
10163 OSKextLog(/* kext */ NULL,
10164 kOSKextLogErrorLevel |
10165 kOSKextLogIPCFlag,
10166 "Error unserializing request from user space: %s.",
10167 errorCString);
10168 result = kOSKextReturnSerialization;
10169 goto finish;
10170 }
10171
10172 predicate = _OSKextGetRequestPredicate(requestDict);
10173 if (!predicate) {
10174 OSKextLog(/* kext */ NULL,
10175 kOSKextLogErrorLevel |
10176 kOSKextLogIPCFlag,
10177 "Recieved kext request from user space with no predicate.");
10178 result = kOSKextReturnInvalidArgument;
10179 goto finish;
10180 }
10181 OSKextLog(/* kext */ NULL,
10182 kOSKextLogDebugLevel |
10183 kOSKextLogIPCFlag,
10184 "Received '%s' request from user space.",
10185 predicate->getCStringNoCopy());
10186
10187 /*
10188 * All management of file sets requires an entitlement
10189 */
10190 result = kOSKextReturnNotPrivileged;
10191 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10192 predicate->isEqualTo(kKextRequestPredicateStart) ||
10193 predicate->isEqualTo(kKextRequestPredicateStop) ||
10194 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10195 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10196 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10197 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10198 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10199 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10200 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10201 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10202 if (!iokitDaemonAvailable()) {
10203 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10204 }
10205 if (hostPriv == HOST_PRIV_NULL) {
10206 OSKextLog(/* kext */ NULL,
10207 kOSKextLogErrorLevel |
10208 kOSKextLogIPCFlag,
10209 "Access Failure - must be root user.");
10210 goto finish;
10211 }
10212 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10213 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10214
10215 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10216 OSKextLog(/* kext */ NULL,
10217 kOSKextLogErrorLevel |
10218 kOSKextLogIPCFlag,
10219 "Access Failure - client not entitled to manage file sets.");
10220 goto finish;
10221 }
10222
10223 /*
10224 * The OnlyBootKC entitlement restricts the
10225 * collection-management entitlement to only managing kexts in
10226 * the BootKC. All other predicates that alter global state or
10227 * add new KCs are disallowed.
10228 */
10229 if (taskOnlyManagesBootKC &&
10230 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10231 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10232 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10233 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10234 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10235 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10236 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10237 OSKextLog(/* kext */ NULL,
10238 kOSKextLogErrorLevel |
10239 kOSKextLogIPCFlag,
10240 "Access Failure - client not entitled to manage non-primary KCs");
10241 goto finish;
10242 }
10243
10244 /*
10245 * If we get here, then the process either has the full KC
10246 * management entitlement, or it has the BootKC-only
10247 * entitlement and the request is about the BootKC.
10248 */
10249 }
10250
10251 /* Get common args in anticipation of use.
10252 */
10253 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10254 requestDict, kKextRequestArgumentBundleIdentifierKey));
10255 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10256 requestDict, kKextRequestArgumentBundleIdentifierKey));
10257 if (kextIdentifier) {
10258 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10259 }
10260 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10261 requestDict, kKextRequestArgumentValueKey));
10262
10263 if (taskOnlyManagesBootKC &&
10264 theKext &&
10265 theKext->isInFileset() &&
10266 theKext->kc_type != KCKindPrimary) {
10267 OSKextLog(/* kext */ NULL,
10268 kOSKextLogErrorLevel |
10269 kOSKextLogIPCFlag,
10270 "Access Failure - client not entitled to manage kext in non-primary KC");
10271 result = kOSKextReturnNotPrivileged;
10272 goto finish;
10273 }
10274 result = kOSKextReturnInvalidArgument;
10275
10276 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10277 if (!kextIdentifier) {
10278 OSKextLog(/* kext */ NULL,
10279 kOSKextLogErrorLevel |
10280 kOSKextLogIPCFlag,
10281 "Invalid arguments to kext start request.");
10282 } else if (!theKext) {
10283 OSKextLog(/* kext */ NULL,
10284 kOSKextLogErrorLevel |
10285 kOSKextLogIPCFlag,
10286 "Kext %s not found for start request.",
10287 kextIdentifier->getCStringNoCopy());
10288 result = kOSKextReturnNotFound;
10289 } else {
10290 result = theKext->start();
10291 }
10292 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10293 if (!kextIdentifier) {
10294 OSKextLog(/* kext */ NULL,
10295 kOSKextLogErrorLevel |
10296 kOSKextLogIPCFlag,
10297 "Invalid arguments to kext stop request.");
10298 } else if (!theKext) {
10299 OSKextLog(/* kext */ NULL,
10300 kOSKextLogErrorLevel |
10301 kOSKextLogIPCFlag,
10302 "Kext %s not found for stop request.",
10303 kextIdentifier->getCStringNoCopy());
10304 result = kOSKextReturnNotFound;
10305 } else {
10306 result = theKext->stop();
10307 }
10308 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10309 result = OSKext::setMissingAuxKCBundles(requestDict);
10310 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10311 if (!kextIdentifier) {
10312 OSKextLog(/* kext */ NULL,
10313 kOSKextLogErrorLevel |
10314 kOSKextLogIPCFlag,
10315 "Invalid arguments to AuxKC Bundle Available request.");
10316 } else {
10317 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10318 }
10319 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10320 if (!kextIdentifier) {
10321 OSKextLog(/* kext */ NULL,
10322 kOSKextLogErrorLevel |
10323 kOSKextLogIPCFlag,
10324 "Invalid arguments to kext load from KC request.");
10325 } else if (!theKext) {
10326 OSKextLog(/* kext */ NULL,
10327 kOSKextLogErrorLevel |
10328 kOSKextLogIPCFlag,
10329 "Kext %s not found for load from KC request.",
10330 kextIdentifier->getCStringNoCopy());
10331 result = kOSKextReturnNotFound;
10332 } else if (!theKext->isInFileset()) {
10333 OSKextLog(/* kext */ NULL,
10334 kOSKextLogErrorLevel |
10335 kOSKextLogIPCFlag,
10336 "Kext %s does not exist in a KC: refusing to load.",
10337 kextIdentifier->getCStringNoCopy());
10338 result = kOSKextReturnNotLoadable;
10339 } else {
10340 result = OSKext::loadKextFromKC(theKext, requestDict);
10341 }
10342 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10343 if (!kextIdentifier) {
10344 OSKextLog(/* kext */ NULL,
10345 kOSKextLogErrorLevel |
10346 kOSKextLogIPCFlag,
10347 "Invalid arguments to codeless kext load interface (missing identifier).");
10348 } else {
10349 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10350 }
10351 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10352 if (!kextIdentifier) {
10353 OSKextLog(/* kext */ NULL,
10354 kOSKextLogErrorLevel |
10355 kOSKextLogIPCFlag,
10356 "Invalid arguments to kext unload request.");
10357 } else if (!theKext) {
10358 OSKextLog(/* kext */ NULL,
10359 kOSKextLogErrorLevel |
10360 kOSKextLogIPCFlag,
10361 "Kext %s not found for unload request.",
10362 kextIdentifier->getCStringNoCopy());
10363 result = kOSKextReturnNotFound;
10364 } else {
10365 if (theKext->isDriverKit()) {
10366 result = OSKext::removeDext(theKext);
10367 } else {
10368 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10369 _OSKextGetRequestArgument(requestDict,
10370 kKextRequestArgumentTerminateIOServicesKey));
10371 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
10372 }
10373 }
10374 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10375 result = OSKext::dispatchResource(requestDict);
10376 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10377 OSNumber *lookupNum = NULL;
10378 lookupNum = OSDynamicCast(OSNumber,
10379 _OSKextGetRequestArgument(requestDict,
10380 kKextRequestArgumentLookupAddressKey));
10381
10382 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
10383 if (responseObject) {
10384 result = kOSReturnSuccess;
10385 } else {
10386 goto finish;
10387 }
10388 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10389 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10390 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10391 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10392 OSBoolean * delayAutounloadBool = NULL;
10393 OSObject * infoKeysRaw = NULL;
10394 OSArray * infoKeys = NULL;
10395 uint32_t infoKeysCount = 0;
10396
10397 delayAutounloadBool = OSDynamicCast(OSBoolean,
10398 _OSKextGetRequestArgument(requestDict,
10399 kKextRequestArgumentDelayAutounloadKey));
10400
10401 /* If asked to delay autounload, reset the timer if it's currently set.
10402 * (That is, don't schedule an unload if one isn't already pending.
10403 */
10404 if (delayAutounloadBool == kOSBooleanTrue) {
10405 OSKext::considerUnloads(/* rescheduleOnly? */ true);
10406 }
10407
10408 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10409 kKextRequestArgumentInfoKeysKey);
10410 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10411 if (infoKeysRaw && !infoKeys) {
10412 OSKextLog(/* kext */ NULL,
10413 kOSKextLogErrorLevel |
10414 kOSKextLogIPCFlag,
10415 "Invalid arguments to kext info request.");
10416 goto finish;
10417 }
10418
10419 if (infoKeys) {
10420 infoKeysCount = infoKeys->getCount();
10421 for (uint32_t i = 0; i < infoKeysCount; i++) {
10422 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10423 OSKextLog(/* kext */ NULL,
10424 kOSKextLogErrorLevel |
10425 kOSKextLogIPCFlag,
10426 "Invalid arguments to kext info request.");
10427 goto finish;
10428 }
10429 }
10430 }
10431
10432 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10433 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
10434 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10435 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
10436 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10437 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10438 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10439 responseObject = OSKext::copyDextsInfo(kextIdentifiers, infoKeys);
10440 }
10441
10442 if (!responseObject) {
10443 result = kOSKextReturnInternalError;
10444 } else {
10445 OSKextLog(/* kext */ NULL,
10446 kOSKextLogDebugLevel |
10447 kOSKextLogIPCFlag,
10448 "Returning loaded kext info.");
10449 result = kOSReturnSuccess;
10450 }
10451 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10452 /* Hand the current sKernelRequests array to the caller
10453 * (who must release it), and make a new one.
10454 */
10455 responseObject = os::move(sKernelRequests);
10456 sKernelRequests = OSArray::withCapacity(0);
10457 sPostedKextLoadIdentifiers->flushCollection();
10458 OSKextLog(/* kext */ NULL,
10459 kOSKextLogDebugLevel |
10460 kOSKextLogIPCFlag,
10461 "Returning kernel requests.");
10462 result = kOSReturnSuccess;
10463 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10464 /* Return the set of all requested bundle identifiers */
10465 responseObject = sAllKextLoadIdentifiers;
10466 OSKextLog(/* kext */ NULL,
10467 kOSKextLogDebugLevel |
10468 kOSKextLogIPCFlag,
10469 "Returning load requests.");
10470 result = kOSReturnSuccess;
10471 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10472 printf("KextLog: Loading FileSet KC(s)\n");
10473 result = OSKext::loadFileSetKexts(requestDict);
10474 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10475 bool active = iokitDaemonActive();
10476 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10477 if (sOSKextWasResetAfterUserspaceReboot) {
10478 printf("KextLog: was reset after userspace reboot\n");
10479 }
10480 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10481 } else {
10482 OSKextLog(/* kext */ NULL,
10483 kOSKextLogDebugLevel |
10484 kOSKextLogIPCFlag,
10485 "Received '%s' invalid request from user space.",
10486 predicate->getCStringNoCopy());
10487 goto finish;
10488 }
10489
10490 /**********
10491 * Now we have handle the request, or not. Gather up the response & logging
10492 * info to ship to user space.
10493 *********/
10494
10495 /* Note: Nothing in OSKext is supposed to retain requestDict,
10496 * but you never know....
10497 */
10498 if (requestDict->getRetainCount() > 1) {
10499 OSKextLog(/* kext */ NULL,
10500 kOSKextLogWarningLevel |
10501 kOSKextLogIPCFlag,
10502 "Request from user space still retained by a kext; "
10503 "probable memory leak.");
10504 }
10505
10506 if (responseOut && responseObject) {
10507 serializer = OSSerialize::withCapacity(0);
10508 if (!serializer) {
10509 result = kOSKextReturnNoMemory;
10510 goto finish;
10511 }
10512 /*
10513 * Before serializing the kernel requests, patch the dext launch requests so
10514 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10515 * IOUserServerCheckInToken kernel object.
10516 */
10517 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10518 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10519 task_t calling_task = current_task();
10520 if (!requests) {
10521 OSKextLog(/* kext */ NULL,
10522 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10523 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10524 result = kOSKextReturnInternalError;
10525 goto finish;
10526 }
10527 result = patchDextLaunchRequests(calling_task, requests);
10528 if (result != kOSReturnSuccess) {
10529 OSKextLog(/* kext */ NULL,
10530 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10531 "Failed to patch dext launch requests.");
10532 goto finish;
10533 }
10534 }
10535
10536 if (!responseObject->serialize(serializer.get())) {
10537 OSKextLog(/* kext */ NULL,
10538 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10539 "Failed to serialize response to request from user space.");
10540 result = kOSKextReturnSerialization;
10541 goto finish;
10542 }
10543
10544 response = (char *)serializer->text();
10545 responseLength = serializer->getLength();
10546 }
10547
10548 if (responseOut && response) {
10549 char * buffer;
10550
10551 /* This kmem_alloc sets the return value of the function.
10552 */
10553 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
10554 round_page(responseLength), KMA_DATA, VM_KERN_MEMORY_OSKEXT);
10555 if (kmem_result != KERN_SUCCESS) {
10556 OSKextLog(/* kext */ NULL,
10557 kOSKextLogErrorLevel |
10558 kOSKextLogIPCFlag,
10559 "Failed to copy response to request from user space.");
10560 result = kmem_result;
10561 goto finish;
10562 } else {
10563 /* 11981737 - clear uninitialized data in last page */
10564 bzero((void *)(buffer + responseLength),
10565 (round_page(responseLength) - responseLength));
10566 memcpy(buffer, response, responseLength);
10567 *responseOut = buffer;
10568 *responseLengthOut = responseLength;
10569 }
10570 }
10571
10572 finish:
10573
10574 /* Gather up the collected log messages for user space. Any messages
10575 * messages past this call will not make it up as log messages but
10576 * will be in the system log. Note that we ignore the return of the
10577 * serialize; it has no bearing on the operation at hand even if we
10578 * fail to get the log messages.
10579 */
10580 logInfoArray = OSKext::clearUserSpaceLogFilter();
10581
10582 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10583 (void)OSKext::serializeLogInfo(logInfoArray.get(),
10584 logInfoOut, logInfoLengthOut);
10585 }
10586
10587 IORecursiveLockUnlock(sKextLock);
10588
10589 return result;
10590 }
10591
10592 #if PRAGMA_MARK
10593 #pragma mark Linked Kext Collection Support
10594 #endif
10595
10596 static int
10597 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10598 {
10599 for (int i = 0; i < segCount; i++) {
10600 vm_offset_t segStart = segAddrs[i];
10601 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10602
10603 if (theAddr >= segStart && theAddr < segEnd) {
10604 return i;
10605 }
10606 }
10607 return -1;
10608 }
10609
10610 static void
10611 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
10612 kernel_segment_command_t *kextTextSeg,
10613 OSData *kaslrOffsets)
10614 {
10615 static const char *plk_segNames[] = {
10616 "__TEXT",
10617 "__TEXT_EXEC",
10618 "__DATA",
10619 "__DATA_CONST",
10620 "__LINKEDIT",
10621 "__PRELINK_TEXT",
10622 "__PLK_TEXT_EXEC",
10623 "__PRELINK_DATA",
10624 "__PLK_DATA_CONST",
10625 "__PLK_LLVM_COV",
10626 "__PLK_LINKEDIT",
10627 "__PRELINK_INFO"
10628 };
10629 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10630
10631 unsigned long plk_segSizes[num_plk_seg];
10632 vm_offset_t plk_segAddrs[num_plk_seg];
10633
10634 for (size_t i = 0; i < num_plk_seg; i++) {
10635 plk_segSizes[i] = 0;
10636 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10637 }
10638
10639 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10640
10641 int slidKextAddrCount = 0;
10642 int badSlideAddr = 0;
10643 int badSlideTarget = 0;
10644
10645 struct kaslrPackedOffsets {
10646 uint32_t count; /* number of offsets */
10647 uint32_t offsetsArray[]; /* offsets to slide */
10648 };
10649 const struct kaslrPackedOffsets *myOffsets = NULL;
10650 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10651
10652 for (uint32_t j = 0; j < myOffsets->count; j++) {
10653 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10654 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10655 int slideAddrSegIndex = -1;
10656 int addrToSlideSegIndex = -1;
10657
10658 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10659 if (slideAddrSegIndex >= 0) {
10660 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10661 if (addrToSlideSegIndex < 0) {
10662 badSlideTarget++;
10663 continue;
10664 }
10665 } else {
10666 badSlideAddr++;
10667 continue;
10668 }
10669
10670 slidKextAddrCount++;
10671 *slideAddr = ml_static_slide(*slideAddr);
10672 } // for ...
10673 }
10674
10675
10676
10677 /********************************************************************
10678 * addKextsFromKextCollection
10679 *
10680 * Input: MachO header of kext collection. The MachO is assumed to
10681 * have a section named 'info_seg_name,info_sect_name' that
10682 * contains a serialized XML info dictionary. This dictionary
10683 * contains a UUID, possibly a set of relocations (for older
10684 * kxld-built binaries), and an array of kext personalities.
10685 *
10686 ********************************************************************/
10687 bool
10688 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10689 OSDictionary *infoDict, const char *text_seg_name,
10690 OSData **kcUUID, kc_kind_t type)
10691 {
10692 bool result = false;
10693
10694 OSArray *kextArray = NULL; // do not release
10695 OSData *infoDictKCUUID = NULL; // do not release
10696 OSData *kaslrOffsets = NULL; // do not release
10697
10698 IORegistryEntry *registryRoot = NULL; // do not release
10699 OSSharedPtr<OSNumber> kcKextCount;
10700
10701 /* extract the KC UUID from the dictionary */
10702 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10703 if (infoDictKCUUID) {
10704 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10705 panic("kcUUID length is %d, expected %lu",
10706 infoDictKCUUID->getLength(), sizeof(uuid_t));
10707 }
10708 }
10709
10710 /* locate the array of kext dictionaries */
10711 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10712 if (!kextArray) {
10713 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10714 "The given KC has no kext info dictionaries");
10715 goto finish;
10716 }
10717
10718 /*
10719 * old-style KASLR offsets may be present in the info dictionary. If
10720 * we find them, use them and eventually slide them.
10721 */
10722 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10723
10724 /*
10725 * Before processing any kexts, locate the special kext bundle which
10726 * contains a list of kexts that we are to prevent from loading.
10727 */
10728 createExcludeListFromPrelinkInfo(kextArray);
10729
10730 /*
10731 * Create OSKext objects for each kext we find in the array of kext
10732 * info plist dictionaries.
10733 */
10734 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10735 OSDictionary *kextDict = NULL;
10736 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10737 if (!kextDict) {
10738 OSKextLog(/* kext */ NULL,
10739 kOSKextLogErrorLevel |
10740 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10741 "Kext info dictionary for kext #%d isn't a dictionary?", i);
10742 continue;
10743 }
10744
10745 /*
10746 * Create the kext for the entry, then release it, because the
10747 * kext system keeps a reference around until the kext is
10748 * explicitly removed. Any creation/registration failures are
10749 * already logged for us.
10750 */
10751 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
10752 }
10753
10754 /*
10755 * slide old-style kxld relocations
10756 * NOTE: this is still used on embedded KCs built with kcgen
10757 * TODO: Remove this once we use the new kext linker everywhere!
10758 */
10759 if (kaslrOffsets && vm_kernel_slide > 0) {
10760 kernel_segment_command_t *text_segment = NULL;
10761 text_segment = getsegbynamefromheader(mh, text_seg_name);
10762 if (!text_segment) {
10763 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10764 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10765 goto finish;
10766 }
10767
10768 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
10769 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10770 setAllVMAttributes();
10771 }
10772
10773 /* Store the number of prelinked kexts in the registry so we can tell
10774 * when the system has been started from a prelinked kernel.
10775 */
10776 registryRoot = IORegistryEntry::getRegistryRoot();
10777 assert(registryRoot);
10778
10779 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10780 assert(kcKextCount);
10781 if (kcKextCount) {
10782 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10783 OSNumber *num;
10784 num = OSDynamicCast(OSNumber, prop.get());
10785 if (num) {
10786 kcKextCount->addValue(num->unsigned64BitValue());
10787 }
10788 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10789 }
10790
10791 OSKextLog(/* kext */ NULL,
10792 kOSKextLogProgressLevel |
10793 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10794 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10795 "%u prelinked kexts", infoDict->getCount());
10796
10797
10798 if (kcUUID && infoDictKCUUID) {
10799 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10800 }
10801
10802 result = true;
10803
10804 finish:
10805 return result;
10806 }
10807
10808 bool
10809 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10810 OSDictionary *infoDict, const char *text_seg_name,
10811 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10812 {
10813 OSData *result = NULL;
10814 bool success = addKextsFromKextCollection(mh,
10815 infoDict,
10816 text_seg_name,
10817 &result,
10818 type);
10819 if (success) {
10820 kcUUID.reset(result, OSNoRetain);
10821 }
10822 return success;
10823 }
10824
10825 static OSSharedPtr<OSObject> deferredAuxKCXML;
10826 bool
10827 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10828 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10829 {
10830 if (type != KCKindAuxiliary) {
10831 return false;
10832 }
10833
10834 kernel_mach_header_t *_mh;
10835 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
10836 if (!_mh || _mh != mh) {
10837 return false;
10838 }
10839
10840 if (deferredAuxKCXML) {
10841 /* only allow this to be called once */
10842 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10843 "An Aux KC has already been registered for deferred processing.");
10844 return false;
10845 }
10846
10847 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
10848 if (!infoDict) {
10849 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10850 "The Aux KC has info dictionary");
10851 return false;
10852 }
10853
10854 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10855 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10856 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10857 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10858 return false;
10859 }
10860
10861 /*
10862 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10863 * sysctl can return the UUID to user space which will check this
10864 * value for errors.
10865 */
10866 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10867 kcUUID->getLength());
10868 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10869 auxkc_uuid_valid = TRUE;
10870
10871 deferredAuxKCXML = parsedXML;
10872
10873 return true;
10874 }
10875
10876 OSSharedPtr<OSObject>
10877 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10878 {
10879 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10880 return NULL;
10881 }
10882
10883 return os::move(deferredAuxKCXML);
10884 }
10885
10886 #if PRAGMA_MARK
10887 #pragma mark Profile-Guided-Optimization Support
10888 #endif
10889
10890 // #include <InstrProfiling.h>
10891 extern "C" {
10892 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10893 const char *DataEnd,
10894 const char *CountersBegin,
10895 const char *CountersEnd,
10896 const char *NamesBegin,
10897 const char *NamesEnd);
10898 int __llvm_profile_write_buffer_internal(char *Buffer,
10899 const char *DataBegin,
10900 const char *DataEnd,
10901 const char *CountersBegin,
10902 const char *CountersEnd,
10903 const char *NamesBegin,
10904 const char *NamesEnd);
10905 }
10906
10907
10908 static
10909 void
10910 OSKextPgoMetadataPut(char *pBuffer,
10911 size_t *position,
10912 size_t bufferSize,
10913 uint32_t *num_pairs,
10914 const char *key,
10915 const char *value)
10916 {
10917 size_t strlen_key = strlen(key);
10918 size_t strlen_value = strlen(value);
10919 size_t len = strlen(key) + 1 + strlen(value) + 1;
10920 char *pos = pBuffer + *position;
10921 *position += len;
10922 if (pBuffer && bufferSize && *position <= bufferSize) {
10923 memcpy(pos, key, strlen_key); pos += strlen_key;
10924 *(pos++) = '=';
10925 memcpy(pos, value, strlen_value); pos += strlen_value;
10926 *(pos++) = 0;
10927 if (num_pairs) {
10928 (*num_pairs)++;
10929 }
10930 }
10931 }
10932
10933
10934 static
10935 void
10936 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10937 {
10938 *position += strlen(key) + 1 + value_max + 1;
10939 }
10940
10941
10942 static
10943 void
10944 OSKextPgoMetadataPutAll(OSKext *kext,
10945 uuid_t instance_uuid,
10946 char *pBuffer,
10947 size_t *position,
10948 size_t bufferSize,
10949 uint32_t *num_pairs)
10950 {
10951 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10952 //log_10 2^16 ≈ 4.82
10953 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10954 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10955
10956 if (!pBuffer) {
10957 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10958 OSKextPgoMetadataPutMax(position, "UUID", 36);
10959 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10960 } else {
10961 uuid_string_t instance_uuid_string;
10962 uuid_unparse(instance_uuid, instance_uuid_string);
10963 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10964 "INSTANCE", instance_uuid_string);
10965
10966 OSSharedPtr<OSData> uuid_data;
10967 uuid_t uuid;
10968 uuid_string_t uuid_string;
10969 uuid_data = kext->copyUUID();
10970 if (uuid_data) {
10971 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10972 uuid_unparse(uuid, uuid_string);
10973 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10974 "UUID", uuid_string);
10975 }
10976
10977 clock_sec_t secs;
10978 clock_usec_t usecs;
10979 clock_get_calendar_microtime(&secs, &usecs);
10980 assert(usecs < 1000000);
10981 char timestamp[max_timestamp_string_size + 1];
10982 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10983 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10984 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10985 "TIMESTAMP", timestamp);
10986 }
10987
10988 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10989 "NAME", kext->getIdentifierCString());
10990
10991 char versionCString[kOSKextVersionMaxLength];
10992 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10993 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10994 "VERSION", versionCString);
10995 }
10996
10997 static
10998 size_t
10999 OSKextPgoMetadataSize(OSKext *kext)
11000 {
11001 size_t position = 0;
11002 uuid_t fakeuuid = {};
11003 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
11004 return position;
11005 }
11006
11007 int
11008 OSKextGrabPgoDataLocked(OSKext *kext,
11009 bool metadata,
11010 uuid_t instance_uuid,
11011 uint64_t *pSize,
11012 char *pBuffer,
11013 uint64_t bufferSize)
11014 {
11015 int err = 0;
11016
11017 kernel_section_t *sect_prf_data = NULL;
11018 kernel_section_t *sect_prf_name = NULL;
11019 kernel_section_t *sect_prf_cnts = NULL;
11020 uint64_t size;
11021 size_t metadata_size = 0;
11022 size_t offset_to_pairs = 0;
11023
11024 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
11025 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
11026 if (!sect_prf_name) {
11027 // kextcache sometimes truncates the section name to 15 chars
11028 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
11029 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
11030 }
11031 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11032
11033 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
11034 err = ENOTSUP;
11035 goto out;
11036 }
11037
11038 size = __llvm_profile_get_size_for_buffer_internal(
11039 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11040 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11041 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11042
11043 if (metadata) {
11044 metadata_size = OSKextPgoMetadataSize(kext);
11045 size += metadata_size;
11046 size += sizeof(pgo_metadata_footer);
11047 }
11048
11049
11050 if (pSize) {
11051 *pSize = size;
11052 }
11053
11054 if (pBuffer && bufferSize) {
11055 if (bufferSize < size) {
11056 err = ERANGE;
11057 goto out;
11058 }
11059
11060 err = __llvm_profile_write_buffer_internal(
11061 pBuffer,
11062 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11063 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11064 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11065
11066 if (err) {
11067 err = EIO;
11068 goto out;
11069 }
11070
11071 if (metadata) {
11072 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11073 if (offset_to_pairs > UINT32_MAX) {
11074 err = E2BIG;
11075 goto out;
11076 }
11077
11078 char *end_of_buffer = pBuffer + size;
11079 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11080 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11081
11082 size_t metadata_position = 0;
11083 uint32_t num_pairs = 0;
11084 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
11085 while (metadata_position < metadata_size) {
11086 metadata_buffer[metadata_position++] = 0;
11087 }
11088
11089 struct pgo_metadata_footer footer;
11090 footer.magic = htonl(0x6d657461);
11091 footer.number_of_pairs = htonl( num_pairs );
11092 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11093 memcpy(footerp, &footer, sizeof(footer));
11094 }
11095 }
11096
11097 out:
11098 return err;
11099 }
11100
11101
11102 int
11103 OSKextGrabPgoData(uuid_t uuid,
11104 uint64_t *pSize,
11105 char *pBuffer,
11106 uint64_t bufferSize,
11107 int wait_for_unload,
11108 int metadata)
11109 {
11110 int err = 0;
11111 OSSharedPtr<OSKext> kext;
11112
11113
11114 IORecursiveLockLock(sKextLock);
11115
11116 kext = OSKext::lookupKextWithUUID(uuid);
11117 if (!kext) {
11118 err = ENOENT;
11119 goto out;
11120 }
11121
11122 if (wait_for_unload) {
11123 OSKextGrabPgoStruct s;
11124
11125 s.metadata = metadata;
11126 s.pSize = pSize;
11127 s.pBuffer = pBuffer;
11128 s.bufferSize = bufferSize;
11129 s.err = EINTR;
11130
11131 struct list_head *prev = &kext->pendingPgoHead;
11132 struct list_head *next = kext->pendingPgoHead.next;
11133
11134 s.list_head.prev = prev;
11135 s.list_head.next = next;
11136
11137 prev->next = &s.list_head;
11138 next->prev = &s.list_head;
11139
11140 kext.reset();
11141
11142 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
11143
11144 prev = s.list_head.prev;
11145 next = s.list_head.next;
11146
11147 prev->next = next;
11148 next->prev = prev;
11149
11150 err = s.err;
11151 } else {
11152 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
11153 }
11154
11155 out:
11156
11157 IORecursiveLockUnlock(sKextLock);
11158
11159 return err;
11160 }
11161
11162 void
11163 OSKextResetPgoCountersLock()
11164 {
11165 IORecursiveLockLock(sKextLock);
11166 }
11167
11168 void
11169 OSKextResetPgoCountersUnlock()
11170 {
11171 IORecursiveLockUnlock(sKextLock);
11172 }
11173
11174
11175 extern unsigned int not_in_kdp;
11176
11177 void
11178 OSKextResetPgoCounters()
11179 {
11180 assert(!not_in_kdp);
11181 uint32_t count = sLoadedKexts->getCount();
11182 for (uint32_t i = 0; i < count; i++) {
11183 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11184 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11185 if (!sect_prf_cnts) {
11186 continue;
11187 }
11188 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
11189 }
11190 }
11191
11192 OSSharedPtr<OSDictionary>
11193 OSKext::copyLoadedKextInfoByUUID(
11194 OSArray * kextIdentifiers,
11195 OSArray * infoKeys)
11196 {
11197 OSSharedPtr<OSDictionary> result;
11198 OSSharedPtr<OSDictionary> kextInfo;
11199 uint32_t max_count, i, j;
11200 uint32_t idCount = 0;
11201 uint32_t idIndex = 0;
11202 IORecursiveLockLock(sKextLock);
11203 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11204 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11205
11206 #if CONFIG_MACF
11207 /* Is the calling process allowed to query kext info? */
11208 if (current_task() != kernel_task) {
11209 int macCheckResult = 0;
11210 kauth_cred_t cred = NULL;
11211
11212 cred = kauth_cred_get_with_ref();
11213 macCheckResult = mac_kext_check_query(cred);
11214 kauth_cred_unref(&cred);
11215
11216 if (macCheckResult != 0) {
11217 OSKextLog(/* kext */ NULL,
11218 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11219 "Failed to query kext info (MAC policy error 0x%x).",
11220 macCheckResult);
11221 goto finish;
11222 }
11223 }
11224 #endif
11225
11226 /* Empty list of UUIDs is equivalent to no list (get all).
11227 */
11228 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11229 kextIdentifiers = NULL;
11230 } else if (kextIdentifiers) {
11231 idCount = kextIdentifiers->getCount();
11232 }
11233
11234 /* Same for keys.
11235 */
11236 if (infoKeys && !infoKeys->getCount()) {
11237 infoKeys = NULL;
11238 }
11239
11240 max_count = count[0] + count[1];
11241 result = OSDictionary::withCapacity(max_count);
11242 if (!result) {
11243 goto finish;
11244 }
11245
11246 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11247 for (i = 0; i < count[j]; i++) {
11248 OSKext *thisKext = NULL; // do not release
11249 Boolean includeThis = true;
11250 uuid_t thisKextUUID;
11251 uuid_t thisKextTextUUID;
11252 OSSharedPtr<OSData> uuid_data;
11253 uuid_string_t uuid_key;
11254
11255 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11256 if (!thisKext) {
11257 continue;
11258 }
11259
11260 uuid_data = thisKext->copyUUID();
11261 if (!uuid_data) {
11262 continue;
11263 }
11264
11265 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
11266
11267 uuid_unparse(thisKextUUID, uuid_key);
11268
11269 uuid_data = thisKext->copyTextUUID();
11270 if (!uuid_data) {
11271 continue;
11272 }
11273 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
11274
11275 /* Skip current kext if we have a list of UUIDs and
11276 * it isn't in the list.
11277 */
11278 if (kextIdentifiers) {
11279 includeThis = false;
11280
11281 for (idIndex = 0; idIndex < idCount; idIndex++) {
11282 const OSString* wantedUUID = OSDynamicCast(OSString,
11283 kextIdentifiers->getObject(idIndex));
11284
11285 uuid_t uuid;
11286 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
11287
11288 if ((0 == uuid_compare(uuid, thisKextUUID))
11289 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
11290 includeThis = true;
11291 /* Only need to find the first kext if multiple match,
11292 * ie. asking for the kernel uuid does not need to find
11293 * interface kexts or builtin static kexts.
11294 */
11295 kextIdentifiers->removeObject(idIndex);
11296 uuid_unparse(uuid, uuid_key);
11297 break;
11298 }
11299 }
11300 }
11301
11302 if (!includeThis) {
11303 continue;
11304 }
11305
11306 kextInfo = thisKext->copyInfo(infoKeys);
11307 if (kextInfo) {
11308 result->setObject(uuid_key, kextInfo.get());
11309 }
11310
11311 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11312 goto finish;
11313 }
11314 }
11315 }
11316
11317 finish:
11318 IORecursiveLockUnlock(sKextLock);
11319
11320 return result;
11321 }
11322
11323 /*********************************************************************
11324 *********************************************************************/
11325 /* static */
11326 OSSharedPtr<OSDictionary>
11327 OSKext::copyKextCollectionInfo(
11328 OSDictionary *requestDict,
11329 OSArray *infoKeys)
11330 {
11331 OSSharedPtr<OSDictionary> result;
11332 OSString *collectionType = NULL;
11333 OSObject *rawLoadedState = NULL;
11334 OSString *loadedState = NULL;
11335
11336 kc_kind_t kc_request_kind = KCKindUnknown;
11337 bool onlyLoaded = false;
11338 bool onlyUnloaded = false;
11339
11340 #if CONFIG_MACF
11341 /* Is the calling process allowed to query kext info? */
11342 if (current_task() != kernel_task) {
11343 int macCheckResult = 0;
11344 kauth_cred_t cred = NULL;
11345
11346 cred = kauth_cred_get_with_ref();
11347 macCheckResult = mac_kext_check_query(cred);
11348 kauth_cred_unref(&cred);
11349
11350 if (macCheckResult != 0) {
11351 OSKextLog(/* kext */ NULL,
11352 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11353 "Failed to query kext info (MAC policy error 0x%x).",
11354 macCheckResult);
11355 goto finish;
11356 }
11357 }
11358 #endif
11359
11360 if (infoKeys && !infoKeys->getCount()) {
11361 infoKeys = NULL;
11362 }
11363
11364 collectionType = OSDynamicCast(OSString,
11365 _OSKextGetRequestArgument(requestDict,
11366 kKextRequestArgumentCollectionTypeKey));
11367 if (!collectionType) {
11368 OSKextLog(/* kext */ NULL,
11369 kOSKextLogErrorLevel |
11370 kOSKextLogIPCFlag,
11371 "Invalid '%s' argument to kext collection info request.",
11372 kKextRequestArgumentCollectionTypeKey);
11373 goto finish;
11374 }
11375 if (collectionType->isEqualTo(kKCTypePrimary)) {
11376 kc_request_kind = KCKindPrimary;
11377 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11378 kc_request_kind = KCKindPageable;
11379 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11380 kc_request_kind = KCKindAuxiliary;
11381 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11382 kc_request_kind = KCKindNone;
11383 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11384 OSKextLog(/* kext */ NULL,
11385 kOSKextLogErrorLevel |
11386 kOSKextLogIPCFlag,
11387 "Invalid '%s' argument value '%s' to kext collection info request.",
11388 kKextRequestArgumentCollectionTypeKey,
11389 collectionType->getCStringNoCopy());
11390 goto finish;
11391 }
11392
11393 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11394 kKextRequestArgumentLoadedStateKey);
11395 if (rawLoadedState) {
11396 loadedState = OSDynamicCast(OSString, rawLoadedState);
11397 if (!loadedState) {
11398 OSKextLog(/* kext */ NULL,
11399 kOSKextLogErrorLevel |
11400 kOSKextLogIPCFlag,
11401 "Invalid '%s' argument to kext collection info request.",
11402 kKextRequestArgumentLoadedStateKey);
11403 goto finish;
11404 }
11405 }
11406 if (loadedState) {
11407 if (loadedState->isEqualTo("Loaded")) {
11408 onlyLoaded = true;
11409 } else if (loadedState->isEqualTo("Unloaded")) {
11410 onlyUnloaded = true;
11411 } else if (!loadedState->isEqualTo("Any")) {
11412 OSKextLog(/* kext */ NULL,
11413 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11414 "Invalid '%s' argument value '%s' for '%s' collection info",
11415 kKextRequestArgumentLoadedStateKey,
11416 loadedState->getCStringNoCopy(),
11417 collectionType->getCStringNoCopy());
11418 goto finish;
11419 }
11420 }
11421
11422 result = OSDictionary::withCapacity(sKextsByID->getCount());
11423 if (!result) {
11424 goto finish;
11425 }
11426
11427 IORecursiveLockLock(sKextLock);
11428 { // start block scope
11429 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11430 {
11431 OSKext *thisKext = NULL; // do not release
11432 OSSharedPtr<OSDictionary> kextInfo;
11433
11434 (void)thisKextID;
11435
11436 thisKext = OSDynamicCast(OSKext, obj);
11437 if (!thisKext) {
11438 return false;
11439 }
11440
11441 /*
11442 * skip the kext if it came from the wrong collection type
11443 * (and the caller requested a specific type)
11444 */
11445 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11446 return false;
11447 }
11448
11449 /*
11450 * respect the caller's desire to find only loaded or
11451 * unloaded kexts
11452 */
11453 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11454 return false;
11455 }
11456 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11457 return false;
11458 }
11459
11460 kextInfo = thisKext->copyInfo(infoKeys);
11461 if (kextInfo) {
11462 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11463 }
11464 return false;
11465 });
11466 } // end block scope
11467 IORecursiveLockUnlock(sKextLock);
11468
11469 finish:
11470 return result;
11471 }
11472
11473 /* static */
11474 OSSharedPtr<OSArray>
11475 OSKext::copyDextsInfo(
11476 OSArray *kextIdentifiers,
11477 OSArray *infoKeys)
11478 {
11479 OSSharedPtr<OSArray> result = NULL;
11480 uint32_t idCount = 0;
11481 bool getActive = false;
11482 bool getLoaded = false;
11483 bool getUnloaded = false;
11484 bool getPendingUpgrade = false;
11485 unsigned int avgDextCount = 0;
11486
11487 #if CONFIG_MACF
11488 /* Is the calling process allowed to query dext info? */
11489 if (current_task() != kernel_task) {
11490 int macCheckResult = 0;
11491 kauth_cred_t cred = NULL;
11492
11493 cred = kauth_cred_get_with_ref();
11494 macCheckResult = mac_kext_check_query(cred);
11495 kauth_cred_unref(&cred);
11496
11497 if (macCheckResult != 0) {
11498 OSKextLog(/* kext */ NULL,
11499 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11500 "Failed to query kext info (MAC policy error 0x%x).",
11501 macCheckResult);
11502 goto finish;
11503 }
11504 }
11505 #endif
11506 /*
11507 * No infoKeys means return everything we
11508 * know about the dexts.
11509 */
11510 if (infoKeys && !infoKeys->getCount()) {
11511 infoKeys = NULL;
11512 }
11513
11514 /*
11515 * Empty list of bundle ids is equivalent to
11516 * no list (get all).
11517 */
11518 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11519 kextIdentifiers = NULL;
11520 } else if (kextIdentifiers) {
11521 idCount = kextIdentifiers->getCount();
11522 }
11523
11524 /*
11525 * Caller can specify which state of dexts to query.
11526 */
11527 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveKey)) {
11528 getActive = true;
11529 }
11530 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11531 getLoaded = true;
11532 }
11533 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11534 getUnloaded = true;
11535 }
11536 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11537 getPendingUpgrade = true;
11538 }
11539
11540 /*
11541 * By default we are going to return all active and pendingUpgrade dexts
11542 * only.
11543 */
11544 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11545 getActive = true;
11546 getPendingUpgrade = true;
11547 }
11548
11549 /*
11550 * We return a dictionary of dexts
11551 * for every group requested.
11552 */
11553 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11554 result = OSArray::withCapacity(avgDextCount);
11555 if (!result) {
11556 goto finish;
11557 }
11558
11559 IORecursiveLockLock(sKextLock);
11560 { // start block scope
11561 if (getActive || getLoaded || getUnloaded) {
11562 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11563 {
11564 OSKext *thisKext = NULL; // do not release
11565 OSSharedPtr<OSDictionary> kextInfo;
11566 Boolean includeThis = true;
11567 (void)thisKextID;
11568
11569 thisKext = OSDynamicCast(OSKext, obj);
11570 if (!thisKext || !thisKext->isDriverKit()) {
11571 return false;
11572 }
11573
11574 /*
11575 * Skip current dext if we have a list of bundle IDs and
11576 * it isn't in the list.
11577 */
11578 if (kextIdentifiers) {
11579 includeThis = false;
11580
11581 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11582 const OSString * thisRequestID = OSDynamicCast(OSString,
11583 kextIdentifiers->getObject(idIndex));
11584 if (thisKextID->isEqualTo(thisRequestID)) {
11585 includeThis = true;
11586 break;
11587 }
11588 }
11589 }
11590
11591 if (!includeThis) {
11592 return false;
11593 }
11594
11595 OSSharedPtr<OSString> state;
11596 if (sLoadedDriverKitKexts->getNextIndexOfObject(thisKext, 0) == -1U) {
11597 if (!(getActive || getUnloaded)) {
11598 return false;
11599 }
11600 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11601 } else {
11602 if (!(getActive || getLoaded)) {
11603 return false;
11604 }
11605 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11606 }
11607
11608 kextInfo = thisKext->copyInfo(infoKeys);
11609 if (kextInfo) {
11610 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11611 result->setObject(kextInfo.get());
11612 }
11613
11614 return false;
11615 });
11616 }
11617
11618 if (getPendingUpgrade) {
11619 sDriverKitToUpgradeByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11620 {
11621 OSKext *thisKext = NULL; // do not release
11622 OSSharedPtr<OSDictionary> kextInfo;
11623 Boolean includeThis = true;
11624 (void)thisKextID;
11625
11626 thisKext = OSDynamicCast(OSKext, obj);
11627 if (!thisKext) {
11628 return false;
11629 }
11630 __assert_only bool isDext = thisKext->isDriverKit();
11631 assert(isDext == true);
11632
11633 /*
11634 * Skip current dext if we have a list of bundle IDs and
11635 * it isn't in the list.
11636 */
11637 if (kextIdentifiers) {
11638 includeThis = false;
11639
11640 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11641 const OSString * thisRequestID = OSDynamicCast(OSString,
11642 kextIdentifiers->getObject(idIndex));
11643 if (thisKextID->isEqualTo(thisRequestID)) {
11644 includeThis = true;
11645 break;
11646 }
11647 }
11648 }
11649
11650 if (!includeThis) {
11651 return false;
11652 }
11653
11654 kextInfo = thisKext->copyInfo(infoKeys);
11655 if (kextInfo) {
11656 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11657 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11658 result->setObject(kextInfo.get());
11659 }
11660 return false;
11661 });
11662 }
11663 } // end block scope
11664 IORecursiveLockUnlock(sKextLock);
11665 finish:
11666 return result;
11667 }
11668
11669 /*********************************************************************
11670 *********************************************************************/
11671 /* static */
11672 OSSharedPtr<OSDictionary>
11673 OSKext::copyLoadedKextInfo(
11674 OSArray * kextIdentifiers,
11675 OSArray * infoKeys)
11676 {
11677 OSSharedPtr<OSDictionary> result;
11678 uint32_t idCount = 0;
11679 bool onlyLoaded;
11680
11681 IORecursiveLockLock(sKextLock);
11682
11683 #if CONFIG_MACF
11684 /* Is the calling process allowed to query kext info? */
11685 if (current_task() != kernel_task) {
11686 int macCheckResult = 0;
11687 kauth_cred_t cred = NULL;
11688
11689 cred = kauth_cred_get_with_ref();
11690 macCheckResult = mac_kext_check_query(cred);
11691 kauth_cred_unref(&cred);
11692
11693 if (macCheckResult != 0) {
11694 OSKextLog(/* kext */ NULL,
11695 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11696 "Failed to query kext info (MAC policy error 0x%x).",
11697 macCheckResult);
11698 goto finish;
11699 }
11700 }
11701 #endif
11702
11703 /* Empty list of bundle ids is equivalent to no list (get all).
11704 */
11705 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11706 kextIdentifiers = NULL;
11707 } else if (kextIdentifiers) {
11708 idCount = kextIdentifiers->getCount();
11709 }
11710
11711 /* Same for keys.
11712 */
11713 if (infoKeys && !infoKeys->getCount()) {
11714 infoKeys = NULL;
11715 }
11716
11717 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
11718
11719 result = OSDictionary::withCapacity(128);
11720 if (!result) {
11721 goto finish;
11722 }
11723
11724 #if 0
11725 OSKextLog(/* kext */ NULL,
11726 kOSKextLogErrorLevel |
11727 kOSKextLogGeneralFlag,
11728 "kaslr: vm_kernel_slide 0x%lx \n",
11729 vm_kernel_slide);
11730 OSKextLog(/* kext */ NULL,
11731 kOSKextLogErrorLevel |
11732 kOSKextLogGeneralFlag,
11733 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11734 vm_kernel_stext, vm_kernel_etext);
11735 OSKextLog(/* kext */ NULL,
11736 kOSKextLogErrorLevel |
11737 kOSKextLogGeneralFlag,
11738 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11739 vm_kernel_base, vm_kernel_top);
11740 OSKextLog(/* kext */ NULL,
11741 kOSKextLogErrorLevel |
11742 kOSKextLogGeneralFlag,
11743 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11744 vm_kext_base, vm_kext_top);
11745 OSKextLog(/* kext */ NULL,
11746 kOSKextLogErrorLevel |
11747 kOSKextLogGeneralFlag,
11748 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11749 vm_prelink_stext, vm_prelink_etext);
11750 OSKextLog(/* kext */ NULL,
11751 kOSKextLogErrorLevel |
11752 kOSKextLogGeneralFlag,
11753 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11754 vm_prelink_sinfo, vm_prelink_einfo);
11755 OSKextLog(/* kext */ NULL,
11756 kOSKextLogErrorLevel |
11757 kOSKextLogGeneralFlag,
11758 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11759 vm_slinkedit, vm_elinkedit);
11760 #endif
11761 { // start block scope
11762 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
11763 {
11764 OSKext * thisKext = NULL; // do not release
11765 Boolean includeThis = true;
11766 OSSharedPtr<OSDictionary> kextInfo;
11767
11768 thisKext = OSDynamicCast(OSKext, obj);
11769 if (!thisKext) {
11770 return false;
11771 }
11772
11773 /* Skip current kext if not yet started and caller didn't request all.
11774 */
11775 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11776 return false;
11777 }
11778
11779 /* Skip current kext if we have a list of bundle IDs and
11780 * it isn't in the list.
11781 */
11782 if (kextIdentifiers) {
11783 includeThis = false;
11784
11785 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11786 const OSString * thisRequestID = OSDynamicCast(OSString,
11787 kextIdentifiers->getObject(idIndex));
11788 if (thisKextID->isEqualTo(thisRequestID)) {
11789 includeThis = true;
11790 break;
11791 }
11792 }
11793 }
11794
11795 if (!includeThis) {
11796 return false;
11797 }
11798
11799 kextInfo = thisKext->copyInfo(infoKeys);
11800 if (kextInfo) {
11801 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11802 }
11803 return false;
11804 });
11805 } // end block scope
11806
11807 finish:
11808 IORecursiveLockUnlock(sKextLock);
11809
11810 return result;
11811 }
11812
11813 /*********************************************************************
11814 * Any info that needs to do allocations must goto finish on alloc
11815 * failure. Info that is just a lookup should just not set the object
11816 * if the info does not exist.
11817 *********************************************************************/
11818 #define _OSKextLoadInfoDictCapacity (12)
11819
11820 OSSharedPtr<OSDictionary>
11821 OSKext::copyInfo(OSArray * infoKeys)
11822 {
11823 OSSharedPtr<OSDictionary> result;
11824 bool success = false;
11825 OSSharedPtr<OSData> headerData;
11826 OSSharedPtr<OSData> logData;
11827 OSSharedPtr<OSNumber> cpuTypeNumber;
11828 OSSharedPtr<OSNumber> cpuSubtypeNumber;
11829 OSString * versionString = NULL; // do not release
11830 OSString * bundleType = NULL; // do not release
11831 uint32_t executablePathCStringSize = 0;
11832 char * executablePathCString = NULL; // must kfree
11833 OSSharedPtr<OSString> executablePathString;
11834 OSSharedPtr<OSData> uuid;
11835 OSSharedPtr<OSArray> dependencyLoadTags;
11836 OSSharedPtr<OSCollectionIterator> metaClassIterator;
11837 OSSharedPtr<OSArray> metaClassInfo;
11838 OSSharedPtr<OSDictionary> metaClassDict;
11839 OSMetaClass * thisMetaClass = NULL; // do not release
11840 OSSharedPtr<OSString> metaClassName;
11841 OSSharedPtr<OSString> superclassName;
11842 kc_format_t kcformat;
11843 uint32_t count, i;
11844
11845 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
11846 if (!result) {
11847 goto finish;
11848 }
11849
11850
11851 /* Empty keys means no keys, but NULL is quicker to check.
11852 */
11853 if (infoKeys && !infoKeys->getCount()) {
11854 infoKeys = NULL;
11855 }
11856
11857 if (!PE_get_primary_kc_format(&kcformat)) {
11858 goto finish;
11859 }
11860
11861 /* Headers, CPU type, and CPU subtype.
11862 */
11863 if (!infoKeys ||
11864 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
11865 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
11866 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
11867 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11868 if (linkedExecutable && !isInterface()) {
11869 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
11870 linkedExecutable->getBytesNoCopy();
11871
11872 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
11873 // do not return macho header info on shipping embedded - 19095897
11874 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
11875 kernel_mach_header_t * temp_kext_mach_hdr;
11876 struct load_command * lcp;
11877
11878 headerData = OSData::withBytes(kext_mach_hdr,
11879 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
11880 if (!headerData) {
11881 goto finish;
11882 }
11883
11884 // unslide any vmaddrs we return to userspace - 10726716
11885 temp_kext_mach_hdr = (kernel_mach_header_t *)
11886 headerData->getBytesNoCopy();
11887 if (temp_kext_mach_hdr == NULL) {
11888 goto finish;
11889 }
11890
11891 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
11892 for (i = 0; (i < temp_kext_mach_hdr->ncmds) && !flags.unslidMachO; i++) {
11893 if (lcp->cmd == LC_SEGMENT_KERNEL) {
11894 kernel_segment_command_t * segp;
11895 kernel_section_t * secp;
11896
11897 segp = (kernel_segment_command_t *) lcp;
11898 // 10543468 - if we jettisoned __LINKEDIT clear size info
11899 if (flags.jettisonLinkeditSeg) {
11900 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
11901 segp->vmsize = 0;
11902 segp->fileoff = 0;
11903 segp->filesize = 0;
11904 }
11905 }
11906
11907 #if __arm__ || __arm64__
11908 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
11909 // and unslide them to avoid vm assertion failures / kernel logging breakage.
11910 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
11911 segp->vmaddr = gVirtBase;
11912 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
11913 secp->size = 0; // paranoia :)
11914 secp->addr = gVirtBase;
11915 }
11916 }
11917 #endif
11918
11919 #if 0
11920 OSKextLog(/* kext */ NULL,
11921 kOSKextLogErrorLevel |
11922 kOSKextLogGeneralFlag,
11923 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
11924 __FUNCTION__, segp->segname, segp->vmaddr,
11925 VM_KERNEL_UNSLIDE(segp->vmaddr),
11926 segp->vmsize, segp->nsects);
11927 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
11928 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
11929 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
11930 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
11931 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
11932 OSKextLog(/* kext */ NULL,
11933 kOSKextLogErrorLevel |
11934 kOSKextLogGeneralFlag,
11935 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
11936 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
11937 }
11938 #endif
11939 segp->vmaddr = ml_static_unslide(segp->vmaddr);
11940
11941 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
11942 secp->addr = ml_static_unslide(secp->addr);
11943 }
11944 }
11945 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
11946 }
11947 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
11948 }
11949 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
11950
11951 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11952 osLogDataHeaderRef *header;
11953 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11954
11955 void *os_log_data = NULL;
11956 void *cstring_data = NULL;
11957 void *asan_cstring_data = NULL;
11958 unsigned long os_log_size = 0;
11959 unsigned long cstring_size = 0;
11960 unsigned long asan_cstring_size = 0;
11961 uint32_t os_log_offset = 0;
11962 uint32_t cstring_offset = 0;
11963 uint32_t asan_cstring_offset = 0;
11964 bool res;
11965
11966 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
11967 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
11968 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
11969
11970 /*
11971 * If the addresses in the Mach-O header are unslid, manually
11972 * slide them to allow for dereferencing.
11973 */
11974 if (flags.unslidMachO) {
11975 os_log_data = (os_log_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)os_log_data) : nullptr;
11976 cstring_data = (cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)cstring_data) : nullptr;
11977 asan_cstring_data = (asan_cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)asan_cstring_data) : nullptr;
11978 }
11979
11980 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
11981 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
11982 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
11983
11984 header = (osLogDataHeaderRef *) headerBytes;
11985 header->version = OS_LOG_HDR_VERSION;
11986 header->sect_count = NUM_OS_LOG_SECTIONS;
11987 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
11988 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
11989 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
11990 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
11991 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
11992 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
11993
11994
11995 logData = OSData::withValue(*header);
11996 if (!logData) {
11997 goto finish;
11998 }
11999 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12000 if (!res) {
12001 goto finish;
12002 }
12003 if (os_log_data) {
12004 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
12005 if (!res) {
12006 goto finish;
12007 }
12008 }
12009 if (cstring_data) {
12010 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
12011 if (!res) {
12012 goto finish;
12013 }
12014 }
12015 if (asan_cstring_data) {
12016 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
12017 if (!res) {
12018 goto finish;
12019 }
12020 }
12021 result->setObject(kOSBundleLogStringsKey, logData.get());
12022 }
12023
12024 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
12025 cpuTypeNumber = OSNumber::withNumber(
12026 (uint64_t) kext_mach_hdr->cputype,
12027 8 * sizeof(kext_mach_hdr->cputype));
12028 if (!cpuTypeNumber) {
12029 goto finish;
12030 }
12031 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
12032 }
12033
12034 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12035 cpuSubtypeNumber = OSNumber::withNumber(
12036 (uint64_t) kext_mach_hdr->cpusubtype,
12037 8 * sizeof(kext_mach_hdr->cpusubtype));
12038 if (!cpuSubtypeNumber) {
12039 goto finish;
12040 }
12041 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
12042 }
12043 } else {
12044 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12045 osLogDataHeaderRef *header;
12046 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12047 bool res;
12048
12049 header = (osLogDataHeaderRef *) headerBytes;
12050 header->version = OS_LOG_HDR_VERSION;
12051 header->sect_count = NUM_OS_LOG_SECTIONS;
12052 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
12053 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
12054 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
12055 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12056 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
12057 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12058
12059 logData = OSData::withValue(*header);
12060 if (!logData) {
12061 goto finish;
12062 }
12063 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12064 if (!res) {
12065 goto finish;
12066 }
12067 result->setObject(kOSBundleLogStringsKey, logData.get());
12068 }
12069 }
12070 }
12071
12072 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
12073 */
12074 result->setObject(kCFBundleIdentifierKey, bundleID.get());
12075
12076 /* kOSBundleDextUniqueIdentifierKey if present.
12077 */
12078 if (isDriverKit() && dextUniqueID != NULL) {
12079 result->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID.get());
12080 }
12081
12082 /* CFBundlePackageType
12083 */
12084 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12085 if (bundleType) {
12086 result->setObject(kCFBundlePackageTypeKey, bundleType);
12087 }
12088
12089 /* CFBundleVersion.
12090 */
12091 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
12092 versionString = OSDynamicCast(OSString,
12093 getPropertyForHostArch(kCFBundleVersionKey));
12094 if (versionString) {
12095 result->setObject(kCFBundleVersionKey, versionString);
12096 }
12097 }
12098
12099 /* OSBundleCompatibleVersion.
12100 */
12101 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
12102 versionString = OSDynamicCast(OSString,
12103 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12104 if (versionString) {
12105 result->setObject(kOSBundleCompatibleVersionKey, versionString);
12106 }
12107 }
12108
12109 /* Path.
12110 */
12111 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
12112 if (path) {
12113 result->setObject(kOSBundlePathKey, path.get());
12114 }
12115 }
12116
12117
12118 /* OSBundleExecutablePath.
12119 */
12120 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
12121 if (path && executableRelPath) {
12122 uint32_t pathLength = path->getLength(); // gets incremented below
12123
12124 // +1 for slash, +1 for \0
12125 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12126
12127 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12128 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12129 if (!executablePathCString) {
12130 goto finish;
12131 }
12132 strlcpy(executablePathCString, path->getCStringNoCopy(),
12133 executablePathCStringSize);
12134 executablePathCString[pathLength++] = '/';
12135 executablePathCString[pathLength++] = '\0';
12136 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
12137 executablePathCStringSize);
12138
12139 executablePathString = OSString::withCString(executablePathCString);
12140
12141 if (!executablePathString) {
12142 goto finish;
12143 }
12144
12145 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12146 } else if (flags.builtin) {
12147 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
12148 } else if (isDriverKit()) {
12149 if (path) {
12150 // +1 for slash, +1 for \0
12151 uint32_t pathLength = path->getLength();
12152 executablePathCStringSize = pathLength + 2;
12153
12154 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12155 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12156 if (!executablePathCString) {
12157 goto finish;
12158 }
12159 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
12160 executablePathCString[pathLength++] = '/';
12161 executablePathCString[pathLength++] = '\0';
12162
12163 executablePathString = OSString::withCString(executablePathCString);
12164
12165 if (!executablePathString) {
12166 goto finish;
12167 }
12168
12169 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12170 }
12171 }
12172 }
12173
12174 /* UUID, if the kext has one.
12175 */
12176 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
12177 uuid = copyUUID();
12178 if (uuid) {
12179 result->setObject(kOSBundleUUIDKey, uuid.get());
12180 }
12181 }
12182 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
12183 uuid = copyTextUUID();
12184 if (uuid) {
12185 result->setObject(kOSBundleTextUUIDKey, uuid.get());
12186 }
12187 }
12188
12189 /*
12190 * Info.plist digest
12191 */
12192 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
12193 OSData *digest;
12194 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12195 if (digest) {
12196 result->setObject(kOSKextInfoPlistDigestKey, digest);
12197 }
12198 }
12199
12200 /*
12201 * Collection type
12202 */
12203 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
12204 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
12205 }
12206
12207 /*
12208 * Collection availability
12209 */
12210 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
12211 result->setObject(kOSKextAuxKCAvailabilityKey,
12212 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12213 }
12214
12215 /*
12216 * Allows user load
12217 */
12218 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
12219 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12220 if (allowUserLoad) {
12221 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
12222 }
12223 }
12224
12225 /*
12226 * Bundle Dependencies (OSBundleLibraries)
12227 */
12228 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
12229 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12230 if (libraries) {
12231 result->setObject(kOSBundleLibrariesKey, libraries);
12232 }
12233 }
12234
12235 /*****
12236 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12237 */
12238 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
12239 result->setObject(kOSKernelResourceKey,
12240 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12241 }
12242
12243 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
12244 result->setObject(kOSBundleIsInterfaceKey,
12245 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12246 }
12247
12248 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
12249 result->setObject(kOSBundlePrelinkedKey,
12250 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12251 }
12252
12253 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
12254 result->setObject(kOSBundleStartedKey,
12255 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12256 }
12257
12258 /* LoadTag (Index).
12259 */
12260 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
12261 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
12262 /* numBits */ 8 * sizeof(loadTag));
12263 if (!scratchNumber) {
12264 goto finish;
12265 }
12266 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
12267 }
12268
12269 /* LoadAddress, LoadSize.
12270 */
12271 if (!infoKeys ||
12272 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
12273 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
12274 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
12275 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
12276 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12277 bool is_dext = isDriverKit();
12278 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12279 /* These go to userspace via serialization, so we don't want any doubts
12280 * about their size.
12281 */
12282 uint64_t loadAddress = 0;
12283 uint32_t loadSize = 0;
12284 uint32_t wiredSize = 0;
12285 uint64_t execLoadAddress = 0;
12286 uint32_t execLoadSize = 0;
12287
12288 /* Interfaces always report 0 load address & size.
12289 * Just the way they roll.
12290 *
12291 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12292 * xxx - shouldn't have one!
12293 */
12294
12295 if (flags.builtin || linkedExecutable) {
12296 kernel_mach_header_t *mh = NULL;
12297 kernel_segment_command_t *seg = NULL;
12298
12299 if (flags.builtin) {
12300 loadAddress = kmod_info->address;
12301 loadSize = (uint32_t)kmod_info->size;
12302 } else {
12303 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12304 loadSize = linkedExecutable->getLength();
12305 }
12306 mh = (kernel_mach_header_t *)loadAddress;
12307 loadAddress = ml_static_unslide(loadAddress);
12308
12309 /* Walk through the kext, looking for the first executable
12310 * segment in case we were asked for its size/address.
12311 */
12312 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
12313 if (seg->initprot & VM_PROT_EXECUTE) {
12314 execLoadAddress = (flags.unslidMachO) ? seg->vmaddr : ml_static_unslide(seg->vmaddr);
12315 execLoadSize = (uint32_t)seg->vmsize;
12316 break;
12317 }
12318 }
12319
12320 /* If we have a kmod_info struct, calculated the wired size
12321 * from that. Otherwise it's the full load size.
12322 */
12323 if (kmod_info) {
12324 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12325 } else {
12326 wiredSize = loadSize;
12327 }
12328 } else if (is_dext) {
12329 /*
12330 * DriverKit userspace executables do not have a kernel linkedExecutable,
12331 * so we "fake" their address range with the LoadTag.
12332 */
12333 if (loadTag) {
12334 loadAddress = execLoadAddress = loadTag;
12335 loadSize = execLoadSize = 1;
12336 }
12337 }
12338
12339 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
12340 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12341 (unsigned long long)(loadAddress),
12342 /* numBits */ 8 * sizeof(loadAddress));
12343 if (!scratchNumber) {
12344 goto finish;
12345 }
12346 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
12347 }
12348 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12349 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
12350 && loadAddress && loadSize) {
12351 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
12352 if (!baseAddress) {
12353 goto finish;
12354 }
12355
12356 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12357 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
12358 /* numBits */ 8 * sizeof(loadAddress));
12359 if (!scratchNumber) {
12360 goto finish;
12361 }
12362 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
12363 }
12364 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
12365 && (this == sKernelKext) && gBuiltinKmodsCount) {
12366 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
12367 }
12368 }
12369
12370 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
12371 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12372 (unsigned long long)(execLoadAddress),
12373 /* numBits */ 8 * sizeof(execLoadAddress));
12374 if (!scratchNumber) {
12375 goto finish;
12376 }
12377 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
12378 }
12379 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
12380 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12381 (unsigned long long)(loadSize),
12382 /* numBits */ 8 * sizeof(loadSize));
12383 if (!scratchNumber) {
12384 goto finish;
12385 }
12386 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
12387 }
12388 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
12389 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12390 (unsigned long long)(execLoadSize),
12391 /* numBits */ 8 * sizeof(execLoadSize));
12392 if (!scratchNumber) {
12393 goto finish;
12394 }
12395 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
12396 }
12397 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12398 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12399 (unsigned long long)(wiredSize),
12400 /* numBits */ 8 * sizeof(wiredSize));
12401 if (!scratchNumber) {
12402 goto finish;
12403 }
12404 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
12405 }
12406 }
12407 }
12408
12409 /* OSBundleDependencies. In descending order for
12410 * easy compatibility with kextstat(8).
12411 */
12412 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
12413 if ((count = getNumDependencies())) {
12414 dependencyLoadTags = OSArray::withCapacity(count);
12415 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
12416
12417 i = count - 1;
12418 do {
12419 OSKext * dependency = OSDynamicCast(OSKext,
12420 dependencies->getObject(i));
12421
12422 if (!dependency) {
12423 continue;
12424 }
12425 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12426 (unsigned long long)dependency->getLoadTag(),
12427 /* numBits*/ 8 * sizeof(loadTag));
12428 if (!scratchNumber) {
12429 goto finish;
12430 }
12431 dependencyLoadTags->setObject(scratchNumber.get());
12432 } while (i--);
12433 }
12434 }
12435
12436 /* OSBundleMetaClasses.
12437 */
12438 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
12439 if (metaClasses && metaClasses->getCount()) {
12440 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
12441 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
12442 if (!metaClassIterator || !metaClassInfo) {
12443 goto finish;
12444 }
12445 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
12446
12447 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12448 metaClassIterator->getNextObject()))) {
12449 metaClassDict = OSDictionary::withCapacity(3);
12450 if (!metaClassDict) {
12451 goto finish;
12452 }
12453
12454 metaClassName = OSString::withCString(thisMetaClass->getClassName());
12455 if (thisMetaClass->getSuperClass()) {
12456 superclassName = OSString::withCString(
12457 thisMetaClass->getSuperClass()->getClassName());
12458 }
12459 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
12460 8 * sizeof(unsigned int));
12461
12462 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12463 * of course.
12464 */
12465 if (!metaClassDict || !metaClassName || !scratchNumber) {
12466 goto finish;
12467 }
12468
12469 metaClassInfo->setObject(metaClassDict.get());
12470 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
12471 if (superclassName) {
12472 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
12473 }
12474 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
12475 }
12476 }
12477 }
12478
12479 /* OSBundleRetainCount.
12480 */
12481 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
12482 {
12483 int kextRetainCount = getRetainCount() - 1;
12484 if (isLoaded()) {
12485 kextRetainCount--;
12486 }
12487 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12488 (int)kextRetainCount,
12489 /* numBits*/ 8 * sizeof(int));
12490 if (scratchNumber) {
12491 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
12492 }
12493 }
12494 }
12495
12496 success = true;
12497
12498 finish:
12499 if (executablePathCString) {
12500 kfree_data(executablePathCString, executablePathCStringSize);
12501 }
12502 if (!success) {
12503 result.reset();
12504 }
12505 return result;
12506 }
12507
12508 /*********************************************************************
12509 *********************************************************************/
12510 /* static */
12511 bool
12512 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12513 {
12514 bool ok;
12515 OSSharedPtr<OSKext> kext;
12516
12517 IORecursiveLockLock(sKextLock);
12518 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12519 IORecursiveLockUnlock(sKextLock);
12520
12521 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12522 return false;
12523 }
12524 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
12525 kext->path->getCStringNoCopy(),
12526 kext->userExecutableRelPath->getCStringNoCopy());
12527 ok = true;
12528
12529 return ok;
12530 }
12531
12532 /*********************************************************************
12533 *********************************************************************/
12534 /* static */
12535 OSReturn
12536 OSKext::requestResource(
12537 const char * kextIdentifierCString,
12538 const char * resourceNameCString,
12539 OSKextRequestResourceCallback callback,
12540 void * context,
12541 OSKextRequestTag * requestTagOut)
12542 {
12543 OSReturn result = kOSReturnError;
12544 OSSharedPtr<OSKext> callbackKext; // looked up
12545
12546 OSKextRequestTag requestTag = -1;
12547 OSSharedPtr<OSNumber> requestTagNum;
12548 OSSharedPtr<OSDictionary> requestDict;
12549 OSSharedPtr<OSString> kextIdentifier;
12550 OSSharedPtr<OSString> resourceName;
12551
12552 OSSharedPtr<OSDictionary> callbackRecord;
12553 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12554
12555 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12556
12557 IORecursiveLockLock(sKextLock);
12558
12559 if (requestTagOut) {
12560 *requestTagOut = kOSKextRequestTagInvalid;
12561 }
12562
12563 /* If requests to user space are disabled, don't go any further */
12564 if (!sKernelRequestsEnabled) {
12565 OSKextLog(/* kext */ NULL,
12566 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12567 "Can't request resource %s for %s - requests to user space are disabled.",
12568 resourceNameCString,
12569 kextIdentifierCString);
12570 result = kOSKextReturnDisabled;
12571 goto finish;
12572 }
12573
12574 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12575 result = kOSKextReturnInvalidArgument;
12576 goto finish;
12577 }
12578
12579 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12580 if (!callbackKext) {
12581 OSKextLog(/* kext */ NULL,
12582 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12583 "Resource request has bad callback address.");
12584 result = kOSKextReturnInvalidArgument;
12585 goto finish;
12586 }
12587 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12588 OSKextLog(/* kext */ NULL,
12589 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12590 "Resource request callback is in a kext that is not started.");
12591 result = kOSKextReturnInvalidArgument;
12592 goto finish;
12593 }
12594
12595 /* Do not allow any new requests to be made on a kext that is unloading.
12596 */
12597 if (callbackKext->flags.stopping) {
12598 result = kOSKextReturnStopping;
12599 goto finish;
12600 }
12601
12602 /* If we're wrapped the next available request tag around to the negative
12603 * numbers, we can't service any more requests.
12604 */
12605 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12606 OSKextLog(/* kext */ NULL,
12607 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12608 "No more request tags available; restart required.");
12609 result = kOSKextReturnNoResources;
12610 goto finish;
12611 }
12612 requestTag = sNextRequestTag++;
12613
12614 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12615 requestDict);
12616 if (result != kOSReturnSuccess) {
12617 goto finish;
12618 }
12619
12620 kextIdentifier = OSString::withCString(kextIdentifierCString);
12621 resourceName = OSString::withCString(resourceNameCString);
12622 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12623 8 * sizeof(requestTag));
12624 if (!kextIdentifier ||
12625 !resourceName ||
12626 !requestTagNum ||
12627 !_OSKextSetRequestArgument(requestDict.get(),
12628 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
12629 !_OSKextSetRequestArgument(requestDict.get(),
12630 kKextRequestArgumentNameKey, resourceName.get()) ||
12631 !_OSKextSetRequestArgument(requestDict.get(),
12632 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
12633 result = kOSKextReturnNoMemory;
12634 goto finish;
12635 }
12636
12637 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
12638 if (!callbackRecord) {
12639 result = kOSKextReturnNoMemory;
12640 goto finish;
12641 }
12642 // we validate callback address at call time
12643 callbackWrapper = OSValueObjectWithValue(callback);
12644 if (context) {
12645 contextWrapper = OSValueObjectWithValue(context);
12646 }
12647 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12648 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
12649 result = kOSKextReturnNoMemory;
12650 goto finish;
12651 }
12652
12653 if (context) {
12654 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12655 kKextRequestArgumentContextKey, contextWrapper.get())) {
12656 result = kOSKextReturnNoMemory;
12657 goto finish;
12658 }
12659 }
12660
12661 /* Only post the requests after all the other potential failure points
12662 * have been passed.
12663 */
12664 if (!sKernelRequests->setObject(requestDict.get()) ||
12665 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12666 result = kOSKextReturnNoMemory;
12667 goto finish;
12668 }
12669
12670 OSKext::pingIOKitDaemon();
12671
12672 result = kOSReturnSuccess;
12673 if (requestTagOut) {
12674 *requestTagOut = requestTag;
12675 }
12676
12677 finish:
12678
12679 /* If we didn't succeed, yank the request & callback
12680 * from their holding arrays.
12681 */
12682 if (result != kOSReturnSuccess) {
12683 unsigned int index;
12684
12685 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
12686 if (index != (unsigned int)-1) {
12687 sKernelRequests->removeObject(index);
12688 }
12689 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
12690 if (index != (unsigned int)-1) {
12691 sRequestCallbackRecords->removeObject(index);
12692 }
12693 }
12694
12695 OSKext::considerUnloads(/* rescheduleOnly? */ true);
12696
12697 IORecursiveLockUnlock(sKextLock);
12698
12699 return result;
12700 }
12701
12702 OSReturn
12703 OSKext::requestDaemonLaunch(
12704 OSString *kextIdentifier,
12705 OSString *serverName,
12706 OSNumber *serverTag,
12707 OSBoolean *reslide,
12708 IOUserServerCheckInToken * checkInToken,
12709 OSData *serverDUI)
12710 {
12711 OSReturn result = kOSReturnError;
12712 OSSharedPtr<OSDictionary> requestDict;
12713 unsigned int size = 0;
12714 const char *dextUniqueIDCString = NULL;
12715
12716 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12717 return kOSKextReturnInvalidArgument;
12718 }
12719
12720 if (serverDUI != NULL) {
12721 dextUniqueIDCString = getDextUniqueIDCString(serverDUI, &size);
12722 }
12723
12724 IORecursiveLockLock(sKextLock);
12725
12726 OSKextLog(/* kext */ NULL,
12727 kOSKextLogDebugLevel |
12728 kOSKextLogGeneralFlag,
12729 "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12730 kextIdentifier->getCStringNoCopy(),
12731 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12732 serverName->getCStringNoCopy(),
12733 serverTag->unsigned64BitValue(),
12734 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12735 );
12736
12737 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
12738 if (result != kOSReturnSuccess) {
12739 goto finish;
12740 }
12741
12742 if (!_OSKextSetRequestArgument(requestDict.get(),
12743 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12744 !_OSKextSetRequestArgument(requestDict.get(),
12745 kKextRequestArgumentDriverExtensionServerName, serverName) ||
12746 !_OSKextSetRequestArgument(requestDict.get(),
12747 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
12748 !_OSKextSetRequestArgument(requestDict.get(),
12749 kKextRequestArgumentDriverExtensionReslideSharedCache, reslide) ||
12750 !_OSKextSetRequestArgument(requestDict.get(),
12751 kKextRequestArgumentCheckInToken, checkInToken)) {
12752 result = kOSKextReturnNoMemory;
12753 goto finish;
12754 }
12755
12756 if (serverDUI) {
12757 if (!_OSKextSetRequestArgument(requestDict.get(),
12758 kOSBundleDextUniqueIdentifierKey, serverDUI)) {
12759 result = kOSKextReturnNoMemory;
12760 goto finish;
12761 }
12762 }
12763
12764 /* Only post the requests after all the other potential failure points
12765 * have been passed.
12766 */
12767 if (!sKernelRequests->setObject(requestDict.get())) {
12768 result = kOSKextReturnNoMemory;
12769 goto finish;
12770 }
12771 OSKext::pingIOKitDaemon();
12772
12773 result = kOSReturnSuccess;
12774 finish:
12775 IORecursiveLockUnlock(sKextLock);
12776 if (dextUniqueIDCString) {
12777 kfree_data(dextUniqueIDCString, size);
12778 }
12779 return result;
12780 }
12781
12782 OSReturn
12783 OSKext::notifyDextUpgrade(
12784 OSString *kextIdentifier,
12785 OSData *dextUniqueIdentifier)
12786 {
12787 OSReturn result = kOSReturnError;
12788 OSSharedPtr<OSDictionary> requestDict;
12789 unsigned int size = 0;
12790 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueIdentifier, &size);
12791 assert(dextUniqueIDCString != NULL);
12792
12793 IORecursiveLockLock(sKextLock);
12794
12795 OSKextLog(NULL,
12796 kOSKextLogDebugLevel |
12797 kOSKextLogGeneralFlag,
12798 "Notifying of dext upgrade for %s with UniqueID %s",
12799 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
12800
12801 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestDict);
12802 if (result != kOSReturnSuccess) {
12803 goto finish;
12804 }
12805
12806 if (!_OSKextSetRequestArgument(requestDict.get(),
12807 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12808 !_OSKextSetRequestArgument(requestDict.get(),
12809 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
12810 result = kOSKextReturnNoMemory;
12811 goto finish;
12812 }
12813
12814 /* Only post the requests after all the other potential failure points
12815 * have been passed.
12816 */
12817 if (!sKernelRequests->setObject(requestDict.get())) {
12818 result = kOSKextReturnNoMemory;
12819 goto finish;
12820 }
12821 OSKext::pingIOKitDaemon();
12822
12823 result = kOSReturnSuccess;
12824 finish:
12825 IORecursiveLockUnlock(sKextLock);
12826
12827 if (dextUniqueIDCString != NULL) {
12828 kfree_data(dextUniqueIDCString, size);
12829 }
12830 return result;
12831 }
12832
12833 /*********************************************************************
12834 * Assumes sKextLock is held.
12835 *********************************************************************/
12836 /* static */
12837 OSReturn
12838 OSKext::dequeueCallbackForRequestTag(
12839 OSKextRequestTag requestTag,
12840 OSSharedPtr<OSDictionary> &callbackRecordOut)
12841 {
12842 OSDictionary * callbackRecordOutRaw = NULL;
12843 OSReturn result;
12844
12845 result = dequeueCallbackForRequestTag(requestTag,
12846 &callbackRecordOutRaw);
12847
12848 if (kOSReturnSuccess == result) {
12849 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
12850 }
12851
12852 return result;
12853 }
12854 OSReturn
12855 OSKext::dequeueCallbackForRequestTag(
12856 OSKextRequestTag requestTag,
12857 OSDictionary ** callbackRecordOut)
12858 {
12859 OSReturn result = kOSReturnError;
12860 OSSharedPtr<OSNumber> requestTagNum;
12861
12862 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12863 8 * sizeof(requestTag));
12864 if (!requestTagNum) {
12865 goto finish;
12866 }
12867
12868 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
12869 callbackRecordOut);
12870
12871 finish:
12872 return result;
12873 }
12874
12875 /*********************************************************************
12876 * Assumes sKextLock is held.
12877 *********************************************************************/
12878 /* static */
12879 OSReturn
12880 OSKext::dequeueCallbackForRequestTag(
12881 OSNumber * requestTagNum,
12882 OSSharedPtr<OSDictionary> &callbackRecordOut)
12883 {
12884 OSDictionary * callbackRecordOutRaw = NULL;
12885 OSReturn result;
12886
12887 result = dequeueCallbackForRequestTag(requestTagNum,
12888 &callbackRecordOutRaw);
12889
12890 if (kOSReturnSuccess == result) {
12891 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
12892 }
12893
12894 return result;
12895 }
12896 OSReturn
12897 OSKext::dequeueCallbackForRequestTag(
12898 OSNumber * requestTagNum,
12899 OSDictionary ** callbackRecordOut)
12900 {
12901 OSReturn result = kOSKextReturnInvalidArgument;
12902 OSDictionary * callbackRecord = NULL; // retain if matched!
12903 OSNumber * callbackTagNum = NULL; // do not release
12904 unsigned int count, i;
12905
12906 result = kOSReturnError;
12907 count = sRequestCallbackRecords->getCount();
12908 for (i = 0; i < count; i++) {
12909 callbackRecord = OSDynamicCast(OSDictionary,
12910 sRequestCallbackRecords->getObject(i));
12911 if (!callbackRecord) {
12912 goto finish;
12913 }
12914
12915 /* If we don't find a tag, we basically have a leak here. Maybe
12916 * we should just remove it.
12917 */
12918 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
12919 callbackRecord, kKextRequestArgumentRequestTagKey));
12920 if (!callbackTagNum) {
12921 goto finish;
12922 }
12923
12924 /* We could be even more paranoid and check that all the incoming
12925 * args match what's in the callback record.
12926 */
12927 if (callbackTagNum->isEqualTo(requestTagNum)) {
12928 if (callbackRecordOut) {
12929 *callbackRecordOut = callbackRecord;
12930 callbackRecord->retain();
12931 }
12932 sRequestCallbackRecords->removeObject(i);
12933 result = kOSReturnSuccess;
12934 goto finish;
12935 }
12936 }
12937 result = kOSKextReturnNotFound;
12938
12939 finish:
12940 return result;
12941 }
12942
12943
12944 /*********************************************************************
12945 * Busy timeout triage
12946 *********************************************************************/
12947 /* static */
12948 bool
12949 OSKext::pendingIOKitDaemonRequests(void)
12950 {
12951 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
12952 }
12953
12954 /*********************************************************************
12955 * Acquires and releases sKextLock
12956 *
12957 * This function is designed to be called by kernelmanagerd and driverkitd
12958 * and it gathers all codeless kext and dext personalities, and then attempts
12959 * to map a System (pageable) KC and an Auxiliary (aux) KC.
12960 *
12961 * The pageable and aux KC can be loaded only once at boot time.
12962 * Even if the pageable or aux KC fail to load - this function will
12963 * not allow a new pageable or aux KC to be installed by subsequent calls.
12964 * This is done to avoid security issues where userspace has been compromised
12965 * or the pageable kc has been tampered with and the attacker
12966 * attempts to re-load a malicious variant.
12967 * However dexts can be dynamically loaded, so this function can be used
12968 * to request the installation of a new set of dexts even after boot time.
12969 *
12970 *
12971 *
12972 * Return: if a KC fails to load the return value will contain:
12973 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
12974 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
12975 * Similarly, if the aux kc load fails, the return value will
12976 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
12977 * compose with each other and with kOSKextReturnKCLoadFailure.
12978 *********************************************************************/
12979 /* static */
12980 OSReturn
12981 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
12982 {
12983 static bool daemon_ready = false;
12984
12985 OSReturn ret = kOSKextReturnInvalidArgument;
12986 OSReturn kcerr = 0;
12987 bool start_matching = false;
12988
12989 bool allow_fileset_load = !daemon_ready;
12990 #if !(defined(__x86_64__) || defined(__i386__))
12991 /* never allow KCs full of kexts on non-x86 machines */
12992 allow_fileset_load = false;
12993 #endif
12994
12995 /*
12996 * Change with 70582300
12997 */
12998 #if 0 || !defined(VM_MAPPED_KEXTS)
12999 /*
13000 * On platforms that don't support the SystemKC or a file-backed
13001 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
13002 * needs to be queried before we load any codeless kexts or release
13003 * any 3rd party kexts to run. On platforms that support a file-backed
13004 * AuxKC, this process is done via the kext audit mechanism.
13005 */
13006
13007 printf("KextLog: waiting for kext receipt to be queried.\n");
13008 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
13009 IOSleep(30);
13010 }
13011 #endif /* !VM_MAPPED_KEXTS */
13012
13013 /*
13014 * Get the args from the request. Right now we need the file
13015 * name for the pageable and the aux kext collection file sets.
13016 */
13017 OSDictionary * requestArgs = NULL; // do not release
13018 OSString * pageable_filepath = NULL; // do not release
13019 OSString * aux_filepath = NULL; // do not release
13020 OSArray * codeless_kexts = NULL; // do not release
13021
13022 kernel_mach_header_t *akc_mh = NULL;
13023
13024 requestArgs = OSDynamicCast(OSDictionary,
13025 requestDict->getObject(kKextRequestArgumentsKey));
13026
13027 if (requestArgs == NULL) {
13028 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13029 "KextLog: No arguments in plist for loading fileset kext\n");
13030 printf("KextLog: No arguments in plist for loading fileset kext\n");
13031 return ret;
13032 }
13033
13034 ret = kOSKextReturnDisabled;
13035
13036 IORecursiveLockLock(sKextLock);
13037
13038 if (!sLoadEnabled) {
13039 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13040 "KextLog: Kext loading is disabled (attempt to load KCs).");
13041 IORecursiveLockUnlock(sKextLock);
13042 return ret;
13043 }
13044
13045 pageable_filepath = OSDynamicCast(OSString,
13046 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
13047
13048 if (allow_fileset_load && pageable_filepath != NULL) {
13049 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
13050
13051 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
13052 if (ret) {
13053 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13054 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13055
13056 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13057 ret = kOSKextReturnKCLoadFailure;
13058 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
13059 goto try_auxkc;
13060 }
13061 /*
13062 * Even if the AuxKC fails to load, we still want to send
13063 * the System KC personalities to the catalog for matching
13064 */
13065 start_matching = true;
13066 } else if (pageable_filepath != NULL) {
13067 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13068 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
13069 ret = kOSKextReturnUnsupported;
13070 }
13071
13072 try_auxkc:
13073 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
13074 if (akc_mh) {
13075 /*
13076 * If we try to load a deferred AuxKC, then don't ever attempt
13077 * a filesystem map of a file
13078 */
13079 allow_fileset_load = false;
13080
13081 /*
13082 * This function is only called once per boot, so we haven't
13083 * yet loaded an AuxKC. If we have registered the AuxKC mach
13084 * header, that means that the kext collection has been placed
13085 * in memory for us by the booter, and is waiting for us to
13086 * process it. Grab the deferred XML plist of info
13087 * dictionaries and add all the kexts.
13088 */
13089 OSSharedPtr<OSObject> parsedXML;
13090 OSSharedPtr<OSData> loaded_kcUUID;
13091 OSDictionary *infoDict;
13092 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
13093 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13094 #if !defined(VM_MAPPED_KEXTS)
13095 /*
13096 * On platforms where we don't dynamically wire-down / page-in
13097 * kext memory, we need to maintain the invariant that if the
13098 * AuxKC in memory does not contain a kext receipt, then we
13099 * should not load any of the kexts.
13100 */
13101 size_t receipt_sz = 0;
13102 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13103 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13104 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13105 ret = kOSKextReturnKCLoadFailure;
13106 goto try_codeless;
13107 }
13108 #endif
13109 if (infoDict) {
13110 bool added;
13111 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13112 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
13113 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
13114 if (!loaded_kcUUID) {
13115 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13116 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13117 } else if (!added) {
13118 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13119 "KextLog: WARNING: Failed to load AuxKC from memory.");
13120 }
13121 /* only return success if the pageable load (above) was successful */
13122 if (ret != kOSKextReturnKCLoadFailure) {
13123 ret = kOSReturnSuccess;
13124 }
13125 /* the registration of the AuxKC parsed out the KC's UUID already */
13126 } else {
13127 if (daemon_ready) {
13128 /*
13129 * Complain, but don't return an error if this isn't the first time the
13130 * IOKit daemon is checking in. If the daemon ever restarts, we will
13131 * hit this case because we've already consumed the deferred personalities.
13132 * We return success here so that a call to this function from a restarted
13133 * daemon with no codeless kexts will succeed.
13134 */
13135 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13136 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13137 if (ret != kOSKextReturnKCLoadFailure) {
13138 ret = kOSReturnSuccess;
13139 }
13140 } else {
13141 /* this is a real error case */
13142 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13143 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13144 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13145 ret = kOSKextReturnKCLoadFailure;
13146 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13147 }
13148 }
13149 }
13150
13151 aux_filepath = OSDynamicCast(OSString,
13152 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13153 if (allow_fileset_load && aux_filepath != NULL) {
13154 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13155
13156 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
13157 if (ret) {
13158 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13159 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13160
13161 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13162 ret = kOSKextReturnKCLoadFailure;
13163 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13164 goto try_codeless;
13165 }
13166 start_matching = true;
13167 } else if (aux_filepath != NULL) {
13168 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13169 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13170 if (ret != kOSKextReturnKCLoadFailure) {
13171 ret = kOSKextReturnUnsupported;
13172 }
13173 }
13174
13175 try_codeless:
13176 /*
13177 * Load codeless kexts last so that there is no possibilty of a
13178 * codeless kext bundle ID preventing a kext in the system KC from
13179 * loading
13180 */
13181 codeless_kexts = OSDynamicCast(OSArray,
13182 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13183 if (codeless_kexts != NULL) {
13184 uint32_t count = codeless_kexts->getCount();
13185 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13186 "KextLog: loading %d codeless kexts/dexts", count);
13187 for (uint32_t i = 0; i < count; i++) {
13188 OSDictionary *infoDict;
13189 infoDict = OSDynamicCast(OSDictionary,
13190 codeless_kexts->getObject(i));
13191 if (!infoDict) {
13192 continue;
13193 }
13194 // instantiate a new kext, and don't hold a reference
13195 // (the kext subsystem will hold one implicitly)
13196 OSKext::withCodelessInfo(infoDict, NULL);
13197 }
13198 /* ignore errors that are not KC load failures */
13199 if (ret != kOSKextReturnKCLoadFailure) {
13200 ret = kOSReturnSuccess;
13201 }
13202 start_matching = true;
13203 }
13204
13205 /* send personalities to the IOCatalog once */
13206 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13207 OSKext::sendAllKextPersonalitiesToCatalog(true);
13208 /*
13209 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13210 * things as active and start all the delayed matching: the
13211 * dext and codeless kext personalities should have all been
13212 * delivered via this one call.
13213 */
13214 if (!daemon_ready) {
13215 OSKext::setIOKitDaemonActive();
13216 OSKext::setDeferredLoadSucceeded(TRUE);
13217 IOService::iokitDaemonLaunched();
13218 }
13219 if (sOSKextWasResetAfterUserspaceReboot) {
13220 sOSKextWasResetAfterUserspaceReboot = false;
13221 OSKext::setIOKitDaemonActive();
13222 IOService::startDeferredMatches();
13223 }
13224 }
13225
13226 if (ret == kOSKextReturnKCLoadFailure) {
13227 ret |= kcerr;
13228 }
13229
13230 /*
13231 * Only allow this function to attempt to load the pageable and
13232 * aux KCs once per boot.
13233 */
13234 daemon_ready = true;
13235
13236 IORecursiveLockUnlock(sKextLock);
13237
13238 return ret;
13239 }
13240
13241 OSReturn
13242 OSKext::resetMutableSegments(void)
13243 {
13244 kernel_segment_command_t *seg = NULL;
13245 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13246 u_int index = 0;
13247 OSKextSavedMutableSegment *savedSegment = NULL;
13248 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
13249 OSReturn err;
13250
13251 if (!savedMutableSegments) {
13252 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13253 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13254 err = kOSKextReturnInternalError;
13255 goto finish;
13256 }
13257
13258 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
13259 if (!segmentIsMutable(seg)) {
13260 continue;
13261 }
13262 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13263 uint64_t vmsize = seg->vmsize;
13264 err = kOSKextReturnInternalError;
13265 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13266 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13267 assert(savedSegment);
13268 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13269 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13270 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13271 err = savedSegment->restoreContents(seg);
13272 if (err != kOSReturnSuccess) {
13273 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13274 }
13275 }
13276 }
13277 if (err != kOSReturnSuccess) {
13278 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13279 }
13280 }
13281 err = kOSReturnSuccess;
13282 finish:
13283 return err;
13284 }
13285
13286
13287 /*********************************************************************
13288 * Assumes sKextLock is held.
13289 *********************************************************************/
13290 /* static */
13291 OSReturn
13292 OSKext::loadKCFileSet(
13293 const char *filepath,
13294 kc_kind_t type)
13295 {
13296 #if VM_MAPPED_KEXTS
13297 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13298 OSReturn err;
13299 struct vnode *vp = NULL;
13300 void *fileset_control;
13301 off_t fsize;
13302 bool pageable = (type == KCKindPageable);
13303
13304 if ((pageable && pageableKCloaded) ||
13305 (!pageable && auxKCloaded)) {
13306 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13307 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13308
13309 return kOSKextReturnInvalidArgument;
13310 }
13311
13312 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13313 if (!pageable && !pageableKCloaded) {
13314 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13315 "Trying to load the Aux KC without loading the Pageable KC");
13316 return kOSKextReturnInvalidArgument;
13317 }
13318
13319 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13320
13321 if (fileset_control == NULL) {
13322 printf("Could not get memory control object for file %s", filepath);
13323
13324 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13325 "Could not get memory control object for file %s", filepath);
13326 return kOSKextReturnInvalidArgument;
13327 }
13328 if (vp == NULL) {
13329 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13330 "Could not find vnode for file %s", filepath);
13331 return kOSKextReturnInvalidArgument;
13332 }
13333
13334 kernel_mach_header_t *mh = NULL;
13335 uintptr_t slide = 0;
13336
13337 #if CONFIG_CSR
13338 /*
13339 * When SIP is enabled, the KC we map must be SIP-protected
13340 */
13341 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13342 struct vnode_attr va;
13343 int error;
13344 VATTR_INIT(&va);
13345 VATTR_WANTED(&va, va_flags);
13346 error = vnode_getattr(vp, &va, vfs_context_current());
13347 if (error) {
13348 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13349 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13350 err = kOSKextReturnInternalError;
13351 goto finish;
13352 }
13353 if (!(va.va_flags & SF_RESTRICTED)) {
13354 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13355 "Path to KC '%s' is not SIP-protected", filepath);
13356 err = kOSKextReturnInvalidArgument;
13357 goto finish;
13358 }
13359 }
13360 #endif
13361
13362 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13363 if (err) {
13364 printf("KextLog: mapKCFileSet returned %d\n", err);
13365
13366 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13367 "mapKCFileSet returned %d\n", err);
13368
13369 err = kOSKextReturnInvalidArgument;
13370 }
13371
13372 #if CONFIG_CSR
13373 finish:
13374 #endif
13375 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13376 assert(vp != NULL);
13377 if (err == kOSReturnSuccess) {
13378 PE_set_kc_vp(type, vp);
13379 if (pageable) {
13380 pageableKCloaded = true;
13381 } else {
13382 auxKCloaded = true;
13383 }
13384 } else {
13385 vnode_put(vp);
13386 }
13387
13388 return err;
13389 #else
13390 (void)filepath;
13391 (void)type;
13392 return kOSKextReturnUnsupported;
13393 #endif // VM_MAPPED_KEXTS
13394 }
13395
13396 #if defined(__x86_64__) || defined(__i386__)
13397 /*********************************************************************
13398 * Assumes sKextLock is held.
13399 *********************************************************************/
13400 /* static */
13401 OSReturn
13402 OSKext::mapKCFileSet(
13403 void *control,
13404 vm_size_t fsize,
13405 kernel_mach_header_t **mhp,
13406 off_t file_offset,
13407 uintptr_t *slidep,
13408 bool pageable,
13409 void *map_entry_list)
13410 {
13411 bool fileset_load = false;
13412 kern_return_t ret;
13413 OSReturn err;
13414 kernel_section_t *infoPlistSection = NULL;
13415 OSDictionary *infoDict = NULL;
13416
13417 OSSharedPtr<OSObject> parsedXML;
13418 OSSharedPtr<OSString> errorString;
13419 OSSharedPtr<OSData> loaded_kcUUID;
13420
13421 /* Check if initial load for file set */
13422 if (*mhp == NULL) {
13423 fileset_load = true;
13424
13425 /* Get a page aligned address from kext map to map the file */
13426 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13427 if (pagealigned_addr == 0) {
13428 return kOSKextReturnNoMemory;
13429 }
13430
13431 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13432
13433 /* Allocate memory for bailout mechanism */
13434 map_entry_list = allocate_kcfileset_map_entry_list();
13435 if (map_entry_list == NULL) {
13436 return kOSKextReturnNoMemory;
13437 }
13438 }
13439
13440 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13441 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13442 /* mhp and slideptr are updated by mapKCTextSegment */
13443 if (err) {
13444 if (fileset_load) {
13445 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13446 }
13447 return err;
13448 }
13449
13450 /* Initialize the kc header globals */
13451 if (fileset_load) {
13452 if (pageable) {
13453 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13454 } else {
13455 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13456 }
13457 }
13458
13459 /* Iterate through all the segments and map necessary segments */
13460 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13461 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13462 vm_map_offset_t start;
13463 kernel_mach_header_t *k_mh = NULL;
13464 kernel_segment_command_t * seg = NULL;
13465 struct fileset_entry_command *fse = NULL;
13466
13467 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13468 seg = (kernel_segment_command_t *)lcp;
13469 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13470 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13471 fse = (struct fileset_entry_command *)lcp;
13472 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13473
13474 /* Map the segments of the mach-o binary */
13475 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13476 if (err) {
13477 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13478 return kOSKextReturnInvalidArgument;
13479 }
13480 continue;
13481 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13482 /* Check if the Aux KC is built pageable style */
13483 if (!pageable && !fileset_load && !auxKCloaded) {
13484 resetAuxKCSegmentOnUnload = true;
13485 }
13486 continue;
13487 } else {
13488 continue;
13489 }
13490
13491 if (fileset_load) {
13492 if (seg->vmsize == 0) {
13493 continue;
13494 }
13495
13496 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13497 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13498 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13499 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13500 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13501 continue;
13502 }
13503 } else {
13504 if (seg->vmsize == 0) {
13505 continue;
13506 }
13507
13508 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13509 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13510 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13511 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13512 continue;
13513 }
13514 }
13515
13516 ret = vm_map_kcfileset_segment(
13517 &start, seg->vmsize,
13518 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13519
13520 if (ret != KERN_SUCCESS) {
13521 if (fileset_load) {
13522 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13523 }
13524 return kOSKextReturnInvalidArgument;
13525 }
13526 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13527 }
13528
13529 /* Return if regular mach-o */
13530 if (!fileset_load) {
13531 return 0;
13532 }
13533
13534 /*
13535 * Fixup for the Pageable KC and the Aux KC is done by
13536 * i386_slide_kext_collection_mh_addrs, but it differs in
13537 * following ways:
13538 *
13539 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13540 * The fixup of kext segments and kext load commands are done at kext
13541 * load time by calling i386_slide_individual_kext.
13542 *
13543 * AuxKC old style: Fixup all the segments and all the load commands.
13544 *
13545 * AuxKC pageable style: Same as the Pageable KC.
13546 */
13547 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13548 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13549 if (ret != KERN_SUCCESS) {
13550 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13551 return kOSKextReturnInvalidArgument;
13552 }
13553
13554 /* Get the prelink info dictionary */
13555 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13556 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13557 if (parsedXML) {
13558 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13559 }
13560
13561 if (!infoDict) {
13562 const char *errorCString = "(unknown error)";
13563
13564 if (errorString && errorString->getCStringNoCopy()) {
13565 errorCString = errorString->getCStringNoCopy();
13566 } else if (parsedXML) {
13567 errorCString = "not a dictionary";
13568 }
13569 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13570 "Error unserializing kext info plist section: %s.", errorCString);
13571 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13572 return kOSKextReturnInvalidArgument;
13573 }
13574
13575 /* Validate that the Kext Collection is prelinked to the loaded KC */
13576 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13577 if (err) {
13578 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13579 return kOSKextReturnInvalidArgument;
13580 }
13581
13582 /* Set Protection of Segments */
13583 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13584
13585 OSKext::addKextsFromKextCollection(*mhp,
13586 infoDict, kPrelinkTextSegment,
13587 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13588
13589 /* Copy in the KC UUID */
13590 if (!loaded_kcUUID) {
13591 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13592 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13593 } else if (pageable) {
13594 pageablekc_uuid_valid = TRUE;
13595 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13596 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13597 } else {
13598 auxkc_uuid_valid = TRUE;
13599 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13600 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13601 }
13602
13603 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13604
13605 return 0;
13606 }
13607
13608 /*********************************************************************
13609 * Assumes sKextLock is held.
13610 *********************************************************************/
13611 /* static */
13612 OSReturn
13613 OSKext::mapKCTextSegment(
13614 void *control,
13615 kernel_mach_header_t **mhp,
13616 off_t file_offset,
13617 uintptr_t *slidep,
13618 void *map_entry_list)
13619 {
13620 kern_return_t ret;
13621 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13622 PAGE_MASK);
13623 vm_map_offset_t load_command_map_size = 0;
13624 kernel_mach_header_t *base_mh = *mhp;
13625
13626 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13627 ret = vm_map_kcfileset_segment(
13628 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13629 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13630
13631 if (ret != KERN_SUCCESS) {
13632 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13633
13634 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13635 "Failed to map mach header of kc fileset with error %d", ret);
13636 return kOSKextReturnInvalidArgument;
13637 }
13638
13639 if (slidep) {
13640 /* Verify that it's an MH_FILESET */
13641 if (base_mh->filetype != MH_FILESET) {
13642 printf("Kext Log: mapKCTextSegment mach header filetype"
13643 " is not an MH_FILESET, it is %x", base_mh->filetype);
13644
13645 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13646 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
13647
13648 /* Unmap the mach header */
13649 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13650 return kOSKextReturnInvalidArgument;
13651 }
13652 }
13653
13654 /* Map the remaining pages of load commands */
13655 if (base_mh->sizeofcmds > mach_header_map_size) {
13656 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13657 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13658
13659 /* Map the load commands */
13660 ret = vm_map_kcfileset_segment(
13661 &load_command_addr, load_command_map_size,
13662 (memory_object_control_t)control, file_offset + mach_header_map_size,
13663 (VM_PROT_READ | VM_PROT_WRITE));
13664
13665 if (ret != KERN_SUCCESS) {
13666 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13667 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13668 "Failed to map load commands of kc fileset with error %d", ret);
13669
13670 /* Unmap the mach header */
13671 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13672 return kOSKextReturnInvalidArgument;
13673 }
13674 }
13675
13676 kernel_segment_command_t *text_seg;
13677 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13678
13679 /* Calculate the slide and vm addr of mach header */
13680 if (slidep) {
13681 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13682 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13683 }
13684
13685 /* Cache the text segment size and file offset before unmapping */
13686 vm_map_offset_t text_segment_size = text_seg->vmsize;
13687 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13688 vm_prot_t text_maxprot = text_seg->maxprot;
13689
13690 /* Unmap the first page and loadcommands and map the text segment */
13691 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13692 assert(ret == KERN_SUCCESS);
13693
13694 if (load_command_map_size) {
13695 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13696 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13697 assert(ret == KERN_SUCCESS);
13698 }
13699
13700 /* Map the text segment at actual vm addr specified in fileset */
13701 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13702 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13703 if (ret != KERN_SUCCESS) {
13704 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13705 "Failed to map Text segment of kc fileset with error %d", ret);
13706 return kOSKextReturnInvalidArgument;
13707 }
13708
13709 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13710 return 0;
13711 }
13712
13713 /*********************************************************************
13714 * Assumes sKextLock is held.
13715 *********************************************************************/
13716 /* static */
13717 OSReturn
13718 OSKext::protectKCFileSet(
13719 kernel_mach_header_t *mh,
13720 kc_kind_t type)
13721 {
13722 vm_map_t kext_map = g_kext_map;
13723 kernel_segment_command_t * seg = NULL;
13724 vm_map_offset_t start = 0;
13725 vm_map_offset_t end = 0;
13726 OSReturn ret = 0;
13727
13728 /* Set VM permissions */
13729 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13730 while (seg) {
13731 start = round_page(seg->vmaddr);
13732 end = trunc_page(seg->vmaddr + seg->vmsize);
13733
13734 /*
13735 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13736 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13737 * for the Aux KC as well.
13738 */
13739 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13740 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13741 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13742 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13743 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13744 ret = OSKext_protect((kernel_mach_header_t *)mh,
13745 kext_map, start, end, seg->maxprot, TRUE, type);
13746 if (ret != KERN_SUCCESS) {
13747 printf("OSKext protect failed with error %d", ret);
13748 return kOSKextReturnInvalidArgument;
13749 }
13750
13751 ret = OSKext_protect((kernel_mach_header_t *)mh,
13752 kext_map, start, end, seg->initprot, FALSE, type);
13753 if (ret != KERN_SUCCESS) {
13754 printf("OSKext protect failed with error %d", ret);
13755 return kOSKextReturnInvalidArgument;
13756 }
13757
13758 ret = OSKext_wire((kernel_mach_header_t *)mh,
13759 kext_map, start, end, seg->initprot, FALSE, type);
13760 if (ret != KERN_SUCCESS) {
13761 printf("OSKext wire failed with error %d", ret);
13762 return kOSKextReturnInvalidArgument;
13763 }
13764 }
13765
13766 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13767 }
13768
13769 return 0;
13770 }
13771
13772 /*********************************************************************
13773 * Assumes sKextLock is held.
13774 *********************************************************************/
13775 /* static */
13776 void
13777 OSKext::freeKCFileSetcontrol(void)
13778 {
13779 PE_reset_all_kc_vp();
13780 }
13781
13782 /*********************************************************************
13783 * Assumes sKextLock is held.
13784 *
13785 * resetKCFileSetSegments: Kext start function expects data segment to
13786 * be pristine on every load, unmap the dirty segments on unload and
13787 * remap them from FileSet on disk. Remap all segments of kext since
13788 * fixups are done per kext and not per segment.
13789 *********************************************************************/
13790 OSReturn
13791 OSKext::resetKCFileSetSegments(void)
13792 {
13793 kernel_segment_command_t *seg = NULL;
13794 kernel_segment_command_t *text_seg;
13795 uint32_t text_fileoff;
13796 kernel_mach_header_t *k_mh = NULL;
13797 uintptr_t slide;
13798 struct vnode *vp = NULL;
13799 void *fileset_control = NULL;
13800 bool pageable = (kc_type == KCKindPageable);
13801 OSReturn err;
13802 kern_return_t kr;
13803
13804 /* Check the vnode reference is still available */
13805 vp = (struct vnode *)PE_get_kc_vp(kc_type);
13806 if (vp == NULL) {
13807 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13808 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
13809 return kOSKextReturnInternalError;
13810 }
13811
13812 fileset_control = ubc_getobject(vp, 0);
13813 assert(fileset_control != NULL);
13814
13815 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13816 "Kext %s resetting all segments", getIdentifierCString());
13817
13818 k_mh = (kernel_mach_header_t *)kmod_info->address;
13819 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
13820 text_fileoff = text_seg->fileoff;
13821 slide = PE_get_kc_slide(kc_type);
13822
13823 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
13824 while (seg) {
13825 if (seg->vmsize == 0) {
13826 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13827 continue;
13828 }
13829
13830 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13831 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13832 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13833 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13834 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13835 continue;
13836 }
13837
13838 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
13839 assert(kr == KERN_SUCCESS);
13840 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13841 }
13842
13843 /* Unmap the text segment */
13844 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
13845 assert(kr == KERN_SUCCESS);
13846
13847 /* Map all the segments of the kext */
13848 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
13849 if (err) {
13850 panic("Could not reset segments of a mapped kext, error %x", err);
13851 }
13852
13853 /* Update address in kmod_info, since it has been reset */
13854 if (kmod_info->address) {
13855 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
13856 }
13857
13858 return 0;
13859 }
13860
13861 /*********************************************************************
13862 * Mechanism to track all segment mapping while mapping KC fileset.
13863 *********************************************************************/
13864
13865 struct kcfileset_map_entry {
13866 vm_map_offset_t me_start;
13867 vm_map_offset_t me_size;
13868 };
13869
13870 struct kcfileset_map_entry_list {
13871 int kme_list_count;
13872 int kme_list_index;
13873 struct kcfileset_map_entry kme_list[];
13874 };
13875
13876 #define KCFILESET_MAP_ENTRY_MAX (16380)
13877
13878 static void *
13879 allocate_kcfileset_map_entry_list(void)
13880 {
13881 struct kcfileset_map_entry_list *entry_list;
13882
13883 entry_list = kalloc_type(struct kcfileset_map_entry_list,
13884 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
13885
13886 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
13887 entry_list->kme_list_index = 0;
13888 return entry_list;
13889 }
13890
13891 static void
13892 add_kcfileset_map_entry(
13893 void *map_entry_list,
13894 vm_map_offset_t start,
13895 vm_map_offset_t size)
13896 {
13897 if (map_entry_list == NULL) {
13898 return;
13899 }
13900
13901 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
13902
13903 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
13904 panic("Ran out of map kc fileset list");
13905 }
13906
13907 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
13908 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
13909
13910 entry_list->kme_list_index++;
13911 }
13912
13913 static void
13914 deallocate_kcfileset_map_entry_list_and_unmap_entries(
13915 void *map_entry_list,
13916 boolean_t unmap_entries,
13917 bool pageable)
13918 {
13919 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
13920
13921 if (unmap_entries) {
13922 for (int i = 0; i < entry_list->kme_list_index; i++) {
13923 kern_return_t ret;
13924 ret = vm_unmap_kcfileset_segment(
13925 &(entry_list->kme_list[i].me_start),
13926 entry_list->kme_list[i].me_size);
13927 assert(ret == KERN_SUCCESS);
13928 }
13929
13930 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
13931 }
13932
13933 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
13934 KCFILESET_MAP_ENTRY_MAX, entry_list);
13935 }
13936
13937 /*********************************************************************
13938 * Mechanism to map kext segment.
13939 *********************************************************************/
13940
13941 kern_return_t
13942 vm_map_kcfileset_segment(
13943 vm_map_offset_t *start,
13944 vm_map_offset_t size,
13945 void *control,
13946 vm_object_offset_t fileoffset,
13947 vm_prot_t max_prot)
13948 {
13949 vm_map_kernel_flags_t vmk_flags = {
13950 .vmf_fixed = true,
13951 .vmkf_no_copy_on_read = true,
13952 .vmkf_cs_enforcement_override = true,
13953 .vm_tag = VM_KERN_MEMORY_OSKEXT,
13954 };
13955 kern_return_t ret;
13956
13957 /* Add Write to max prot to allow fixups */
13958 max_prot = max_prot | VM_PROT_WRITE;
13959
13960 /*
13961 * Map the segments from file as COPY mappings to
13962 * make sure changes on disk to the file does not affect
13963 * mapped segments.
13964 */
13965 ret = vm_map_enter_mem_object_control(
13966 g_kext_map,
13967 start,
13968 size,
13969 (mach_vm_offset_t)0,
13970 vmk_flags,
13971 (memory_object_control_t)control,
13972 fileoffset,
13973 TRUE, /* copy */
13974 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
13975 VM_INHERIT_NONE);
13976
13977 return ret;
13978 }
13979
13980 kern_return_t
13981 vm_unmap_kcfileset_segment(
13982 vm_map_offset_t *start,
13983 vm_map_offset_t size)
13984 {
13985 return mach_vm_deallocate(g_kext_map, *start, size);
13986 }
13987
13988 #endif //(__x86_64__) || defined(__i386__)
13989
13990 /*********************************************************************
13991 * Assumes sKextLock is held.
13992 *********************************************************************/
13993 /* static */
13994 OSReturn
13995 OSKext::validateKCFileSetUUID(
13996 OSDictionary *infoDict,
13997 kc_kind_t type)
13998 {
13999 OSReturn ret = kOSReturnSuccess;
14000
14001 if (!kernelcache_uuid_valid) {
14002 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14003 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
14004 ret = kOSKextReturnInvalidArgument;
14005 goto finish;
14006 }
14007 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
14008 if (ret != 0) {
14009 goto finish;
14010 }
14011
14012 #if defined(__x86_64__) || defined(__i386__)
14013 /* Check if the Aux KC is prelinked to correct Pageable KC */
14014 if (type == KCKindAuxiliary) {
14015 if (!pageablekc_uuid_valid) {
14016 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14017 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
14018 ret = kOSKextReturnInvalidArgument;
14019 goto finish;
14020 }
14021 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
14022 if (ret != 0) {
14023 goto finish;
14024 }
14025 }
14026 #endif //(__x86_64__) || defined(__i386__)
14027
14028 printf("KextLog: Collection UUID matches with loaded KCs.\n");
14029 finish:
14030 return ret;
14031 }
14032
14033 /*********************************************************************
14034 * Assumes sKextLock is held.
14035 *********************************************************************/
14036 /* static */
14037 OSReturn
14038 OSKext::validateKCUUIDfromPrelinkInfo(
14039 uuid_t *loaded_kcuuid,
14040 kc_kind_t type,
14041 OSDictionary *infoDict,
14042 const char *uuid_key)
14043 {
14044 /* extract the UUID from the dictionary */
14045 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
14046 if (!prelinkinfoKCUUID) {
14047 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14048 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
14049 return kOSKextReturnInvalidArgument;
14050 }
14051
14052 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
14053 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14054 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
14055 return kOSKextReturnInvalidArgument;
14056 }
14057
14058 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
14059 prelinkinfoKCUUID->getLength())) {
14060 OSData *info_dict_uuid;
14061 uuid_string_t info_dict_uuid_str = {};
14062 uuid_string_t expected_uuid_str = {};
14063 uuid_string_t given_uuid_str = {};
14064 uuid_t given_uuid;
14065
14066 /* extract the KC UUID from the dictionary */
14067 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
14068 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
14069 uuid_t tmp_uuid;
14070 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
14071 uuid_unparse(tmp_uuid, info_dict_uuid_str);
14072 }
14073
14074 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
14075 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
14076 uuid_unparse(given_uuid, given_uuid_str);
14077
14078 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14079 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14080 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14081 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14082 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14083 if (type == KCKindPageable && sPanicOnKCMismatch) {
14084 panic("System KC UUID %s linked against %s, but %s is loaded",
14085 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14086 }
14087 return kOSKextReturnInvalidArgument;
14088 }
14089
14090 return 0;
14091 }
14092
14093 /*********************************************************************
14094 * Assumes sKextLock is held.
14095 *********************************************************************/
14096 /* static */
14097 OSReturn
14098 OSKext::dispatchResource(OSDictionary * requestDict)
14099 {
14100 OSReturn result = kOSReturnError;
14101 OSSharedPtr<OSDictionary> callbackRecord;
14102 OSNumber * requestTag = NULL; // do not release
14103 OSNumber * requestResult = NULL; // do not release
14104 OSData * dataObj = NULL; // do not release
14105 uint32_t dataLength = 0;
14106 const void * dataPtr = NULL; // do not free
14107 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14108 OSKextRequestResourceCallback callback = NULL;
14109 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14110 void * context = NULL; // do not free
14111 OSSharedPtr<OSKext> callbackKext;
14112
14113 /* Get the args from the request. Right now we need the tag
14114 * to look up the callback record, and the result for invoking the callback.
14115 */
14116 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14117 kKextRequestArgumentRequestTagKey));
14118 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14119 kKextRequestArgumentResultKey));
14120 if (!requestTag || !requestResult) {
14121 result = kOSKextReturnInvalidArgument;
14122 goto finish;
14123 }
14124
14125 /* Look for a callback record matching this request's tag.
14126 */
14127 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
14128 if (result != kOSReturnSuccess) {
14129 goto finish;
14130 }
14131
14132 /*****
14133 * Get the context pointer of the callback record (if there is one).
14134 */
14135 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14136 callbackRecord.get(), kKextRequestArgumentContextKey));
14137 context = _OSKextExtractPointer(contextWrapper);
14138 if (contextWrapper && !context) {
14139 goto finish;
14140 }
14141
14142 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14143 _OSKextGetRequestArgument(callbackRecord.get(),
14144 kKextRequestArgumentCallbackKey));
14145 callback = _OSKextExtractCallbackPointer(callbackWrapper);
14146 if (!callback) {
14147 goto finish;
14148 }
14149
14150 /* Check for a data obj. We might not have one and that's ok, that means
14151 * we didn't find the requested resource, and we still have to tell the
14152 * caller that via the callback.
14153 */
14154 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14155 kKextRequestArgumentValueKey));
14156 if (dataObj) {
14157 dataPtr = dataObj->getBytesNoCopy();
14158 dataLength = dataObj->getLength();
14159 }
14160
14161 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
14162 if (!callbackKext) {
14163 OSKextLog(/* kext */ NULL,
14164 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14165 "Can't invoke callback for resource request; ");
14166 goto finish;
14167 }
14168 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14169 OSKextLog(/* kext */ NULL,
14170 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14171 "Can't invoke kext resource callback; ");
14172 goto finish;
14173 }
14174
14175 (void)callback(requestTag->unsigned32BitValue(),
14176 (OSReturn)requestResult->unsigned32BitValue(),
14177 dataPtr, dataLength, context);
14178
14179 result = kOSReturnSuccess;
14180
14181 finish:
14182 return result;
14183 }
14184
14185 /*********************************************************************
14186 * Assumes sKextLock is held.
14187 *********************************************************************/
14188 /* static */
14189 OSReturn
14190 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14191 {
14192 OSSharedPtr<OSDictionary> missingIDs;
14193 OSArray *bundleIDList = NULL; // do not release
14194
14195 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14196 requestDict, kKextRequestArgumentMissingBundleIDs));
14197 if (!bundleIDList) {
14198 return kOSKextReturnInvalidArgument;
14199 }
14200
14201 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
14202 if (!missingIDs) {
14203 return kOSKextReturnNoMemory;
14204 }
14205
14206 uint32_t count, i;
14207 count = bundleIDList->getCount();
14208 for (i = 0; i < count; i++) {
14209 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14210 if (thisID) {
14211 missingIDs->setObject(thisID, kOSBooleanFalse);
14212 }
14213 }
14214
14215 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
14216
14217 return kOSReturnSuccess;
14218 }
14219
14220 /*********************************************************************
14221 * Assumes sKextLock is held.
14222 *********************************************************************/
14223 /* static */
14224 OSReturn
14225 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14226 {
14227 bool loadable = true;
14228 if (!kextIdentifier) {
14229 return kOSKextReturnInvalidArgument;
14230 }
14231
14232 if (requestDict) {
14233 OSBoolean *loadableArg;
14234 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14235 requestDict, kKextRequestArgumentBundleAvailability));
14236 /* If we find the "Bundle Available" arg, and it's false, then
14237 * mark the bundle ID as _not_ loadable
14238 */
14239 if (loadableArg && !loadableArg->getValue()) {
14240 loadable = false;
14241 }
14242 }
14243
14244 if (!sNonLoadableKextsByID) {
14245 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
14246 }
14247
14248 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
14249
14250 OSKextLog(/* kext */ NULL,
14251 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14252 "KextLog: AuxKC bundle %s marked as %s",
14253 kextIdentifier->getCStringNoCopy(),
14254 (loadable ? "loadable" : "NOT loadable"));
14255
14256 return kOSReturnSuccess;
14257 }
14258
14259 /*********************************************************************
14260 *********************************************************************/
14261 /* static */
14262 void
14263 OSKext::invokeRequestCallback(
14264 OSDictionary * callbackRecord,
14265 OSReturn callbackResult)
14266 {
14267 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
14268 OSSharedPtr<OSNumber> resultNum;
14269
14270 if (!predicate) {
14271 goto finish;
14272 }
14273
14274 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
14275 8 * sizeof(callbackResult));
14276 if (!resultNum) {
14277 goto finish;
14278 }
14279
14280 /* Insert the result into the callback record and dispatch it as if it
14281 * were the reply coming down from user space.
14282 */
14283 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
14284 resultNum.get());
14285
14286 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14287 /* This removes the pending callback record.
14288 */
14289 OSKext::dispatchResource(callbackRecord);
14290 }
14291
14292 finish:
14293 return;
14294 }
14295
14296 /*********************************************************************
14297 * Assumes sKextLock is held.
14298 *********************************************************************/
14299 /* static */
14300 OSReturn
14301 OSKext::cancelRequest(
14302 OSKextRequestTag requestTag,
14303 void ** contextOut)
14304 {
14305 OSReturn result = kOSKextReturnNoMemory;
14306 OSSharedPtr<OSDictionary> callbackRecord;
14307 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14308
14309 IORecursiveLockLock(sKextLock);
14310 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14311 callbackRecord);
14312 IORecursiveLockUnlock(sKextLock);
14313
14314 if (result == kOSReturnSuccess && contextOut) {
14315 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14316 _OSKextGetRequestArgument(callbackRecord.get(),
14317 kKextRequestArgumentContextKey));
14318 *contextOut = _OSKextExtractPointer(contextWrapper);
14319 }
14320
14321 return result;
14322 }
14323
14324 /*********************************************************************
14325 * Assumes sKextLock is held.
14326 *********************************************************************/
14327 void
14328 OSKext::invokeOrCancelRequestCallbacks(
14329 OSReturn callbackResult,
14330 bool invokeFlag)
14331 {
14332 unsigned int count, i;
14333
14334 count = sRequestCallbackRecords->getCount();
14335 if (!count) {
14336 goto finish;
14337 }
14338
14339 i = count - 1;
14340 do {
14341 OSDictionary * request = OSDynamicCast(OSDictionary,
14342 sRequestCallbackRecords->getObject(i));
14343
14344 if (!request) {
14345 continue;
14346 }
14347 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14348 _OSKextGetRequestArgument(request,
14349 kKextRequestArgumentCallbackKey));
14350
14351 if (!callbackWrapper) {
14352 sRequestCallbackRecords->removeObject(i);
14353 continue;
14354 }
14355
14356 vm_address_t callbackAddress = (vm_address_t)
14357 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14358
14359 if ((kmod_info->address <= callbackAddress) &&
14360 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14361 if (invokeFlag) {
14362 /* This removes the callback record.
14363 */
14364 invokeRequestCallback(request, callbackResult);
14365 } else {
14366 sRequestCallbackRecords->removeObject(i);
14367 }
14368 }
14369 } while (i--);
14370
14371 finish:
14372 return;
14373 }
14374
14375 /*********************************************************************
14376 * Assumes sKextLock is held.
14377 *********************************************************************/
14378 uint32_t
14379 OSKext::countRequestCallbacks(void)
14380 {
14381 uint32_t result = 0;
14382 unsigned int count, i;
14383
14384 count = sRequestCallbackRecords->getCount();
14385 if (!count) {
14386 goto finish;
14387 }
14388
14389 i = count - 1;
14390 do {
14391 OSDictionary * request = OSDynamicCast(OSDictionary,
14392 sRequestCallbackRecords->getObject(i));
14393
14394 if (!request) {
14395 continue;
14396 }
14397 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14398 _OSKextGetRequestArgument(request,
14399 kKextRequestArgumentCallbackKey));
14400
14401 if (!callbackWrapper) {
14402 continue;
14403 }
14404
14405 vm_address_t callbackAddress = (vm_address_t)
14406 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14407
14408 if ((kmod_info->address <= callbackAddress) &&
14409 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14410 result++;
14411 }
14412 } while (i--);
14413
14414 finish:
14415 return result;
14416 }
14417
14418 /*********************************************************************
14419 *********************************************************************/
14420 static OSReturn
14421 _OSKextCreateRequest(
14422 const char * predicate,
14423 OSSharedPtr<OSDictionary> & requestR)
14424 {
14425 OSReturn result = kOSKextReturnNoMemory;
14426 OSSharedPtr<OSDictionary> request;
14427
14428 request = OSDictionary::withCapacity(2);
14429 if (!request) {
14430 goto finish;
14431 }
14432 result = _OSDictionarySetCStringValue(request.get(),
14433 kKextRequestPredicateKey, predicate);
14434 if (result != kOSReturnSuccess) {
14435 goto finish;
14436 }
14437 result = kOSReturnSuccess;
14438
14439 finish:
14440 if (result == kOSReturnSuccess) {
14441 requestR = os::move(request);
14442 }
14443
14444 return result;
14445 }
14446
14447 /*********************************************************************
14448 *********************************************************************/
14449 static OSString *
14450 _OSKextGetRequestPredicate(OSDictionary * requestDict)
14451 {
14452 return OSDynamicCast(OSString,
14453 requestDict->getObject(kKextRequestPredicateKey));
14454 }
14455
14456 /*********************************************************************
14457 *********************************************************************/
14458 static OSObject *
14459 _OSKextGetRequestArgument(
14460 OSDictionary * requestDict,
14461 const char * argName)
14462 {
14463 OSDictionary * args = OSDynamicCast(OSDictionary,
14464 requestDict->getObject(kKextRequestArgumentsKey));
14465 if (args) {
14466 return args->getObject(argName);
14467 }
14468 return NULL;
14469 }
14470
14471 /*********************************************************************
14472 *********************************************************************/
14473 static bool
14474 _OSKextSetRequestArgument(
14475 OSDictionary * requestDict,
14476 const char * argName,
14477 OSMetaClassBase * value)
14478 {
14479 OSDictionary * args = OSDynamicCast(OSDictionary,
14480 requestDict->getObject(kKextRequestArgumentsKey));
14481 OSSharedPtr<OSDictionary> newArgs;
14482 if (!args) {
14483 newArgs = OSDictionary::withCapacity(2);
14484 args = newArgs.get();
14485 if (!args) {
14486 goto finish;
14487 }
14488 requestDict->setObject(kKextRequestArgumentsKey, args);
14489 }
14490 if (args) {
14491 return args->setObject(argName, value);
14492 }
14493 finish:
14494 return false;
14495 }
14496
14497 /*********************************************************************
14498 *********************************************************************/
14499 template <typename T>
14500 static T *
14501 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
14502 {
14503 if (!wrapper) {
14504 return nullptr;
14505 }
14506 return wrapper->getRef();
14507 }
14508
14509 /*********************************************************************
14510 *********************************************************************/
14511 static OSKextRequestResourceCallback
14512 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14513 {
14514 if (!wrapper) {
14515 return nullptr;
14516 }
14517 return wrapper->getRef();
14518 }
14519
14520
14521 /*********************************************************************
14522 *********************************************************************/
14523 static OSReturn
14524 _OSDictionarySetCStringValue(
14525 OSDictionary * dict,
14526 const char * cKey,
14527 const char * cValue)
14528 {
14529 OSReturn result = kOSKextReturnNoMemory;
14530 OSSharedPtr<const OSSymbol> key;
14531 OSSharedPtr<OSString> value;
14532
14533 key = OSSymbol::withCString(cKey);
14534 value = OSString::withCString(cValue);
14535 if (!key || !value) {
14536 goto finish;
14537 }
14538 if (dict->setObject(key.get(), value.get())) {
14539 result = kOSReturnSuccess;
14540 }
14541
14542 finish:
14543 return result;
14544 }
14545
14546 /*********************************************************************
14547 *********************************************************************/
14548 static bool
14549 _OSArrayContainsCString(
14550 OSArray * array,
14551 const char * cString)
14552 {
14553 bool result = false;
14554 OSSharedPtr<const OSSymbol> symbol;
14555 uint32_t count, i;
14556
14557 if (!array || !cString) {
14558 goto finish;
14559 }
14560
14561 symbol = OSSymbol::withCStringNoCopy(cString);
14562 if (!symbol) {
14563 goto finish;
14564 }
14565
14566 count = array->getCount();
14567 for (i = 0; i < count; i++) {
14568 OSObject * thisObject = array->getObject(i);
14569 if (symbol->isEqualTo(thisObject)) {
14570 result = true;
14571 goto finish;
14572 }
14573 }
14574
14575 finish:
14576 return result;
14577 }
14578
14579 #if CONFIG_KXLD
14580 /*********************************************************************
14581 * We really only care about boot / system start up related kexts.
14582 * We return true if we're less than REBUILD_MAX_TIME since start up,
14583 * otherwise return false.
14584 *********************************************************************/
14585 bool
14586 _OSKextInPrelinkRebuildWindow(void)
14587 {
14588 static bool outside_the_window = false;
14589 AbsoluteTime my_abstime;
14590 UInt64 my_ns;
14591 SInt32 my_secs;
14592
14593 if (outside_the_window) {
14594 return false;
14595 }
14596 clock_get_uptime(&my_abstime);
14597 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14598 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14599 if (my_secs > REBUILD_MAX_TIME) {
14600 outside_the_window = true;
14601 return false;
14602 }
14603 return true;
14604 }
14605 #endif /* CONFIG_KXLD */
14606
14607 /*********************************************************************
14608 *********************************************************************/
14609 bool
14610 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14611 {
14612 int unLoadedCount, i;
14613 bool result = false;
14614
14615 IORecursiveLockLock(sKextLock);
14616
14617 if (sUnloadedPrelinkedKexts == NULL) {
14618 goto finish;
14619 }
14620 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14621 if (unLoadedCount == 0) {
14622 goto finish;
14623 }
14624
14625 for (i = 0; i < unLoadedCount; i++) {
14626 const OSSymbol * myBundleID; // do not release
14627
14628 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14629 if (!myBundleID) {
14630 continue;
14631 }
14632 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
14633 result = true;
14634 break;
14635 }
14636 }
14637 finish:
14638 IORecursiveLockUnlock(sKextLock);
14639 return result;
14640 }
14641
14642 #if PRAGMA_MARK
14643 #pragma mark Personalities (IOKit Drivers)
14644 #endif
14645 /*********************************************************************
14646 *********************************************************************/
14647 /* static */
14648 OSSharedPtr<OSArray>
14649 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14650 {
14651 OSSharedPtr<OSArray> result;
14652 OSSharedPtr<OSCollectionIterator> kextIterator;
14653 OSSharedPtr<OSArray> personalities;
14654
14655 OSString * kextID = NULL; // do not release
14656 OSKext * theKext = NULL; // do not release
14657
14658 IORecursiveLockLock(sKextLock);
14659
14660 /* Let's conservatively guess that any given kext has around 3
14661 * personalities for now.
14662 */
14663 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
14664 if (!result) {
14665 goto finish;
14666 }
14667
14668 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
14669 if (!kextIterator) {
14670 goto finish;
14671 }
14672
14673 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14674 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14675 if (theKext->flags.requireExplicitLoad) {
14676 OSKextLog(theKext,
14677 kOSKextLogDebugLevel |
14678 kOSKextLogLoadFlag,
14679 "Kext %s requires an explicit kextload; "
14680 "omitting its personalities.",
14681 theKext->getIdentifierCString());
14682 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14683 personalities = theKext->copyPersonalitiesArray();
14684 if (!personalities) {
14685 continue;
14686 }
14687 result->merge(personalities.get());
14688 } else {
14689 // xxx - check for better place to put this log msg
14690 OSKextLog(theKext,
14691 kOSKextLogWarningLevel |
14692 kOSKextLogLoadFlag,
14693 "Kext %s is not loadable during safe boot; "
14694 "omitting its personalities.",
14695 theKext->getIdentifierCString());
14696 }
14697 }
14698
14699 finish:
14700 IORecursiveLockUnlock(sKextLock);
14701
14702 return result;
14703 }
14704
14705 /*********************************************************************
14706 *********************************************************************/
14707 /* static */
14708 void
14709 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14710 {
14711 int numPersonalities = 0;
14712
14713 OSKextLog(/* kext */ NULL,
14714 kOSKextLogStepLevel |
14715 kOSKextLogLoadFlag,
14716 "Sending all eligible registered kexts' personalities "
14717 "to the IOCatalogue %s.",
14718 startMatching ? "and starting matching" : "but not starting matching");
14719
14720 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14721 /* filterSafeBootFlag */ true);
14722
14723 if (personalities) {
14724 gIOCatalogue->addDrivers(personalities.get(), startMatching);
14725 numPersonalities = personalities->getCount();
14726 }
14727
14728 OSKextLog(/* kext */ NULL,
14729 kOSKextLogStepLevel |
14730 kOSKextLogLoadFlag,
14731 "%d kext personalit%s sent to the IOCatalogue; %s.",
14732 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14733 startMatching ? "matching started" : "matching not started");
14734 return;
14735 }
14736
14737 /*********************************************************************
14738 * Do not make a deep copy, just convert the IOKitPersonalities dict
14739 * to an array for sending to the IOCatalogue.
14740 *********************************************************************/
14741 OSSharedPtr<OSArray>
14742 OSKext::copyPersonalitiesArray(void)
14743 {
14744 OSSharedPtr<OSArray> result;
14745 OSDictionary * personalities = NULL; // do not release
14746 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14747
14748 OSString * personalityName = NULL; // do not release
14749 OSString * personalityBundleIdentifier = NULL; // do not release
14750
14751 personalities = OSDynamicCast(OSDictionary,
14752 getPropertyForHostArch(kIOKitPersonalitiesKey));
14753 if (!personalities) {
14754 goto finish;
14755 }
14756
14757 result = OSArray::withCapacity(personalities->getCount());
14758 if (!result) {
14759 goto finish;
14760 }
14761
14762 personalitiesIterator =
14763 OSCollectionIterator::withCollection(personalities);
14764 if (!personalitiesIterator) {
14765 goto finish;
14766 }
14767 while ((personalityName = OSDynamicCast(OSString,
14768 personalitiesIterator->getNextObject()))) {
14769 OSDictionary * personality = OSDynamicCast(OSDictionary,
14770 personalities->getObject(personalityName));
14771
14772 if (personality) {
14773 /******
14774 * If the personality doesn't have a CFBundleIdentifier, or if it
14775 * differs from the kext's, insert the kext's ID so we can find it.
14776 * The publisher ID is used to remove personalities from bundles
14777 * correctly.
14778 */
14779 personalityBundleIdentifier = OSDynamicCast(OSString,
14780 personality->getObject(kCFBundleIdentifierKey));
14781
14782 if (!personalityBundleIdentifier) {
14783 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
14784 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
14785 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
14786 }
14787 }
14788
14789 result->setObject(personality);
14790 }
14791
14792 finish:
14793 return result;
14794 }
14795
14796 /*********************************************************************
14797 * Might want to change this to a bool return?
14798 *********************************************************************/
14799 OSReturn
14800 OSKext::sendPersonalitiesToCatalog(
14801 bool startMatching,
14802 OSArray * personalityNames)
14803 {
14804 OSReturn result = kOSReturnSuccess;
14805 OSSharedPtr<OSArray> personalitiesToSend;
14806 OSDictionary * kextPersonalities = NULL; // do not release
14807 int count, i;
14808
14809 if (!sLoadEnabled) {
14810 OSKextLog(this,
14811 kOSKextLogErrorLevel |
14812 kOSKextLogLoadFlag,
14813 "Kext loading is disabled (attempt to start matching for kext %s).",
14814 getIdentifierCString());
14815 result = kOSKextReturnDisabled;
14816 goto finish;
14817 }
14818
14819 if (sSafeBoot && !isLoadableInSafeBoot()) {
14820 OSKextLog(this,
14821 kOSKextLogErrorLevel |
14822 kOSKextLogLoadFlag,
14823 "Kext %s is not loadable during safe boot; "
14824 "not sending personalities to the IOCatalogue.",
14825 getIdentifierCString());
14826 result = kOSKextReturnNotLoadable;
14827 goto finish;
14828 }
14829
14830 if (!personalityNames || !personalityNames->getCount()) {
14831 personalitiesToSend = copyPersonalitiesArray();
14832 } else {
14833 kextPersonalities = OSDynamicCast(OSDictionary,
14834 getPropertyForHostArch(kIOKitPersonalitiesKey));
14835 if (!kextPersonalities || !kextPersonalities->getCount()) {
14836 // not an error
14837 goto finish;
14838 }
14839 personalitiesToSend = OSArray::withCapacity(0);
14840 if (!personalitiesToSend) {
14841 result = kOSKextReturnNoMemory;
14842 goto finish;
14843 }
14844 count = personalityNames->getCount();
14845 for (i = 0; i < count; i++) {
14846 OSString * name = OSDynamicCast(OSString,
14847 personalityNames->getObject(i));
14848 if (!name) {
14849 continue;
14850 }
14851 OSDictionary * personality = OSDynamicCast(OSDictionary,
14852 kextPersonalities->getObject(name));
14853 if (personality) {
14854 personalitiesToSend->setObject(personality);
14855 }
14856 }
14857 }
14858 if (personalitiesToSend) {
14859 unsigned numPersonalities = personalitiesToSend->getCount();
14860 OSKextLog(this,
14861 kOSKextLogStepLevel |
14862 kOSKextLogLoadFlag,
14863 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
14864 getIdentifierCString(),
14865 numPersonalities,
14866 numPersonalities > 1 ? "ies" : "y",
14867 startMatching ? " and starting matching" : " but not starting matching");
14868 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
14869 }
14870 finish:
14871 return result;
14872 }
14873
14874 /*********************************************************************
14875 * xxx - We should allow removing the kext's declared personalities,
14876 * xxx - even with other bundle identifiers.
14877 *********************************************************************/
14878 void
14879 OSKext::removePersonalitiesFromCatalog(void)
14880 {
14881 OSSharedPtr<OSDictionary> personality;
14882
14883 personality = OSDictionary::withCapacity(1);
14884 if (!personality) {
14885 goto finish;
14886 }
14887 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
14888
14889 OSKextLog(this,
14890 kOSKextLogStepLevel |
14891 kOSKextLogLoadFlag,
14892 "Kext %s removing all personalities naming it from the IOCatalogue.",
14893 getIdentifierCString());
14894
14895 /* Have the IOCatalog remove all personalities matching this kext's
14896 * bundle ID and trigger matching anew.
14897 */
14898 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
14899
14900 finish:
14901 return;
14902 }
14903
14904 void
14905 OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
14906 {
14907 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
14908 return;
14909 }
14910
14911 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(1);
14912 if (!personalityToRemove) {
14913 return;
14914 }
14915
14916 /*
14917 * Create a personality dictionary with just the bundleID.
14918 * We will remove any personality that has a matching bundleID,
14919 * irrespective of which other keys are present on the dictionary.
14920 */
14921 personalityToRemove->setObject(kCFBundleIdentifierKey, getIdentifier());
14922 gIOCatalogue->exchangeDrivers(personalityToRemove.get(), upgradedPersonalities, true);
14923 }
14924
14925 #if PRAGMA_MARK
14926 #pragma mark Logging
14927 #endif
14928 /*********************************************************************
14929 * Do not call any function that takes sKextLock here!
14930 *********************************************************************/
14931 /* static */
14932 OSKextLogSpec
14933 OSKext::setUserSpaceLogFilter(
14934 OSKextLogSpec newUserLogFilter,
14935 bool captureFlag)
14936 {
14937 OSKextLogSpec result;
14938 bool allocError = false;
14939
14940 /* Do not call any function that takes sKextLoggingLock during
14941 * this critical block. That means do logging after.
14942 */
14943 IOLockLock(sKextLoggingLock);
14944
14945 result = sUserSpaceKextLogFilter;
14946 sUserSpaceKextLogFilter = newUserLogFilter;
14947
14948 if (newUserLogFilter && captureFlag &&
14949 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
14950 // xxx - do some measurements for a good initial capacity?
14951 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
14952 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
14953
14954 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
14955 allocError = true;
14956 }
14957 }
14958
14959 IOLockUnlock(sKextLoggingLock);
14960
14961 /* If the config flag itself is changing, log the state change
14962 * going both ways, before setting up the user-space log arrays,
14963 * so that this is only logged in the kernel.
14964 */
14965 if (result != newUserLogFilter) {
14966 OSKextLog(/* kext */ NULL,
14967 kOSKextLogDebugLevel |
14968 kOSKextLogGeneralFlag,
14969 "User-space log flags changed from 0x%x to 0x%x.",
14970 result, newUserLogFilter);
14971 }
14972 if (allocError) {
14973 OSKextLog(/* kext */ NULL,
14974 kOSKextLogErrorLevel |
14975 kOSKextLogGeneralFlag,
14976 "Failed to allocate user-space log message arrays.");
14977 }
14978
14979 return result;
14980 }
14981
14982 /*********************************************************************
14983 * Do not call any function that takes sKextLock here!
14984 *********************************************************************/
14985 /* static */
14986 OSSharedPtr<OSArray>
14987 OSKext::clearUserSpaceLogFilter(void)
14988 {
14989 OSSharedPtr<OSArray> result;
14990 OSKextLogSpec oldLogFilter;
14991 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
14992
14993 /* Do not call any function that takes sKextLoggingLock during
14994 * this critical block. That means do logging after.
14995 */
14996 IOLockLock(sKextLoggingLock);
14997
14998 result = OSArray::withCapacity(2);
14999 if (result) {
15000 result->setObject(sUserSpaceLogSpecArray.get());
15001 result->setObject(sUserSpaceLogMessageArray.get());
15002 }
15003 sUserSpaceLogSpecArray.reset();
15004 sUserSpaceLogMessageArray.reset();
15005
15006 oldLogFilter = sUserSpaceKextLogFilter;
15007 sUserSpaceKextLogFilter = newLogFilter;
15008
15009 IOLockUnlock(sKextLoggingLock);
15010
15011 /* If the config flag itself is changing, log the state change
15012 * going both ways, after tearing down the user-space log
15013 * arrays, so this is only logged within the kernel.
15014 */
15015 if (oldLogFilter != newLogFilter) {
15016 OSKextLog(/* kext */ NULL,
15017 kOSKextLogDebugLevel |
15018 kOSKextLogGeneralFlag,
15019 "User-space log flags changed from 0x%x to 0x%x.",
15020 oldLogFilter, newLogFilter);
15021 }
15022
15023 return result;
15024 }
15025
15026
15027 /*********************************************************************
15028 * Do not call any function that takes sKextLock here!
15029 *********************************************************************/
15030 /* static */
15031 OSKextLogSpec
15032 OSKext::getUserSpaceLogFilter(void)
15033 {
15034 OSKextLogSpec result;
15035
15036 IOLockLock(sKextLoggingLock);
15037 result = sUserSpaceKextLogFilter;
15038 IOLockUnlock(sKextLoggingLock);
15039
15040 return result;
15041 }
15042
15043 /*********************************************************************
15044 * This function is called by OSMetaClass during kernel C++ setup.
15045 * Be careful what you access here; assume only OSKext::initialize()
15046 * has been called.
15047 *
15048 * Do not call any function that takes sKextLock here!
15049 *********************************************************************/
15050 #define VTRESET "\033[0m"
15051
15052 #define VTBOLD "\033[1m"
15053 #define VTUNDER "\033[4m"
15054
15055 #define VTRED "\033[31m"
15056 #define VTGREEN "\033[32m"
15057 #define VTYELLOW "\033[33m"
15058 #define VTBLUE "\033[34m"
15059 #define VTMAGENTA "\033[35m"
15060 #define VTCYAN "\033[36m"
15061
15062 inline const char *
15063 colorForFlags(OSKextLogSpec flags)
15064 {
15065 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
15066
15067 switch (logLevel) {
15068 case kOSKextLogErrorLevel:
15069 return VTRED VTBOLD;
15070 case kOSKextLogWarningLevel:
15071 return VTRED;
15072 case kOSKextLogBasicLevel:
15073 return VTYELLOW VTUNDER;
15074 case kOSKextLogProgressLevel:
15075 return VTYELLOW;
15076 case kOSKextLogStepLevel:
15077 return VTGREEN;
15078 case kOSKextLogDetailLevel:
15079 return VTCYAN;
15080 case kOSKextLogDebugLevel:
15081 return VTMAGENTA;
15082 default:
15083 return ""; // white
15084 }
15085 }
15086
15087 inline bool
15088 logSpecMatch(
15089 OSKextLogSpec msgLogSpec,
15090 OSKextLogSpec logFilter)
15091 {
15092 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15093 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15094 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15095
15096 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15097 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15098 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15099
15100 /* Explicit messages always get logged.
15101 */
15102 if (msgLevel == kOSKextLogExplicitLevel) {
15103 return true;
15104 }
15105
15106 /* Warnings and errors are logged regardless of the flags.
15107 */
15108 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15109 return true;
15110 }
15111
15112 /* A verbose message that isn't for a logging-enabled kext and isn't global
15113 * does *not* get logged.
15114 */
15115 if (!msgKextGlobal && !filterKextGlobal) {
15116 return false;
15117 }
15118
15119 /* Warnings and errors are logged regardless of the flags.
15120 * All other messages must fit the flags and
15121 * have a level at or below the filter.
15122 *
15123 */
15124 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15125 return true;
15126 }
15127 return false;
15128 }
15129
15130 extern "C" {
15131 void
15132 OSKextLog(
15133 OSKext * aKext,
15134 OSKextLogSpec msgLogSpec,
15135 const char * format, ...)
15136 {
15137 va_list argList;
15138
15139 va_start(argList, format);
15140 OSKextVLog(aKext, msgLogSpec, format, argList);
15141 va_end(argList);
15142 }
15143
15144 void
15145 OSKextVLog(
15146 OSKext * aKext,
15147 OSKextLogSpec msgLogSpec,
15148 const char * format,
15149 va_list srcArgList)
15150 {
15151 extern int disableConsoleOutput;
15152
15153 bool logForKernel = false;
15154 bool logForUser = false;
15155 va_list argList;
15156 char stackBuffer[120];
15157 uint32_t length = 0;
15158 char * allocBuffer = NULL; // must kfree
15159 OSSharedPtr<OSNumber> logSpecNum;
15160 OSSharedPtr<OSString> logString;
15161 char * buffer = stackBuffer; // do not free
15162
15163 IOLockLock(sKextLoggingLock);
15164
15165 /* Set the kext/global bit in the message spec if we have no
15166 * kext or if the kext requests logging.
15167 */
15168 if (!aKext || aKext->flags.loggingEnabled) {
15169 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15170 }
15171
15172 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
15173 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15174 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
15175 }
15176
15177 if (!(logForKernel || logForUser)) {
15178 goto finish;
15179 }
15180
15181 /* No goto from here until past va_end()!
15182 */
15183 va_copy(argList, srcArgList);
15184 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15185 va_end(argList);
15186
15187 if (length + 1 >= sizeof(stackBuffer)) {
15188 allocBuffer = (char *)kalloc_data_tag(length + 1,
15189 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15190 if (!allocBuffer) {
15191 goto finish;
15192 }
15193
15194 /* No goto from here until past va_end()!
15195 */
15196 va_copy(argList, srcArgList);
15197 vsnprintf(allocBuffer, length + 1, format, argList);
15198 va_end(argList);
15199
15200 buffer = allocBuffer;
15201 }
15202
15203 /* If user space wants the log message, queue it up.
15204 */
15205 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15206 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
15207 logString = OSString::withCString(buffer);
15208 if (logSpecNum && logString) {
15209 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15210 sUserSpaceLogMessageArray->setObject(logString.get());
15211 }
15212 }
15213
15214 /* Always log messages from the kernel according to the kernel's
15215 * log flags.
15216 */
15217 if (logForKernel) {
15218 /* If we are in console mode and have a custom log filter,
15219 * colorize the log message.
15220 */
15221 if (!disableConsoleOutput && sBootArgLogFilterFound) {
15222 const char * color = ""; // do not free
15223 color = colorForFlags(msgLogSpec);
15224 printf("%s%s%s\n", colorForFlags(msgLogSpec),
15225 buffer, color[0] ? VTRESET : "");
15226 } else {
15227 printf("%s\n", buffer);
15228 }
15229 }
15230
15231 finish:
15232 IOLockUnlock(sKextLoggingLock);
15233
15234 if (allocBuffer) {
15235 kfree_data(allocBuffer, length + 1);
15236 }
15237 return;
15238 }
15239
15240 #if KASLR_IOREG_DEBUG
15241
15242 #define IOLOG_INDENT( the_indention ) \
15243 { \
15244 int i; \
15245 for ( i = 0; i < (the_indention); i++ ) { \
15246 IOLog(" "); \
15247 } \
15248 }
15249
15250 extern vm_offset_t vm_kernel_stext;
15251 extern vm_offset_t vm_kernel_etext;
15252 extern mach_vm_offset_t kext_alloc_base;
15253 extern mach_vm_offset_t kext_alloc_max;
15254
15255 bool ScanForAddrInObject(OSObject * theObject,
15256 int indent );
15257
15258 bool
15259 ScanForAddrInObject(OSObject * theObject,
15260 int indent)
15261 {
15262 const OSMetaClass * myTypeID;
15263 OSSharedPtr<OSCollectionIterator> myIter;
15264 OSSymbol * myKey;
15265 OSObject * myValue;
15266 bool myResult = false;
15267
15268 if (theObject == NULL) {
15269 IOLog("%s: theObject is NULL \n",
15270 __FUNCTION__);
15271 return myResult;
15272 }
15273
15274 myTypeID = OSTypeIDInst(theObject);
15275
15276 if (myTypeID == OSTypeID(OSDictionary)) {
15277 OSDictionary * myDictionary;
15278
15279 myDictionary = OSDynamicCast(OSDictionary, theObject);
15280 myIter = OSCollectionIterator::withCollection( myDictionary );
15281 if (myIter == NULL) {
15282 return myResult;
15283 }
15284
15285 // !! reset the iterator
15286 myIter->reset();
15287
15288 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15289 bool myTempResult;
15290
15291 myValue = myDictionary->getObject(myKey);
15292 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15293 if (myTempResult) {
15294 // if we ever get a true result return true
15295 myResult = true;
15296 IOLOG_INDENT(indent);
15297 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15298 }
15299 }
15300
15301 // !! release the iterator
15302 myIter.reset();
15303 } else if (myTypeID == OSTypeID(OSArray)) {
15304 OSArray * myArray;
15305
15306 myArray = OSDynamicCast(OSArray, theObject);
15307 myIter = OSCollectionIterator::withCollection(myArray);
15308 if (myIter == NULL) {
15309 return myResult;
15310 }
15311 // !! reset the iterator
15312 myIter->reset();
15313
15314 while ((myValue = myIter->getNextObject())) {
15315 bool myTempResult;
15316 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15317 if (myTempResult) {
15318 // if we ever get a true result return true
15319 myResult = true;
15320 IOLOG_INDENT(indent);
15321 IOLog("OSArray: \n");
15322 }
15323 }
15324 // !! release the iterator
15325 myIter.reset();
15326 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15327 // should we look for addresses in strings?
15328 } else if (myTypeID == OSTypeID(OSData)) {
15329 void * * myPtrPtr;
15330 unsigned int myLen;
15331 OSData * myDataObj;
15332
15333 myDataObj = OSDynamicCast(OSData, theObject);
15334 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15335 myLen = myDataObj->getLength();
15336
15337 if (myPtrPtr && myLen && myLen > 7) {
15338 int i;
15339 int myPtrCount = (myLen / sizeof(void *));
15340
15341 for (i = 0; i < myPtrCount; i++) {
15342 UInt64 numberValue = (UInt64) * (myPtrPtr);
15343
15344 if (kext_alloc_max != 0 &&
15345 numberValue >= kext_alloc_base &&
15346 numberValue < kext_alloc_max) {
15347 OSSharedPtr<OSKext> myKext;
15348 // IOLog("found OSData %p in kext map %p to %p \n",
15349 // *(myPtrPtr),
15350 // (void *) kext_alloc_base,
15351 // (void *) kext_alloc_max);
15352
15353 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15354 if (myKext) {
15355 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15356 *(myPtrPtr),
15357 myKext->getIdentifierCString());
15358 }
15359 myResult = true;
15360 }
15361 if (vm_kernel_etext != 0 &&
15362 numberValue >= vm_kernel_stext &&
15363 numberValue < vm_kernel_etext) {
15364 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15365 *(myPtrPtr),
15366 (void *) vm_kernel_stext,
15367 (void *) vm_kernel_etext);
15368 myResult = true;
15369 }
15370 myPtrPtr++;
15371 }
15372 }
15373 } else if (myTypeID == OSTypeID(OSBoolean)) {
15374 // do nothing here...
15375 } else if (myTypeID == OSTypeID(OSNumber)) {
15376 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15377
15378 UInt64 numberValue = number->unsigned64BitValue();
15379
15380 if (kext_alloc_max != 0 &&
15381 numberValue >= kext_alloc_base &&
15382 numberValue < kext_alloc_max) {
15383 OSSharedPtr<OSKext> myKext;
15384 IOLog("found OSNumber in kext map %p to %p \n",
15385 (void *) kext_alloc_base,
15386 (void *) kext_alloc_max);
15387 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15388
15389 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15390 if (myKext) {
15391 IOLog("found in kext \"%s\" \n",
15392 myKext->getIdentifierCString());
15393 }
15394
15395 myResult = true;
15396 }
15397 if (vm_kernel_etext != 0 &&
15398 numberValue >= vm_kernel_stext &&
15399 numberValue < vm_kernel_etext) {
15400 IOLog("found OSNumber in kernel text segment %p to %p \n",
15401 (void *) vm_kernel_stext,
15402 (void *) vm_kernel_etext);
15403 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15404 myResult = true;
15405 }
15406 }
15407 #if 0
15408 else {
15409 const OSMetaClass* myMetaClass = NULL;
15410
15411 myMetaClass = theObject->getMetaClass();
15412 if (myMetaClass) {
15413 IOLog("class %s \n", myMetaClass->getClassName());
15414 } else {
15415 IOLog("Unknown object \n" );
15416 }
15417 }
15418 #endif
15419
15420 return myResult;
15421 }
15422 #endif // KASLR_KEXT_DEBUG
15423 }; /* extern "C" */
15424
15425 #if PRAGMA_MARK
15426 #pragma mark Backtrace Dump & kmod_get_info() support
15427 #endif
15428 /*********************************************************************
15429 * This function must be safe to call in panic context.
15430 *********************************************************************/
15431 /* static */
15432 void
15433 OSKext::printKextsInBacktrace(
15434 vm_offset_t * addr __unused,
15435 unsigned int cnt __unused,
15436 int (* printf_func)(const char *fmt, ...) __unused,
15437 uint32_t flags __unused)
15438 {
15439 addr64_t summary_page = 0;
15440 addr64_t last_summary_page = 0;
15441 bool found_kmod = false;
15442 u_int i = 0;
15443
15444 if (kPrintKextsLock & flags) {
15445 if (!sKextSummariesLock) {
15446 return;
15447 }
15448 IOLockLock(sKextSummariesLock);
15449 }
15450
15451 if (!gLoadedKextSummaries) {
15452 (*printf_func)(" can't perform kext scan: no kext summary");
15453 goto finish;
15454 }
15455
15456 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15457 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
15458 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15459 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
15460 (*printf_func)(" can't perform kext scan: "
15461 "missing kext summary page %p", summary_page);
15462 goto finish;
15463 }
15464 }
15465
15466 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15467 OSKextLoadedKextSummary * summary;
15468
15469 summary = gLoadedKextSummaries->summaries + i;
15470 if (!summary->address) {
15471 continue;
15472 }
15473
15474 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15475 continue;
15476 }
15477
15478 if (!found_kmod) {
15479 if (!(kPrintKextsTerse & flags)) {
15480 (*printf_func)(" Kernel Extensions in backtrace:\n");
15481 }
15482 found_kmod = true;
15483 }
15484
15485 printSummary(summary, printf_func, flags);
15486 }
15487
15488 finish:
15489 if (kPrintKextsLock & flags) {
15490 IOLockUnlock(sKextSummariesLock);
15491 }
15492
15493 return;
15494 }
15495
15496 /*********************************************************************
15497 * This function must be safe to call in panic context.
15498 *********************************************************************/
15499 /* static */
15500 boolean_t
15501 OSKext::summaryIsInBacktrace(
15502 OSKextLoadedKextSummary * summary,
15503 vm_offset_t * addr,
15504 unsigned int cnt)
15505 {
15506 u_int i = 0;
15507
15508 for (i = 0; i < cnt; i++) {
15509 vm_offset_t kscan_addr = addr[i];
15510 #if __has_feature(ptrauth_calls)
15511 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15512 #endif /* __has_feature(ptrauth_calls) */
15513 if ((kscan_addr >= summary->text_exec_address) &&
15514 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15515 return TRUE;
15516 }
15517 }
15518
15519 return FALSE;
15520 }
15521
15522 /*
15523 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15524 * sKextSummariesLock held.
15525 */
15526 OSKextLoadedKextSummary *
15527 OSKext::summaryForAddress(uintptr_t addr)
15528 {
15529 #if __has_feature(ptrauth_calls)
15530 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15531 #endif /* __has_feature(ptrauth_calls) */
15532 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15533 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15534 if (!summary->address) {
15535 continue;
15536 }
15537
15538 #if VM_MAPPED_KEXTS
15539 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15540 * support split kexts, but we also may unmap the kexts, which can
15541 * race with the above codepath (see OSKext::unload). As such,
15542 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15543 */
15544 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15545 return summary;
15546 }
15547 #else
15548 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15549 kernel_segment_command_t *seg;
15550
15551 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
15552 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15553 return summary;
15554 }
15555 }
15556 #endif
15557 }
15558
15559 /* addr did not map to any kext */
15560 return NULL;
15561 }
15562
15563 /* static */
15564 void *
15565 OSKext::kextForAddress(const void *address)
15566 {
15567 OSKextActiveAccount * active;
15568 OSKext * kext = NULL;
15569 uint32_t baseIdx;
15570 uint32_t lim;
15571 uintptr_t addr = (uintptr_t) address;
15572 size_t i;
15573
15574 if (!addr) {
15575 return NULL;
15576 }
15577 #if __has_feature(ptrauth_calls)
15578 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15579 #endif /* __has_feature(ptrauth_calls) */
15580
15581 if (sKextAccountsCount) {
15582 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
15583 // bsearch sKextAccounts list
15584 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15585 active = &sKextAccounts[baseIdx + (lim >> 1)];
15586 if ((addr >= active->address) && (addr < active->address_end)) {
15587 kext = active->account->kext;
15588 if (kext && kext->kmod_info) {
15589 lck_ticket_unlock(sKextAccountsLock);
15590 return (void *)kext->kmod_info->address;
15591 }
15592 break;
15593 } else if (addr > active->address) {
15594 // move right
15595 baseIdx += (lim >> 1) + 1;
15596 lim--;
15597 }
15598 // else move left
15599 }
15600 lck_ticket_unlock(sKextAccountsLock);
15601 }
15602 if (kernel_text_contains(addr)) {
15603 return (void *)&_mh_execute_header;
15604 }
15605 if (gLoadedKextSummaries) {
15606 IOLockLock(sKextSummariesLock);
15607 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15608 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15609 if (addr >= summary->address && addr < summary->address + summary->size) {
15610 void *kextAddress = (void *)summary->address;
15611 IOLockUnlock(sKextSummariesLock);
15612 return kextAddress;
15613 }
15614 }
15615 IOLockUnlock(sKextSummariesLock);
15616 }
15617
15618 return NULL;
15619 }
15620
15621 /*
15622 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15623 * Safe to call in panic context.
15624 */
15625 static OSKextLoadedKextSummary *
15626 findSummary(uint32_t tagID)
15627 {
15628 OSKextLoadedKextSummary * summary;
15629 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15630 summary = gLoadedKextSummaries->summaries + i;
15631 if (summary->loadTag == tagID) {
15632 return summary;
15633 }
15634 }
15635 return NULL;
15636 }
15637
15638 /*********************************************************************
15639 * This function must be safe to call in panic context.
15640 *********************************************************************/
15641 void
15642 OSKext::printSummary(
15643 OSKextLoadedKextSummary * summary,
15644 int (* printf_func)(const char *fmt, ...),
15645 uint32_t flags)
15646 {
15647 kmod_reference_t * kmod_ref = NULL;
15648 uuid_string_t uuid;
15649 char version[kOSKextVersionMaxLength];
15650 uint64_t tmpAddr;
15651 uint64_t tmpSize;
15652 OSKextLoadedKextSummary *dependencySummary;
15653
15654 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
15655 strlcpy(version, "unknown version", sizeof(version));
15656 }
15657 (void) uuid_unparse(summary->uuid, uuid);
15658
15659 #if defined(__arm__) || defined(__arm64__)
15660 tmpAddr = summary->text_exec_address;
15661 tmpSize = summary->text_exec_size;
15662 #else
15663 tmpAddr = summary->address;
15664 tmpSize = summary->size;
15665 #endif
15666 if (kPrintKextsUnslide & flags) {
15667 tmpAddr = ml_static_unslide(tmpAddr);
15668 }
15669 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15670 (kPrintKextsTerse & flags) ? "" : " ",
15671 summary->name, version, uuid,
15672 tmpAddr, tmpAddr + tmpSize - 1);
15673
15674 if (kPrintKextsTerse & flags) {
15675 return;
15676 }
15677
15678 /* print dependency info */
15679 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15680 kmod_ref;
15681 kmod_ref = kmod_ref->next) {
15682 kmod_info_t * rinfo;
15683
15684 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15685 (*printf_func)(" kmod dependency scan stopped "
15686 "due to missing dependency page: %p\n",
15687 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
15688 break;
15689 }
15690 rinfo = kmod_ref->info;
15691
15692 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
15693 (*printf_func)(" kmod dependency scan stopped "
15694 "due to missing kmod page: %p\n",
15695 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
15696 break;
15697 }
15698
15699 if (!rinfo->address) {
15700 continue; // skip fake entries for built-ins
15701 }
15702
15703 dependencySummary = findSummary(rinfo->id);
15704 uuid[0] = 0x00;
15705 tmpAddr = rinfo->address;
15706 tmpSize = rinfo->size;
15707 if (dependencySummary) {
15708 (void) uuid_unparse(dependencySummary->uuid, uuid);
15709 #if defined(__arm__) || defined(__arm64__)
15710 tmpAddr = dependencySummary->text_exec_address;
15711 tmpSize = dependencySummary->text_exec_size;
15712 #endif
15713 }
15714
15715 if (kPrintKextsUnslide & flags) {
15716 tmpAddr = ml_static_unslide(tmpAddr);
15717 }
15718 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15719 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15720 }
15721 return;
15722 }
15723
15724
15725 #if !defined(__arm__) && !defined(__arm64__)
15726 /*******************************************************************************
15727 * substitute() looks at an input string (a pointer within a larger buffer)
15728 * for a match to a substring, and on match it writes the marker & substitution
15729 * character to an output string, updating the scan (from) and
15730 * output (to) indexes as appropriate.
15731 *******************************************************************************/
15732 static int substitute(
15733 const char * scan_string,
15734 char * string_out,
15735 uint32_t * to_index,
15736 uint32_t * from_index,
15737 const char * substring,
15738 char marker,
15739 char substitution);
15740
15741 /* string_out must be at least KMOD_MAX_NAME bytes.
15742 */
15743 static int
15744 substitute(
15745 const char * scan_string,
15746 char * string_out,
15747 uint32_t * to_index,
15748 uint32_t * from_index,
15749 const char * substring,
15750 char marker,
15751 char substitution)
15752 {
15753 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
15754
15755 /* On a substring match, append the marker (if there is one) and then
15756 * the substitution character, updating the output (to) index accordingly.
15757 * Then update the input (from) length by the length of the substring
15758 * that got replaced.
15759 */
15760 if (!strncmp(scan_string, substring, substring_length)) {
15761 if (marker) {
15762 string_out[(*to_index)++] = marker;
15763 }
15764 string_out[(*to_index)++] = substitution;
15765 (*from_index) += substring_length;
15766 return 1;
15767 }
15768 return 0;
15769 }
15770
15771 /*******************************************************************************
15772 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
15773 * KMOD_MAX_NAME characters and performs various substitutions of common
15774 * prefixes & substrings as defined by tables in kext_panic_report.h.
15775 *******************************************************************************/
15776 static void compactIdentifier(
15777 const char * identifier,
15778 char * identifier_out,
15779 char ** identifier_out_end);
15780
15781 static void
15782 compactIdentifier(
15783 const char * identifier,
15784 char * identifier_out,
15785 char ** identifier_out_end)
15786 {
15787 uint32_t from_index, to_index;
15788 uint32_t scan_from_index = 0;
15789 uint32_t scan_to_index = 0;
15790 subs_entry_t * subs_entry = NULL;
15791 int did_sub = 0;
15792
15793 from_index = to_index = 0;
15794 identifier_out[0] = '\0';
15795
15796 /* Replace certain identifier prefixes with shorter @+character sequences.
15797 * Check the return value of substitute() so we only replace the prefix.
15798 */
15799 for (subs_entry = &kext_identifier_prefix_subs[0];
15800 subs_entry->substring && !did_sub;
15801 subs_entry++) {
15802 did_sub = substitute(identifier, identifier_out,
15803 &scan_to_index, &scan_from_index,
15804 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
15805 }
15806 did_sub = 0;
15807
15808 /* Now scan through the identifier looking for the common substrings
15809 * and replacing them with shorter !+character sequences via substitute().
15810 */
15811 for (/* see above */;
15812 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
15813 /* see loop */) {
15814 const char * scan_string = &identifier[scan_from_index];
15815
15816 did_sub = 0;
15817
15818 if (scan_from_index) {
15819 for (subs_entry = &kext_identifier_substring_subs[0];
15820 subs_entry->substring && !did_sub;
15821 subs_entry++) {
15822 did_sub = substitute(scan_string, identifier_out,
15823 &scan_to_index, &scan_from_index,
15824 subs_entry->substring, '!', subs_entry->substitute);
15825 }
15826 }
15827
15828 /* If we didn't substitute, copy the input character to the output.
15829 */
15830 if (!did_sub) {
15831 identifier_out[scan_to_index++] = identifier[scan_from_index++];
15832 }
15833 }
15834
15835 identifier_out[scan_to_index] = '\0';
15836 if (identifier_out_end) {
15837 *identifier_out_end = &identifier_out[scan_to_index];
15838 }
15839
15840 return;
15841 }
15842 #endif /* !defined(__arm__) && !defined(__arm64__) */
15843
15844 /*******************************************************************************
15845 * assemble_identifier_and_version() adds to a string buffer a compacted
15846 * bundle identifier followed by a version string.
15847 *******************************************************************************/
15848
15849 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
15850 */
15851 static size_t assemble_identifier_and_version(
15852 kmod_info_t * kmod_info,
15853 char * identPlusVers,
15854 size_t bufSize);
15855
15856 static size_t
15857 assemble_identifier_and_version(
15858 kmod_info_t * kmod_info,
15859 char * identPlusVers,
15860 size_t bufSize)
15861 {
15862 size_t result = 0;
15863
15864 #if defined(__arm__) || defined(__arm64__)
15865 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
15866 #else
15867 compactIdentifier(kmod_info->name, identPlusVers, NULL);
15868 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
15869 #endif
15870 identPlusVers[result++] = '\t'; // increment for real char
15871 identPlusVers[result] = '\0'; // don't increment for nul char
15872 result = strlcat(identPlusVers, kmod_info->version, bufSize);
15873 if (result >= bufSize) {
15874 identPlusVers[bufSize - 1] = '\0';
15875 result = bufSize - 1;
15876 }
15877
15878 return result;
15879 }
15880
15881 /*******************************************************************************
15882 * Assumes sKextLock is held.
15883 *******************************************************************************/
15884 /* static */
15885 int
15886 OSKext::saveLoadedKextPanicListTyped(
15887 const char * prefix,
15888 int invertFlag,
15889 int libsFlag,
15890 char * paniclist,
15891 uint32_t list_size)
15892 {
15893 int result = -1;
15894 unsigned int count, i;
15895
15896 count = sLoadedKexts->getCount();
15897 if (!count) {
15898 goto finish;
15899 }
15900
15901 i = count - 1;
15902 do {
15903 OSObject * rawKext = sLoadedKexts->getObject(i);
15904 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
15905 int match;
15906 size_t identPlusVersLength;
15907 size_t tempLen;
15908 char identPlusVers[2 * KMOD_MAX_NAME];
15909
15910 if (!rawKext) {
15911 printf("OSKext::saveLoadedKextPanicListTyped - "
15912 "NULL kext in loaded kext list; continuing\n");
15913 continue;
15914 }
15915
15916 if (!theKext) {
15917 printf("OSKext::saveLoadedKextPanicListTyped - "
15918 "Kext type cast failed in loaded kext list; continuing\n");
15919 continue;
15920 }
15921
15922 /* Skip all built-in kexts.
15923 */
15924 if (theKext->isKernelComponent()) {
15925 continue;
15926 }
15927
15928 kmod_info_t * kmod_info = theKext->kmod_info;
15929
15930 /* Filter for kmod name (bundle identifier).
15931 */
15932 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
15933 if ((match && invertFlag) || (!match && !invertFlag)) {
15934 continue;
15935 }
15936
15937 /* Filter for libraries (kexts that have a compatible version).
15938 */
15939 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
15940 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
15941 continue;
15942 }
15943
15944 if (!kmod_info ||
15945 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
15946 printf("kext scan stopped due to missing kmod_info page: %p\n",
15947 kmod_info);
15948 goto finish;
15949 }
15950
15951 identPlusVersLength = assemble_identifier_and_version(kmod_info,
15952 identPlusVers,
15953 sizeof(identPlusVers));
15954 if (!identPlusVersLength) {
15955 printf("error saving loaded kext info\n");
15956 goto finish;
15957 }
15958
15959 /* make sure everything fits and we null terminate.
15960 */
15961 tempLen = strlcat(paniclist, identPlusVers, list_size);
15962 if (tempLen >= list_size) {
15963 // panic list is full, keep it and null terminate
15964 paniclist[list_size - 1] = 0x00;
15965 result = 0;
15966 goto finish;
15967 }
15968 tempLen = strlcat(paniclist, "\n", list_size);
15969 if (tempLen >= list_size) {
15970 // panic list is full, keep it and null terminate
15971 paniclist[list_size - 1] = 0x00;
15972 result = 0;
15973 goto finish;
15974 }
15975 } while (i--);
15976
15977 result = 0;
15978 finish:
15979
15980 return result;
15981 }
15982
15983 /*********************************************************************
15984 *********************************************************************/
15985 /* static */
15986 void
15987 OSKext::saveLoadedKextPanicList(void)
15988 {
15989 char * newlist = NULL;
15990 uint32_t newlist_size = 0;
15991
15992 newlist_size = KEXT_PANICLIST_SIZE;
15993 newlist = (char *)kalloc_data_tag(newlist_size,
15994 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15995
15996 if (!newlist) {
15997 OSKextLog(/* kext */ NULL,
15998 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
15999 "Couldn't allocate kext panic log buffer.");
16000 goto finish;
16001 }
16002
16003 newlist[0] = '\0';
16004
16005 // non-"com.apple." kexts
16006 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
16007 /* libs? */ -1, newlist, newlist_size) != 0) {
16008 goto finish;
16009 }
16010 // "com.apple." nonlibrary kexts
16011 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16012 /* libs? */ 0, newlist, newlist_size) != 0) {
16013 goto finish;
16014 }
16015 // "com.apple." library kexts
16016 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16017 /* libs? */ 1, newlist, newlist_size) != 0) {
16018 goto finish;
16019 }
16020
16021 if (loaded_kext_paniclist) {
16022 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
16023 }
16024 loaded_kext_paniclist = newlist;
16025 newlist = NULL;
16026 loaded_kext_paniclist_size = newlist_size;
16027
16028 finish:
16029 if (newlist) {
16030 kfree_data(newlist, newlist_size);
16031 }
16032 return;
16033 }
16034
16035 /*********************************************************************
16036 * Assumes sKextLock is held.
16037 *********************************************************************/
16038 void
16039 OSKext::savePanicString(bool isLoading)
16040 {
16041 u_long len;
16042
16043 if (!kmod_info) {
16044 return; // do not goto finish here b/c of lock
16045 }
16046
16047 len = assemble_identifier_and_version( kmod_info,
16048 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
16049 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
16050 if (!len) {
16051 printf("error saving unloaded kext info\n");
16052 goto finish;
16053 }
16054
16055 if (isLoading) {
16056 last_loaded_strlen = len;
16057 last_loaded_address = (void *)kmod_info->address;
16058 last_loaded_size = kmod_info->size;
16059 clock_get_uptime(&last_loaded_timestamp);
16060 } else {
16061 last_unloaded_strlen = len;
16062 last_unloaded_address = (void *)kmod_info->address;
16063 last_unloaded_size = kmod_info->size;
16064 clock_get_uptime(&last_unloaded_timestamp);
16065 }
16066
16067 finish:
16068 return;
16069 }
16070
16071 /*********************************************************************
16072 *********************************************************************/
16073 /* static */
16074 void
16075 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
16076 {
16077 if (last_loaded_strlen) {
16078 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
16079 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16080 last_loaded_strlen, last_loaded_str_buf,
16081 last_loaded_address, last_loaded_size);
16082 }
16083
16084 if (last_unloaded_strlen) {
16085 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16086 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16087 last_unloaded_strlen, last_unloaded_str_buf,
16088 last_unloaded_address, last_unloaded_size);
16089 }
16090
16091 printf_func("loaded kexts:\n");
16092 if (loaded_kext_paniclist &&
16093 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16094 loaded_kext_paniclist[0]) {
16095 printf_func("%.*s",
16096 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
16097 loaded_kext_paniclist);
16098 } else {
16099 printf_func("(none)\n");
16100 }
16101 return;
16102 }
16103
16104 /*********************************************************************
16105 * Assumes sKextLock is held.
16106 *********************************************************************/
16107 /* static */
16108 void
16109 OSKext::updateLoadedKextSummaries(void)
16110 {
16111 kern_return_t result = KERN_FAILURE;
16112 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16113 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16114 OSKext *aKext;
16115 vm_map_offset_t start, end;
16116 size_t summarySize = 0;
16117 size_t size;
16118 u_int count;
16119 u_int maxKexts;
16120 u_int i, j;
16121 OSKextActiveAccount * accountingList;
16122 OSKextActiveAccount * prevAccountingList;
16123 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16124
16125 prevAccountingList = NULL;
16126 prevAccountingListCount = 0;
16127
16128 #if DEVELOPMENT || DEBUG
16129 if (IORecursiveLockHaveLock(sKextLock) == false) {
16130 panic("sKextLock must be held");
16131 }
16132 #endif
16133
16134 IOLockLock(sKextSummariesLock);
16135
16136 count = sLoadedKexts->getCount();
16137 for (i = 0, maxKexts = 0; i < count; ++i) {
16138 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16139 maxKexts += (aKext && aKext->isExecutable());
16140 }
16141
16142 if (!maxKexts) {
16143 goto finish;
16144 }
16145 if (maxKexts < kOSKextTypicalLoadCount) {
16146 maxKexts = kOSKextTypicalLoadCount;
16147 }
16148
16149 /* Calculate the size needed for the new summary headers.
16150 */
16151
16152 size = sizeof(*gLoadedKextSummaries);
16153 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16154 size = round_page(size);
16155
16156 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16157 if (gLoadedKextSummaries) {
16158 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
16159 gLoadedKextSummaries = NULL;
16160 gLoadedKextSummariesTimestamp = mach_absolute_time();
16161 sLoadedKextSummariesAllocSize = 0;
16162 }
16163 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
16164 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
16165 if (result != KERN_SUCCESS) {
16166 goto finish;
16167 }
16168 summaryHeader = summaryHeaderAlloc;
16169 summarySize = size;
16170 } else {
16171 summaryHeader = gLoadedKextSummaries;
16172 summarySize = sLoadedKextSummariesAllocSize;
16173
16174 start = (vm_map_offset_t) summaryHeader;
16175 end = start + summarySize;
16176 result = vm_map_protect(kernel_map,
16177 start,
16178 end,
16179 VM_PROT_DEFAULT,
16180 FALSE);
16181 if (result != KERN_SUCCESS) {
16182 goto finish;
16183 }
16184 }
16185
16186 /* Populate the summary header.
16187 */
16188
16189 bzero(summaryHeader, summarySize);
16190 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16191 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16192
16193 /* Populate each kext summary.
16194 */
16195
16196 count = sLoadedKexts->getCount();
16197 accountingListAlloc = 0;
16198 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16199 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16200 if (!aKext || !aKext->isExecutable()) {
16201 continue;
16202 }
16203
16204 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
16205 summaryHeader->numSummaries++;
16206 accountingListAlloc++;
16207 }
16208
16209 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16210 accountingListCount = 0;
16211 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16212 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16213 if (!aKext || !aKext->isExecutable()) {
16214 continue;
16215 }
16216
16217 OSKextActiveAccount activeAccount;
16218 aKext->updateActiveAccount(&activeAccount);
16219 // order by address
16220 for (idx = 0; idx < accountingListCount; idx++) {
16221 if (activeAccount.address < accountingList[idx].address) {
16222 break;
16223 }
16224 }
16225 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
16226 accountingList[idx] = activeAccount;
16227 accountingListCount++;
16228 }
16229 assert(accountingListCount == accountingListAlloc);
16230 /* Write protect the buffer and move it into place.
16231 */
16232
16233 start = (vm_map_offset_t) summaryHeader;
16234 end = start + summarySize;
16235
16236 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
16237 if (result != KERN_SUCCESS) {
16238 goto finish;
16239 }
16240
16241 gLoadedKextSummaries = summaryHeader;
16242 gLoadedKextSummariesTimestamp = mach_absolute_time();
16243 sLoadedKextSummariesAllocSize = summarySize;
16244 summaryHeaderAlloc = NULL;
16245
16246 /* Call the magic breakpoint function through a static function pointer so
16247 * the compiler can't optimize the function away.
16248 */
16249 if (sLoadedKextSummariesUpdated) {
16250 (*sLoadedKextSummariesUpdated)();
16251 }
16252
16253 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16254 prevAccountingList = sKextAccounts;
16255 prevAccountingListCount = sKextAccountsCount;
16256 sKextAccounts = accountingList;
16257 sKextAccountsCount = accountingListCount;
16258 lck_ticket_unlock(sKextAccountsLock);
16259
16260 finish:
16261 IOLockUnlock(sKextSummariesLock);
16262
16263 /* If we had to allocate a new buffer but failed to generate the summaries,
16264 * free that now.
16265 */
16266 if (summaryHeaderAlloc) {
16267 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
16268 }
16269 if (prevAccountingList) {
16270 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16271 }
16272
16273 return;
16274 }
16275
16276 /*********************************************************************
16277 *********************************************************************/
16278 void
16279 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16280 {
16281 OSSharedPtr<OSData> uuid;
16282
16283 strlcpy(summary->name, getIdentifierCString(),
16284 sizeof(summary->name));
16285
16286 uuid = copyUUID();
16287 if (uuid) {
16288 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
16289 }
16290
16291 if (flags.builtin) {
16292 // this value will stop lldb from parsing the mach-o header
16293 // summary->address = UINT64_MAX;
16294 // summary->size = 0;
16295 summary->address = kmod_info->address;
16296 summary->size = kmod_info->size;
16297 } else {
16298 summary->address = kmod_info->address;
16299 summary->size = kmod_info->size;
16300 }
16301 summary->version = getVersion();
16302 summary->loadTag = kmod_info->id;
16303 summary->flags = 0;
16304 summary->reference_list = (uint64_t) kmod_info->reference_list;
16305
16306 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16307 if (summary->text_exec_address == 0) {
16308 // Fallback to __TEXT
16309 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16310 }
16311 return;
16312 }
16313
16314 /*********************************************************************
16315 *********************************************************************/
16316
16317 void
16318 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16319 {
16320 kernel_mach_header_t *hdr = NULL;
16321 kernel_segment_command_t *seg = NULL;
16322
16323 bzero(accountp, sizeof(*accountp));
16324
16325 hdr = (kernel_mach_header_t *)kmod_info->address;
16326 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16327 /*
16328 * If this kext supports split segments (or is in a new
16329 * MH_FILESET kext collection), use the first
16330 * executable segment as the range for instructions
16331 * (and thus for backtracing.
16332 */
16333 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
16334 if (seg->initprot & VM_PROT_EXECUTE) {
16335 break;
16336 }
16337 }
16338 }
16339 if (seg) {
16340 accountp->address = seg->vmaddr;
16341 if (accountp->address) {
16342 accountp->address_end = seg->vmaddr + seg->vmsize;
16343 }
16344 } else {
16345 /* For non-split kexts and for kexts without executable
16346 * segments, just use the kmod_info range (as the kext
16347 * is either all in one range or should not show up in
16348 * instruction backtraces).
16349 */
16350 accountp->address = kmod_info->address;
16351 if (accountp->address) {
16352 accountp->address_end = kmod_info->address + kmod_info->size;
16353 }
16354 }
16355
16356 accountp->account = this->account;
16357 }
16358
16359 bool
16360 OSKext::isDriverKit(void)
16361 {
16362 OSString *bundleType;
16363
16364 if (infoDict) {
16365 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16366 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16367 return TRUE;
16368 }
16369 }
16370 return FALSE;
16371 }
16372
16373 bool
16374 OSKext::isInFileset(void)
16375 {
16376 if (!kmod_info) {
16377 goto check_prelinked;
16378 }
16379
16380 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16381 return true;
16382 }
16383
16384 check_prelinked:
16385 if (isPrelinked()) {
16386 /*
16387 * If we haven't setup kmod_info yet, but we know
16388 * we're loading a prelinked kext in an MH_FILESET KC,
16389 * then return true
16390 */
16391 kc_format_t kc_format;
16392 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
16393 return true;
16394 }
16395 }
16396 return false;
16397 }
16398
16399 OSSharedPtr<OSDextStatistics>
16400 OSKext::copyDextStatistics(void)
16401 {
16402 return dextStatistics;
16403 }
16404
16405 bool
16406 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16407 {
16408 kern_return_t result;
16409 if (!super::init()) {
16410 return false;
16411 }
16412 if (seg == nullptr) {
16413 return false;
16414 }
16415 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
16416 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16417 if (result != KERN_SUCCESS) {
16418 return false;
16419 }
16420 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
16421 savedSegment = seg;
16422 vmsize = seg->vmsize;
16423 vmaddr = seg->vmaddr;
16424 return true;
16425 }
16426
16427 OSSharedPtr<OSKextSavedMutableSegment>
16428 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16429 {
16430 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16431 if (me && !me->initWithSegment(seg)) {
16432 return nullptr;
16433 }
16434 return me;
16435 }
16436
16437 void
16438 OSKextSavedMutableSegment::free(void)
16439 {
16440 if (data) {
16441 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
16442 }
16443 }
16444
16445 vm_offset_t
16446 OSKextSavedMutableSegment::getVMAddr() const
16447 {
16448 return vmaddr;
16449 }
16450
16451 vm_offset_t
16452 OSKextSavedMutableSegment::getVMSize() const
16453 {
16454 return vmsize;
16455 }
16456
16457 OSReturn
16458 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16459 {
16460 if (seg != savedSegment) {
16461 return kOSKextReturnInvalidArgument;
16462 }
16463 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16464 return kOSKextReturnInvalidArgument;
16465 }
16466 memcpy((void *)seg->vmaddr, data, vmsize);
16467 return kOSReturnSuccess;
16468 }
16469
16470 extern "C" kern_return_t
16471 OSKextSetReceiptQueried(void)
16472 {
16473 OSKextLog(/* kext */ NULL,
16474 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16475 "Setting kext receipt as queried");
16476
16477 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
16478 return KERN_SUCCESS;
16479 }
16480
16481 extern "C" const vm_allocation_site_t *
16482 OSKextGetAllocationSiteForCaller(uintptr_t address)
16483 {
16484 OSKextActiveAccount * active;
16485 vm_allocation_site_t * site;
16486 vm_allocation_site_t * releasesite;
16487
16488 uint32_t baseIdx;
16489 uint32_t lim;
16490 #if __has_feature(ptrauth_calls)
16491 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16492 #endif /* __has_feature(ptrauth_calls) */
16493
16494 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16495 site = releasesite = NULL;
16496
16497 // bsearch sKextAccounts list
16498 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16499 active = &sKextAccounts[baseIdx + (lim >> 1)];
16500 if ((address >= active->address) && (address < active->address_end)) {
16501 site = &active->account->site;
16502 if (!site->tag) {
16503 vm_tag_alloc_locked(site, &releasesite);
16504 }
16505 break;
16506 } else if (address > active->address) {
16507 // move right
16508 baseIdx += (lim >> 1) + 1;
16509 lim--;
16510 }
16511 // else move left
16512 }
16513 lck_ticket_unlock(sKextAccountsLock);
16514 if (releasesite) {
16515 kern_allocation_name_release(releasesite);
16516 }
16517
16518 return site;
16519 }
16520
16521 #if DEVELOPMENT || DEBUG
16522 extern "C" void
16523 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16524 {
16525 OSKextActiveAccount * active;
16526
16527 uint32_t baseIdx;
16528 uint32_t lim;
16529 #if __has_feature(ptrauth_calls)
16530 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16531 #endif /* __has_feature(ptrauth_calls) */
16532
16533 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16534
16535 // bsearch sKextAccounts list
16536 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16537 active = &sKextAccounts[baseIdx + (lim >> 1)];
16538 if ((address >= active->address) && (address < active->address_end)) {
16539 cb(&active->account->task_refgrp);
16540 break;
16541 } else if (address > active->address) {
16542 // move right
16543 baseIdx += (lim >> 1) + 1;
16544 lim--;
16545 }
16546 // else move left
16547 }
16548 lck_ticket_unlock(sKextAccountsLock);
16549 }
16550 #endif /* DEVELOPMENT || DEBUG */
16551
16552 extern "C" uint32_t
16553 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16554 {
16555 OSKextAccount * account = (typeof(account))site;
16556 const char * kname;
16557
16558 if (name) {
16559 if (account->kext) {
16560 kname = account->kext->getIdentifierCString();
16561 } else {
16562 kname = "<>";
16563 }
16564 strlcpy(name, kname, namelen);
16565 }
16566
16567 return account->loadTag;
16568 }
16569
16570 extern "C" void
16571 OSKextFreeSite(vm_allocation_site_t * site)
16572 {
16573 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16574 IOFreeType(freeAccount, OSKextAccount);
16575 }
16576
16577 /*********************************************************************
16578 *********************************************************************/
16579
16580 #if CONFIG_IMAGEBOOT
16581 int
16582 OSKextGetUUIDForName(const char *name, uuid_t uuid)
16583 {
16584 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
16585 if (!kext) {
16586 return 1;
16587 }
16588
16589 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16590 if (uuid_data) {
16591 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
16592 return 0;
16593 }
16594
16595 return 1;
16596 }
16597 #endif
16598
16599
16600
16601 class OSDextCrash : public OSObject {
16602 OSDeclareDefaultStructors(OSDextCrash);
16603 public:
16604 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16605 uint64_t getTimestamp();
16606
16607 private:
16608 virtual bool initWithTimestamp(uint64_t timestamp);
16609 uint64_t fTimestamp;
16610 };
16611
16612 OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16613
16614 OSSharedPtr<OSDextCrash>
16615 OSDextCrash::withTimestamp(uint64_t timestamp)
16616 {
16617 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16618 if (!result->initWithTimestamp(timestamp)) {
16619 return NULL;
16620 }
16621 return result;
16622 }
16623
16624 bool
16625 OSDextCrash::initWithTimestamp(uint64_t timestamp)
16626 {
16627 if (!OSObject::init()) {
16628 return false;
16629 }
16630 fTimestamp = timestamp;
16631 return true;
16632 }
16633
16634 uint64_t
16635 OSDextCrash::getTimestamp()
16636 {
16637 return fTimestamp;
16638 }
16639
16640 OSSharedPtr<OSDextStatistics>
16641 OSDextStatistics::create()
16642 {
16643 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16644 if (!result->init()) {
16645 return NULL;
16646 }
16647 return result;
16648 }
16649
16650 bool
16651 OSDextStatistics::init()
16652 {
16653 if (!OSObject::init()) {
16654 return false;
16655 }
16656
16657 lock = IOLockAlloc();
16658 crashes = OSArray::withCapacity(kMaxDextCrashesInOneDay);
16659 return true;
16660 }
16661
16662 void
16663 OSDextStatistics::free()
16664 {
16665 if (lock) {
16666 IOLockFree(lock);
16667 }
16668 crashes.reset();
16669 OSObject::free();
16670 }
16671
16672 OSDextCrashPolicy
16673 OSDextStatistics::recordCrash()
16674 {
16675 size_t i = 0;
16676 uint64_t timestamp = mach_continuous_time();
16677 uint64_t interval;
16678 nanoseconds_to_absolutetime(86400 * NSEC_PER_SEC /* 1 day */, &interval);
16679 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16680 OSDextCrashPolicy policy;
16681
16682 IOLockLock(lock);
16683 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16684 for (i = 0; i < crashes->getCount();) {
16685 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16686 assert(current != NULL);
16687 if (current->getTimestamp() < lastTimestamp) {
16688 crashes->removeObject(i);
16689 } else {
16690 i++;
16691 }
16692 }
16693
16694 crashes->setObject(crash);
16695
16696 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16697 policy = kOSDextCrashPolicyReboot;
16698 } else {
16699 policy = kOSDextCrashPolicyNone;
16700 }
16701
16702 IOLockUnlock(lock);
16703
16704 return policy;
16705 }
16706
16707 size_t
16708 OSDextStatistics::getCrashCount()
16709 {
16710 size_t result = 0;
16711 IOLockLock(lock);
16712 result = crashes->getCount();
16713 IOLockUnlock(lock);
16714 return result;
16715 }
16716
16717 static int
16718 sysctl_willuserspacereboot
16719 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
16720 {
16721 int new_value = 0, old_value = 0, changed = 0;
16722 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
16723 if (error) {
16724 return error;
16725 }
16726 if (changed) {
16727 OSKext::willUserspaceReboot();
16728 }
16729 return 0;
16730 }
16731
16732 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
16733 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
16734 NULL, 0, sysctl_willuserspacereboot, "I", "");
16735