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
4230 /**
4231 * If the addresses within the Mach-O are unslid, then manually
4232 * slide any addresses coming from the Mach-O before usage.
4233 */
4234 if (thisKext->flags.unslidMachO) {
4235 textExecBase = (uintptr_t) ml_static_slide((vm_offset_t) textExecBase);
4236 }
4237
4238 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4239 foundKext.reset(thisKext, OSRetain);
4240 goto finish;
4241 }
4242 #endif /* defined (__arm64__) */
4243 }
4244 }
4245 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4246 foundKext.reset(sKernelKext, OSRetain);
4247 goto finish;
4248 }
4249 /*
4250 * DriverKit userspace executables do not have a kernel linkedExecutable,
4251 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4252 * here, so use the original address passed to this method.
4253 *
4254 * This is supposed to be used for logging reasons only. When logd
4255 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4256 * remove it here before checking it against the LoadTag.
4257 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4258 */
4259
4260 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4261 count = sLoadedDriverKitKexts->getCount();
4262 for (i = 0; i < count; i++) {
4263 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4264 if (thisKext->getLoadTag() == address) {
4265 foundKext.reset(thisKext, OSRetain);
4266 }
4267 }
4268
4269 finish:
4270 IORecursiveLockUnlock(sKextLock);
4271
4272 return foundKext;
4273 }
4274
4275 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)4276 OSKext::copyKextUUIDForAddress(OSNumber *address)
4277 {
4278 OSSharedPtr<OSData> uuid;
4279 OSSharedPtr<OSKext> kext;
4280
4281 if (!address) {
4282 return NULL;
4283 }
4284
4285 #if CONFIG_MACF
4286 /* Is the calling process allowed to query kext info? */
4287 if (current_task() != kernel_task) {
4288 int macCheckResult = 0;
4289 kauth_cred_t cred = NULL;
4290
4291 cred = kauth_cred_get_with_ref();
4292 macCheckResult = mac_kext_check_query(cred);
4293 kauth_cred_unref(&cred);
4294
4295 if (macCheckResult != 0) {
4296 OSKextLog(/* kext */ NULL,
4297 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4298 "Failed to query kext UUID (MAC policy error 0x%x).",
4299 macCheckResult);
4300 return NULL;
4301 }
4302 }
4303 #endif
4304
4305 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4306 if (slidAddress != 0) {
4307 kext = lookupKextWithAddress(slidAddress);
4308 if (kext) {
4309 uuid = kext->copyTextUUID();
4310 }
4311 }
4312
4313 if (!uuid) {
4314 /*
4315 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4316 * a kext. This might have happened because the log message came from a dext.
4317 *
4318 * Try again with the original address.
4319 */
4320 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4321 if (kext && kext->isDriverKit()) {
4322 uuid = kext->copyTextUUID();
4323 }
4324 }
4325
4326 return uuid;
4327 }
4328
4329 /*********************************************************************
4330 *********************************************************************/
4331 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4332 OSKext::lookupKextWithUUID(uuid_t wanted)
4333 {
4334 OSSharedPtr<OSKext> foundKext; // returned
4335 uint32_t j, i;
4336 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4337 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4338
4339
4340 IORecursiveLockLock(sKextLock);
4341
4342 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4343 for (i = 0; i < count[j]; i++) {
4344 OSKext * thisKext = NULL;
4345
4346 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4347 if (!thisKext) {
4348 continue;
4349 }
4350
4351 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4352 if (!uuid_data) {
4353 continue;
4354 }
4355
4356 uuid_t uuid;
4357 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4358
4359 if (0 == uuid_compare(wanted, uuid)) {
4360 foundKext.reset(thisKext, OSRetain);
4361 goto finish;
4362 }
4363 }
4364 }
4365 finish:
4366 IORecursiveLockUnlock(sKextLock);
4367
4368 return foundKext;
4369 }
4370
4371
4372
4373
4374 /*********************************************************************
4375 *********************************************************************/
4376 /* static */
4377 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4378 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4379 {
4380 bool result = false;
4381 OSKext * foundKext = NULL; // returned
4382
4383 IORecursiveLockLock(sKextLock);
4384
4385 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4386 if (foundKext && foundKext->isLoaded()) {
4387 result = true;
4388 }
4389
4390 IORecursiveLockUnlock(sKextLock);
4391
4392 return result;
4393 }
4394
4395 /*********************************************************************
4396 * xxx - should spawn a separate thread so a kext can safely have
4397 * xxx - itself unloaded.
4398 *********************************************************************/
4399 /* static */
4400 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4401 OSKext::removeKext(
4402 OSKext * aKext,
4403 #if CONFIG_EMBEDDED
4404 __unused
4405 #endif
4406 bool terminateServicesAndRemovePersonalitiesFlag)
4407 {
4408 #if CONFIG_EMBEDDED
4409 if (!aKext->isDriverKit()) {
4410 OSKextLog(aKext,
4411 kOSKextLogErrorLevel |
4412 kOSKextLogKextBookkeepingFlag,
4413 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4414 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4415
4416 return kOSReturnSuccess;
4417 }
4418 #endif /* CONFIG_EMBEDDED */
4419 OSReturn result = kOSKextReturnInUse;
4420 OSKext * checkKext = NULL; // do not release
4421 #if CONFIG_MACF
4422 int macCheckResult = 0;
4423 kauth_cred_t cred = NULL;
4424 #endif
4425
4426 IORecursiveLockLock(sKextLock);
4427
4428 /* If the kext has no identifier, it failed to init
4429 * so isn't in sKextsByID and it isn't loaded.
4430 */
4431 if (!aKext->getIdentifier()) {
4432 result = kOSReturnSuccess;
4433 goto finish;
4434 }
4435
4436 checkKext = OSDynamicCast(OSKext,
4437 sKextsByID->getObject(aKext->getIdentifier()));
4438 if (checkKext != aKext) {
4439 result = kOSKextReturnNotFound;
4440 goto finish;
4441 }
4442
4443 if (aKext->isLoaded() || aKext->isDriverKit()) {
4444 #if CONFIG_MACF
4445 if (current_task() != kernel_task) {
4446 cred = kauth_cred_get_with_ref();
4447 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4448 kauth_cred_unref(&cred);
4449 }
4450
4451 if (macCheckResult != 0) {
4452 result = kOSReturnError;
4453 OSKextLog(aKext,
4454 kOSKextLogErrorLevel |
4455 kOSKextLogKextBookkeepingFlag,
4456 "Failed to remove kext %s (MAC policy error 0x%x).",
4457 aKext->getIdentifierCString(), macCheckResult);
4458 goto finish;
4459 }
4460 #endif
4461
4462 /* make sure there are no resource requests in flight - 17187548 */
4463 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4464 goto finish;
4465 }
4466 if (aKext->flags.unloadUnsupported) {
4467 result = kOSKextReturnInUse;
4468 OSKextLog(aKext,
4469 kOSKextLogErrorLevel |
4470 kOSKextLogKextBookkeepingFlag,
4471 "Can't remove kext %s; unsupported by cache.",
4472 aKext->getIdentifierCString());
4473 goto finish;
4474 }
4475
4476 /* If we are terminating, send the request to the IOCatalogue
4477 * (which will actually call us right back but that's ok we have
4478 * a recursive lock don't you know) but do not ask the IOCatalogue
4479 * to call back with an unload, we'll do that right here.
4480 */
4481 if (terminateServicesAndRemovePersonalitiesFlag) {
4482 result = gIOCatalogue->terminateDriversForModule(
4483 aKext->getIdentifierCString(), /* unload */ false);
4484 if (result != kOSReturnSuccess) {
4485 OSKextLog(aKext,
4486 kOSKextLogErrorLevel |
4487 kOSKextLogKextBookkeepingFlag,
4488 "Can't remove kext %s; services failed to terminate - 0x%x.",
4489 aKext->getIdentifierCString(), result);
4490 goto finish;
4491 }
4492 }
4493
4494 result = aKext->unload();
4495 if (result != kOSReturnSuccess) {
4496 OSKextLog(aKext,
4497 kOSKextLogErrorLevel |
4498 kOSKextLogKextBookkeepingFlag,
4499 "Can't remove kext %s; kext failed to unload - 0x%x.",
4500 aKext->getIdentifierCString(), result);
4501 goto finish;
4502 }
4503 }
4504
4505 /* Remove personalities as requested. This is a bit redundant for a loaded
4506 * kext as IOCatalogue::terminateDriversForModule() removes driver
4507 * personalities, but it doesn't restart matching, which we always want
4508 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4509 * that happens.
4510 */
4511 if (terminateServicesAndRemovePersonalitiesFlag) {
4512 aKext->removePersonalitiesFromCatalog();
4513 }
4514
4515 if (aKext->isInFileset()) {
4516 OSKextLog(aKext,
4517 kOSKextLogProgressLevel |
4518 kOSKextLogKextBookkeepingFlag,
4519 "Fileset kext %s unloaded.",
4520 aKext->getIdentifierCString());
4521 } else {
4522 OSKextLog(aKext,
4523 kOSKextLogProgressLevel |
4524 kOSKextLogKextBookkeepingFlag,
4525 "Removing kext %s.",
4526 aKext->getIdentifierCString());
4527
4528 sKextsByID->removeObject(aKext->getIdentifier());
4529 }
4530 result = kOSReturnSuccess;
4531
4532 finish:
4533 IORecursiveLockUnlock(sKextLock);
4534 return result;
4535 }
4536
4537 /*********************************************************************
4538 *********************************************************************/
4539 /* static */
4540 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4541 OSKext::removeKextWithIdentifier(
4542 const char * kextIdentifier,
4543 bool terminateServicesAndRemovePersonalitiesFlag)
4544 {
4545 OSReturn result = kOSReturnError;
4546
4547 IORecursiveLockLock(sKextLock);
4548
4549 OSKext * aKext = OSDynamicCast(OSKext,
4550 sKextsByID->getObject(kextIdentifier));
4551 if (!aKext) {
4552 result = kOSKextReturnNotFound;
4553 OSKextLog(/* kext */ NULL,
4554 kOSKextLogErrorLevel |
4555 kOSKextLogKextBookkeepingFlag,
4556 "Can't remove kext %s - not found.",
4557 kextIdentifier);
4558 goto finish;
4559 }
4560
4561 result = OSKext::removeKext(aKext,
4562 terminateServicesAndRemovePersonalitiesFlag);
4563
4564 finish:
4565 IORecursiveLockUnlock(sKextLock);
4566
4567 return result;
4568 }
4569
4570 /*********************************************************************
4571 *********************************************************************/
4572 /* static */
4573 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4574 OSKext::removeKextWithLoadTag(
4575 OSKextLoadTag loadTag,
4576 bool terminateServicesAndRemovePersonalitiesFlag)
4577 {
4578 OSReturn result = kOSReturnError;
4579 OSKext * foundKext = NULL;
4580 uint32_t i, j;
4581 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4582 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4583
4584
4585 IORecursiveLockLock(sKextLock);
4586
4587 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4588 for (i = 0; i < count[j]; i++) {
4589 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4590 if (thisKext->loadTag == loadTag) {
4591 foundKext = thisKext;
4592 break;
4593 }
4594 }
4595 }
4596
4597 if (!foundKext) {
4598 result = kOSKextReturnNotFound;
4599 OSKextLog(/* kext */ NULL,
4600 kOSKextLogErrorLevel |
4601 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4602 "Can't remove kext with load tag %d - not found.",
4603 loadTag);
4604 goto finish;
4605 }
4606
4607 result = OSKext::removeKext(foundKext,
4608 terminateServicesAndRemovePersonalitiesFlag);
4609
4610 finish:
4611 IORecursiveLockUnlock(sKextLock);
4612
4613 return result;
4614 }
4615
4616 /*********************************************************************
4617 *********************************************************************/
4618 OSSharedPtr<OSDictionary>
copyKexts(void)4619 OSKext::copyKexts(void)
4620 {
4621 OSSharedPtr<OSDictionary> result;
4622
4623 IORecursiveLockLock(sKextLock);
4624 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4625 IORecursiveLockUnlock(sKextLock);
4626
4627 return result;
4628 }
4629
4630 /*********************************************************************
4631 *********************************************************************/
4632 #define BOOTER_KEXT_PREFIX "Driver-"
4633
4634 typedef struct _DeviceTreeBuffer {
4635 uint32_t paddr;
4636 uint32_t length;
4637 } _DeviceTreeBuffer;
4638
4639 /*********************************************************************
4640 * Create a dictionary of excluded kexts from the given booter data.
4641 *********************************************************************/
4642 /* static */
4643 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4644 OSKext::createExcludeListFromBooterData(
4645 OSDictionary * theDictionary,
4646 OSCollectionIterator * theIterator )
4647 {
4648 OSString * deviceTreeName = NULL; // do not release
4649 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4650 char * booterDataPtr = NULL; // do not release
4651 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4652 char * infoDictAddr = NULL; // do not release
4653 OSSharedPtr<OSObject> parsedXML;
4654 OSDictionary * theInfoDict = NULL; // do not release
4655
4656 theIterator->reset();
4657
4658 /* look for AppleKextExcludeList.kext */
4659 while ((deviceTreeName =
4660 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4661 const char * devTreeNameCString;
4662 OSData * deviceTreeEntry; // do not release
4663 OSString * myBundleID; // do not release
4664
4665 deviceTreeEntry =
4666 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4667 if (!deviceTreeEntry) {
4668 continue;
4669 }
4670
4671 /* Make sure it is a kext */
4672 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4673 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4674 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4675 OSKextLog(NULL,
4676 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4677 "\"%s\" not a kext",
4678 devTreeNameCString);
4679 continue;
4680 }
4681
4682 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4683 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4684 if (!deviceTreeBuffer) {
4685 continue;
4686 }
4687
4688 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4689 if (!booterDataPtr) {
4690 continue;
4691 }
4692
4693 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4694 if (!kextFileInfo->infoDictPhysAddr ||
4695 !kextFileInfo->infoDictLength) {
4696 continue;
4697 }
4698
4699 infoDictAddr = (char *)
4700 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4701 if (!infoDictAddr) {
4702 continue;
4703 }
4704
4705 parsedXML = OSUnserializeXML(infoDictAddr);
4706 if (!parsedXML) {
4707 continue;
4708 }
4709
4710 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4711 if (!theInfoDict) {
4712 continue;
4713 }
4714
4715 myBundleID =
4716 OSDynamicCast(OSString,
4717 theInfoDict->getObject(kCFBundleIdentifierKey));
4718 if (myBundleID &&
4719 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4720 boolean_t updated = updateExcludeList(theInfoDict);
4721 if (!updated) {
4722 /* 25322874 */
4723 panic("Missing OSKextExcludeList dictionary");
4724 }
4725 break;
4726 }
4727 } // while ( (deviceTreeName = ...) )
4728
4729 return;
4730 }
4731
4732 /*********************************************************************
4733 * Create a dictionary of excluded kexts from the given prelink
4734 * info (kernelcache).
4735 *********************************************************************/
4736 /* static */
4737 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4738 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4739 {
4740 OSDictionary * myInfoDict = NULL; // do not release
4741 OSString * myBundleID; // do not release
4742 u_int i;
4743
4744 /* Find the Apple Kext Exclude List. */
4745 for (i = 0; i < theInfoArray->getCount(); i++) {
4746 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4747 if (!myInfoDict) {
4748 continue;
4749 }
4750 myBundleID =
4751 OSDynamicCast(OSString,
4752 myInfoDict->getObject(kCFBundleIdentifierKey));
4753 if (myBundleID &&
4754 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4755 boolean_t updated = updateExcludeList(myInfoDict);
4756 if (!updated) {
4757 /* 25322874 */
4758 panic("Missing OSKextExcludeList dictionary");
4759 }
4760 break;
4761 }
4762 } // for (i = 0; i < theInfoArray->getCount()...
4763
4764 return;
4765 }
4766
4767 /* static */
4768 boolean_t
updateExcludeList(OSDictionary * infoDict)4769 OSKext::updateExcludeList(OSDictionary *infoDict)
4770 {
4771 OSDictionary *myTempDict = NULL; // do not free
4772 OSString *myTempString = NULL; // do not free
4773 OSKextVersion newVersion = 0;
4774 boolean_t updated = false;
4775
4776 if (!infoDict) {
4777 return false;
4778 }
4779
4780 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4781 if (!myTempDict) {
4782 return false;
4783 }
4784
4785 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4786 if (!myTempString) {
4787 return false;
4788 }
4789
4790 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4791 if (newVersion == 0) {
4792 return false;
4793 }
4794
4795 IORecursiveLockLock(sKextLock);
4796
4797 if (newVersion > sExcludeListVersion) {
4798 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4799 sExcludeListVersion = newVersion;
4800 updated = true;
4801 }
4802
4803 IORecursiveLockUnlock(sKextLock);
4804 return updated;
4805 }
4806
4807 #if PRAGMA_MARK
4808 #pragma mark Accessors
4809 #endif
4810
4811 /*********************************************************************
4812 *********************************************************************/
4813 const OSObject *
getBundleExecutable(void)4814 OSKext::getBundleExecutable(void)
4815 {
4816 return infoDict->getObject(kCFBundleExecutableKey);
4817 }
4818
4819 /*********************************************************************
4820 *********************************************************************/
4821 const OSSymbol *
getIdentifier(void)4822 OSKext::getIdentifier(void)
4823 {
4824 return bundleID.get();
4825 }
4826
4827 /*********************************************************************
4828 * A kext must have a bundle identifier to even survive initialization;
4829 * this is guaranteed to exist past then.
4830 *********************************************************************/
4831 const char *
getIdentifierCString(void)4832 OSKext::getIdentifierCString(void)
4833 {
4834 return bundleID->getCStringNoCopy();
4835 }
4836
4837 /*********************************************************************
4838 *********************************************************************/
4839 OSKextVersion
getVersion(void)4840 OSKext::getVersion(void)
4841 {
4842 return version;
4843 }
4844
4845 /*********************************************************************
4846 *********************************************************************/
4847 OSKextVersion
getCompatibleVersion(void)4848 OSKext::getCompatibleVersion(void)
4849 {
4850 return compatibleVersion;
4851 }
4852
4853 /*********************************************************************
4854 *********************************************************************/
4855 bool
isLibrary(void)4856 OSKext::isLibrary(void)
4857 {
4858 return getCompatibleVersion() > 0;
4859 }
4860
4861 /*********************************************************************
4862 *********************************************************************/
4863 bool
isCompatibleWithVersion(OSKextVersion aVersion)4864 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4865 {
4866 if ((compatibleVersion > -1 && version > -1) &&
4867 (compatibleVersion <= version && aVersion <= version)) {
4868 return true;
4869 }
4870 return false;
4871 }
4872
4873 /*********************************************************************
4874 *********************************************************************/
4875 bool
declaresExecutable(void)4876 OSKext::declaresExecutable(void)
4877 {
4878 if (isDriverKit()) {
4879 return false;
4880 }
4881 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4882 }
4883
4884 /*********************************************************************
4885 *********************************************************************/
4886 OSData *
getExecutable(void)4887 OSKext::getExecutable(void)
4888 {
4889 OSData * result = NULL;
4890 OSSharedPtr<OSData> extractedExecutable;
4891
4892 if (flags.builtin) {
4893 return sKernelKext->linkedExecutable.get();
4894 }
4895
4896 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4897 if (result) {
4898 return result;
4899 }
4900
4901 #if CONFIG_KXLD
4902 OSData * mkextExecutableRef = NULL; // do not release
4903 mkextExecutableRef = OSDynamicCast(OSData,
4904 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4905
4906 if (mkextExecutableRef) {
4907 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4908 mkextExecutableRef->getBytesNoCopy();
4909 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4910 if (mkextVersion == MKEXT_VERS_2) {
4911 mkext2_file_entry * fileinfo =
4912 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4913 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4914 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4915 extractedExecutable = extractMkext2FileData(
4916 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4917 compressedSize, fullSize);
4918 } else {
4919 OSKextLog(this, kOSKextLogErrorLevel |
4920 kOSKextLogArchiveFlag,
4921 "Kext %s - unknown mkext version 0x%x for executable.",
4922 getIdentifierCString(), mkextVersion);
4923 }
4924
4925 /* Regardless of success, remove the mkext executable,
4926 * and drop one reference on the mkext. (setExecutable() does not
4927 * replace, it removes, or panics if asked to replace.)
4928 */
4929 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4930 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4931
4932 if (extractedExecutable && extractedExecutable->getLength()) {
4933 if (!setExecutable(extractedExecutable.get())) {
4934 goto finish;
4935 }
4936 result = extractedExecutable.get();
4937 } else {
4938 goto finish;
4939 }
4940 }
4941
4942 finish:
4943 #endif // CONFIG_KXLD
4944 return result;
4945 }
4946
4947 /*********************************************************************
4948 *********************************************************************/
4949 bool
isInterface(void)4950 OSKext::isInterface(void)
4951 {
4952 return flags.interface;
4953 }
4954
4955 /*********************************************************************
4956 *********************************************************************/
4957 bool
isKernel(void)4958 OSKext::isKernel(void)
4959 {
4960 return this == sKernelKext;
4961 }
4962
4963 /*********************************************************************
4964 *********************************************************************/
4965 bool
isKernelComponent(void)4966 OSKext::isKernelComponent(void)
4967 {
4968 return flags.kernelComponent ? true : false;
4969 }
4970
4971 /*********************************************************************
4972 *********************************************************************/
4973 bool
isExecutable(void)4974 OSKext::isExecutable(void)
4975 {
4976 return !isKernel() && !isInterface() && declaresExecutable();
4977 }
4978
4979 /*********************************************************************
4980 *********************************************************************/
4981 bool
isSpecialKernelBinary(void)4982 OSKext::isSpecialKernelBinary(void)
4983 {
4984 return false;
4985 }
4986
4987 /*********************************************************************
4988 * We might want to check this recursively for all dependencies,
4989 * since a subtree of dependencies could get loaded before we hit
4990 * a dependency that isn't safe-boot-loadable.
4991 *
4992 * xxx - Might want to return false if OSBundleEnableKextLogging or
4993 * OSBundleDebugLevel
4994 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4995 * the point except it's usually development drivers, which might
4996 * cause panics on startup, that have those properties). Heh; could
4997 * use a "kx" boot-arg!
4998 *********************************************************************/
4999 bool
isLoadableInSafeBoot(void)5000 OSKext::isLoadableInSafeBoot(void)
5001 {
5002 bool result = false;
5003 OSString * required = NULL; // do not release
5004
5005 if (isKernel()) {
5006 result = true;
5007 goto finish;
5008 }
5009
5010 if (isDriverKit()) {
5011 result = true;
5012 goto finish;
5013 }
5014
5015 required = OSDynamicCast(OSString,
5016 getPropertyForHostArch(kOSBundleRequiredKey));
5017 if (!required) {
5018 goto finish;
5019 }
5020 if (required->isEqualTo(kOSBundleRequiredRoot) ||
5021 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
5022 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
5023 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
5024 required->isEqualTo(kOSBundleRequiredConsole)) {
5025 result = true;
5026 }
5027
5028 finish:
5029 return result;
5030 }
5031
5032 /*********************************************************************
5033 *********************************************************************/
5034 bool
isPrelinked(void)5035 OSKext::isPrelinked(void)
5036 {
5037 return flags.prelinked ? true : false;
5038 }
5039
5040 /*********************************************************************
5041 *********************************************************************/
5042 bool
isLoaded(void)5043 OSKext::isLoaded(void)
5044 {
5045 return flags.loaded ? true : false;
5046 }
5047
5048 /*********************************************************************
5049 *********************************************************************/
5050 bool
isStarted(void)5051 OSKext::isStarted(void)
5052 {
5053 return flags.started ? true : false;
5054 }
5055
5056 /*********************************************************************
5057 *********************************************************************/
5058 bool
isCPPInitialized(void)5059 OSKext::isCPPInitialized(void)
5060 {
5061 return flags.CPPInitialized;
5062 }
5063
5064 /*********************************************************************
5065 *********************************************************************/
5066 void
setCPPInitialized(bool initialized)5067 OSKext::setCPPInitialized(bool initialized)
5068 {
5069 flags.CPPInitialized = initialized;
5070 }
5071
5072 /*********************************************************************
5073 *********************************************************************/
5074 uint32_t
getLoadTag(void)5075 OSKext::getLoadTag(void)
5076 {
5077 return loadTag;
5078 }
5079
5080 /*********************************************************************
5081 *********************************************************************/
5082 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)5083 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5084 {
5085 if (linkedExecutable) {
5086 *loadSize = linkedExecutable->getLength();
5087
5088 /* If we have a kmod_info struct, calculated the wired size
5089 * from that. Otherwise it's the full load size.
5090 */
5091 if (kmod_info) {
5092 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5093 } else {
5094 *wiredSize = *loadSize;
5095 }
5096 } else {
5097 *wiredSize = 0;
5098 *loadSize = 0;
5099 }
5100 }
5101
5102 /*********************************************************************
5103 *********************************************************************/
5104 OSSharedPtr<OSData>
copyUUID(void)5105 OSKext::copyUUID(void)
5106 {
5107 OSSharedPtr<OSData> result;
5108 OSData * theExecutable = NULL; // do not release
5109 const kernel_mach_header_t * header;
5110
5111 /* An interface kext doesn't have a linked executable with an LC_UUID,
5112 * we create one when it's linked.
5113 */
5114 if (interfaceUUID) {
5115 result = interfaceUUID;
5116 goto finish;
5117 }
5118
5119 if (flags.builtin || isInterface()) {
5120 return sKernelKext->copyUUID();
5121 }
5122
5123 if (isDriverKit() && infoDict) {
5124 return driverKitUUID;
5125 }
5126
5127 /* For real kexts, try to get the UUID from the linked executable,
5128 * or if is hasn't been linked yet, the unrelocated executable.
5129 */
5130 theExecutable = linkedExecutable.get();
5131 if (!theExecutable) {
5132 theExecutable = getExecutable();
5133 }
5134
5135 if (!theExecutable) {
5136 goto finish;
5137 }
5138
5139 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5140 result = copyMachoUUID(header);
5141
5142 finish:
5143 return result;
5144 }
5145
5146 /*********************************************************************
5147 *********************************************************************/
5148 OSSharedPtr<OSData>
copyTextUUID(void)5149 OSKext::copyTextUUID(void)
5150 {
5151 if (flags.builtin) {
5152 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
5153 }
5154 return copyUUID();
5155 }
5156
5157 /*********************************************************************
5158 *********************************************************************/
5159 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)5160 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5161 {
5162 OSSharedPtr<OSData> result;
5163 const struct load_command * load_cmd = NULL;
5164 const struct uuid_command * uuid_cmd = NULL;
5165 uint32_t i;
5166
5167 load_cmd = (const struct load_command *)&header[1];
5168
5169 if (header->magic != MH_MAGIC_KERNEL) {
5170 OSKextLog(NULL,
5171 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5172 "%s: bad header %p",
5173 __func__,
5174 header);
5175 goto finish;
5176 }
5177
5178 for (i = 0; i < header->ncmds; i++) {
5179 if (load_cmd->cmd == LC_UUID) {
5180 uuid_cmd = (struct uuid_command *)load_cmd;
5181 result = OSData::withValue(uuid_cmd->uuid);
5182 goto finish;
5183 }
5184 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5185 }
5186
5187 finish:
5188 return result;
5189 }
5190
5191 void
setDriverKitUUID(OSData * uuid)5192 OSKext::setDriverKitUUID(OSData *uuid)
5193 {
5194 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5195 OSSafeReleaseNULL(uuid);
5196 }
5197 }
5198
5199 OSData *
getDextUniqueID(void)5200 OSKext::getDextUniqueID(void)
5201 {
5202 if (isDriverKit() && dextUniqueID != NULL) {
5203 return dextUniqueID.get();
5204 }
5205
5206 return NULL;
5207 }
5208
5209 /*
5210 * In case a DextUniqueID exists this function returns
5211 * an allocated char* with the hexadecimal represantition of
5212 * DextUniqueID.
5213 * The returned pinter needs to be freed with kfree_data, the
5214 * size of the allocated buffer is returned in size.
5215 */
5216 static const char *
getDextUniqueIDCString(OSData * dextUniqueID,unsigned int * size)5217 getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5218 {
5219 if (dextUniqueID != NULL) {
5220 char *s_buffer = NULL;
5221 unsigned int d_length = dextUniqueID->getLength();
5222 /*
5223 * We are converting in hex, so for every byte we will have
5224 * 2 hex chars and one last \0.
5225 */
5226 unsigned int s_length = d_length * 2 + 1;
5227 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5228
5229 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5230 int cpos = 0;
5231 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5232 int ret = snprintf(s_buffer + cpos, s_length - cpos - 1, "%02X", uid[i]);
5233 if (ret <= 0) {
5234 break;
5235 }
5236 cpos += ret;
5237 }
5238 *size = s_length;
5239
5240 return s_buffer;
5241 }
5242
5243 return NULL;
5244 }
5245
5246 /*
5247 * Atomically swaps the olddext with newdext.
5248 * olddext will be unloaded, so it might be freed
5249 * after this call unless it was previously retained.
5250 *
5251 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5252 */
5253 void
replaceDextInternal(OSKext * olddext,OSKext * newdext)5254 OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5255 {
5256 OSReturn result;
5257 const OSSymbol * dextID = olddext->getIdentifier();
5258 OSData * oldDextUniqueIdentifier = olddext->getDextUniqueID();
5259 OSSharedPtr<OSArray> new_personalities;
5260 OSSharedPtr<OSString> kextIdentifier;
5261 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5262 assert(lock_held);
5263
5264 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5265 dextID->retain();
5266
5267 if (newdext != NULL) {
5268 __assert_only bool eq = dextID->isEqualTo(newdext->getIdentifier());
5269 assert(eq);
5270 }
5271
5272 if (newdext != NULL) {
5273 /*
5274 * Swap the catalog personalities.
5275 */
5276 new_personalities = newdext->copyPersonalitiesArray();
5277 olddext->updatePersonalitiesInCatalog(new_personalities.get());
5278 }
5279
5280 if (NULL != oldDextUniqueIdentifier) {
5281 oldDextUniqueIdentifier->retain();
5282 }
5283
5284 /*
5285 * Unload the dext.
5286 */
5287 result = olddext->unload();
5288 if (result != kOSReturnSuccess) {
5289 OSKextLog(NULL,
5290 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5291 "Cannot unload dext for upgrade %s: %d\n",
5292 dextID->getCStringNoCopy(), result);
5293 }
5294
5295 if (newdext != NULL) {
5296 /*
5297 * Swap the dexts on the OSKext dictionary.
5298 * This might free the dext.
5299 */
5300 sKextsByID->setObject(dextID, newdext);
5301 } else {
5302 /*
5303 * Remove the old dext
5304 */
5305 removeKext(olddext, true);
5306 }
5307
5308 /*
5309 * Inform userspace.
5310 */
5311 if (newdext != NULL) {
5312 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), newdext->getDextUniqueID());
5313 if (result != kOSReturnSuccess) {
5314 OSKextLog(NULL,
5315 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5316 "Cannot send upgrade notification for %s\n",
5317 dextID->getCStringNoCopy());
5318 }
5319 } else {
5320 // notify dext removal
5321 queueKextNotification(kKextRequestPredicateUnloadNotification,
5322 OSDynamicCast(OSString, dextID), oldDextUniqueIdentifier);
5323 }
5324
5325 OSSafeReleaseNULL(dextID);
5326 OSSafeReleaseNULL(oldDextUniqueIdentifier);
5327 }
5328
5329 /*
5330 * To be called with sKextLock held.
5331 * NOTE: this could unload the olddext.
5332 */
5333 bool
upgradeDext(OSKext * olddext,OSKext * newdext)5334 OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5335 {
5336 const char * dextIDCS = newdext->getIdentifierCString();
5337 __assert_only bool old_isDext = olddext->isDriverKit();
5338 __assert_only bool new_isDext = newdext->isDriverKit();
5339 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5340
5341 assert(old_isDext && new_isDext);
5342 assert(lock_held);
5343
5344 /*
5345 * New dext and old dext have the same ID.
5346 * We use this ID as key on the OSKext
5347 * dictionarys/arrays.
5348 */
5349 const OSSymbol * dextID = newdext->getIdentifier();
5350 __assert_only bool eq = dextID->isEqualTo(olddext->getIdentifier());
5351 assert(eq);
5352
5353 /*
5354 * Set this OSKect as to update.
5355 * Note that this flags will never be removed once set.
5356 * When a OSKext is marked, it will be substitued by a new
5357 * OSKext, and every subsystem having a reference on this
5358 * OSKext need to know they have check if they can use
5359 * this OSKext or look for a new one.
5360 */
5361 olddext->flags.dextToReplace = 1;
5362
5363 /*
5364 * Check if the current OSKext has any
5365 * userspace processes launched.
5366 * In this case we cannot upgrade and we have to
5367 * delay the upgrade until all processes
5368 * are done.
5369 */
5370 if (olddext->dextLaunchedCount == 0) {
5371 /*
5372 * Be sure that if there are no launched dexts, no
5373 * pending upgrades exist.
5374 * This is an error if it happens, as the decrement
5375 * should have removed the dext from sDriverKitToUpgradeByID
5376 * in case it reached 0.
5377 */
5378 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(dextID);
5379 if (pending_upgdare != NULL) {
5380 OSKextLog(NULL,
5381 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5382 "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5383 dextIDCS);
5384 goto out;
5385 }
5386
5387 replaceDextInternal(olddext, newdext);
5388 return true;
5389 }
5390
5391 out:
5392
5393 /*
5394 * Delay the upgrade.
5395 * Make the new dext available in sDriverKitToUpgradeByID.
5396 * In case there was already a pending upgrade, this will
5397 * overwrite it.
5398 */
5399 sDriverKitToUpgradeByID->setObject(dextID, newdext);
5400 return false;
5401 }
5402
5403 /*
5404 * To be called with sKextLock held.
5405 * NOTE: this could unload the dext.
5406 */
5407 bool
removeDext(OSKext * dext)5408 OSKext::removeDext(OSKext *dext)
5409 {
5410 __assert_only bool dext_isDext = dext->isDriverKit();
5411 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5412 IOReturn result;
5413
5414 assert(dext_isDext);
5415 assert(lock_held);
5416
5417 /*
5418 * Set this OSKext to be unloaded when all running instances exit.
5419 */
5420 dext->flags.dextToReplace = 1;
5421
5422 result = gIOCatalogue->terminateDriversForModule(
5423 dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5424 if (result != kOSReturnSuccess) {
5425 OSKextLog(dext,
5426 kOSKextLogErrorLevel |
5427 kOSKextLogKextBookkeepingFlag,
5428 "%s services failed to terminate - 0x%x.",
5429 dext->getIdentifierCString(), result);
5430 }
5431
5432 dext->removePersonalitiesFromCatalog();
5433 sDriverKitToUpgradeByID->removeObject(dext->getIdentifier());
5434
5435 /*
5436 * Check if the current OSKext has any
5437 * userspace processes launched.
5438 * In this case we cannot unload and we have to
5439 * delay the unload until all processes
5440 * are done.
5441 */
5442 if (dext->dextLaunchedCount == 0) {
5443 replaceDextInternal(dext, NULL);
5444 return true;
5445 }
5446
5447 return false;
5448 }
5449
5450 bool
incrementDextLaunchCount(OSKext * dext,OSData * dextUniqueIDToMatch)5451 OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5452 {
5453 bool ret = false;
5454 __assert_only bool isDext = dext->isDriverKit();
5455 assert(isDext);
5456
5457 const char * dextIDCS = dext->getIdentifierCString();
5458 OSData *myDextUniqueID = dext->getDextUniqueID();
5459
5460 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5461 OSKextLog(dext,
5462 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5463 "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5464 dextIDCS);
5465 return ret;
5466 }
5467
5468 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5469 const char *dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5470 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueIDToMatch, &dextUniqueIDToMatchCStringSize);
5471 assert(dextUniqueIDCString != NULL);
5472 assert(dextUniqueIDToMatchCString != NULL);
5473
5474 IORecursiveLockLock(sKextLock);
5475
5476 /*
5477 * Check that the dext we are referencing is the same
5478 * looked for the match.
5479 */
5480 if (myDextUniqueID->isEqualTo(dextUniqueIDToMatch)) {
5481 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5482 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5483 OSKextLog(dext,
5484 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5485 "Too many dexts launched for %s UniqueID %s\n",
5486 dextIDCS, dextUniqueIDCString);
5487 } else {
5488 dext->dextLaunchedCount++;
5489 ret = true;
5490
5491 OSKextLog(dext,
5492 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5493 "New dext launched for %s UniqueID %s",
5494 dextIDCS, dextUniqueIDCString);
5495 }
5496 } else {
5497 OSKextLog(dext,
5498 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5499 "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5500 dextIDCS, dextUniqueIDCString);
5501 }
5502 } else {
5503 OSKextLog(dext,
5504 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5505 "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5506 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5507 }
5508
5509 IORecursiveLockUnlock(sKextLock);
5510
5511 if (dextUniqueIDCString != NULL) {
5512 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5513 }
5514 if (dextUniqueIDToMatchCString != NULL) {
5515 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5516 }
5517 return ret;
5518 }
5519
5520 bool
decrementDextLaunchCount(OSString * bundleID)5521 OSKext::decrementDextLaunchCount(OSString *bundleID)
5522 {
5523 bool ret = false;
5524 const char * dextIDCS;
5525 OSData *myDextUniqueID;
5526 unsigned int dextUniqueIDCStringSize = 0;
5527 const char * dextUniqueIDCString = NULL;
5528 OSKext* dext = NULL;
5529
5530 if (!bundleID) {
5531 return ret;
5532 }
5533 dextIDCS = bundleID->getCStringNoCopy();
5534
5535 IORecursiveLockLock(sKextLock);
5536
5537 /*
5538 * Look for the dext with the bundle it. This
5539 * call is triggered only if a previous increment was
5540 * performed. It means that the dext could have not
5541 * been upgraded as its dextLaunchedCount was at least 1.
5542 * Because of this it still needs to be available
5543 * in sKextsByID.
5544 */
5545 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5546 if (!dext || !dext->isDriverKit()) {
5547 OSKextLog(NULL,
5548 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5549 "Cannot find dext for %s, cannot decrement dext launches\n",
5550 dextIDCS);
5551
5552 goto out_locked;
5553 }
5554
5555 myDextUniqueID = dext->getDextUniqueID();
5556 if (!myDextUniqueID) {
5557 OSKextLog(dext,
5558 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5559 "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5560 dextIDCS);
5561
5562 goto out_locked;
5563 }
5564 dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5565 assert(dextUniqueIDCString != NULL);
5566
5567 if (dext->dextLaunchedCount == 0) {
5568 OSKextLog(dext,
5569 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5570 "Over decrementing dext launch for %s UniqueID %s\n",
5571 dextIDCS, dextUniqueIDCString);
5572
5573 goto out_locked;
5574 }
5575
5576 dext->dextLaunchedCount--;
5577
5578 OSKextLog(dext,
5579 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5580 "Dext terminated for %s UniqueID %s",
5581 dextIDCS, dextUniqueIDCString);
5582
5583 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5584 /*
5585 * Find the upgraded dext.
5586 */
5587 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5588 if (newdext) {
5589 OSKextLog(dext,
5590 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5591 "Dext upgrade for %s UniqueID %s",
5592 dextIDCS, dextUniqueIDCString);
5593 replaceDextInternal(dext, newdext);
5594 /* NOTE dext could have been freed past this point */
5595
5596 sDriverKitToUpgradeByID->removeObject(dextIDCS);
5597 } else {
5598 OSKextLog(dext,
5599 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5600 "Dext unload for %s UniqueID %s",
5601 dextIDCS, dextUniqueIDCString);
5602 replaceDextInternal(dext, NULL);
5603 }
5604
5605 ret = true;
5606 }
5607 out_locked:
5608 IORecursiveLockUnlock(sKextLock);
5609
5610 if (dextUniqueIDCString != NULL) {
5611 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5612 }
5613
5614 return ret;
5615 }
5616
5617 /*********************************************************************
5618 *********************************************************************/
5619 #if defined (__arm__)
5620 #include <arm/arch.h>
5621 #endif
5622
5623 #if defined (__x86_64__)
5624 #define ARCHNAME "x86_64"
5625 #elif defined (__arm64__)
5626 #define ARCHNAME "arm64"
5627 #elif defined (__arm__)
5628
5629 #if defined (__ARM_ARCH_7S__)
5630 #define ARCHNAME "armv7s"
5631 #elif defined (__ARM_ARCH_7F__)
5632 #define ARCHNAME "armv7f"
5633 #elif defined (__ARM_ARCH_7K__)
5634 #define ARCHNAME "armv7k"
5635 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5636 #define ARCHNAME "armv7"
5637 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5638 #define ARCHNAME "armv6"
5639 #endif
5640
5641 #elif defined (__arm64__)
5642 #define ARCHNAME "arm64"
5643 #else
5644 #error architecture not supported
5645 #endif
5646
5647 #define ARCH_SEPARATOR_CHAR '_'
5648
5649 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)5650 makeHostArchKey(const char * key, size_t * keySizeOut)
5651 {
5652 char * result = NULL;
5653 size_t keyLength = strlen(key);
5654 size_t keySize;
5655
5656 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5657 */
5658 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5659 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5660
5661 if (!result) {
5662 goto finish;
5663 }
5664 strlcpy(result, key, keySize);
5665 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5666 result[keyLength] = '\0';
5667 strlcat(result, ARCHNAME, keySize);
5668 *keySizeOut = keySize;
5669
5670 finish:
5671 return result;
5672 }
5673
5674 /*********************************************************************
5675 *********************************************************************/
5676 OSObject *
getPropertyForHostArch(const char * key)5677 OSKext::getPropertyForHostArch(const char * key)
5678 {
5679 OSObject * result = NULL;// do not release
5680 size_t hostArchKeySize = 0;
5681 char * hostArchKey = NULL;// must kfree
5682
5683 if (!key || !infoDict) {
5684 goto finish;
5685 }
5686
5687 /* Some properties are not allowed to be arch-variant:
5688 * - Any CFBundle... property.
5689 * - OSBundleIsInterface.
5690 * - OSKernelResource.
5691 */
5692 if (STRING_HAS_PREFIX(key, "OS") ||
5693 STRING_HAS_PREFIX(key, "IO")) {
5694 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
5695 if (!hostArchKey) {
5696 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5697 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5698 "Allocation failure.");
5699 goto finish;
5700 }
5701 result = infoDict->getObject(hostArchKey);
5702 }
5703
5704 if (!result) {
5705 result = infoDict->getObject(key);
5706 }
5707
5708 finish:
5709 if (hostArchKey) {
5710 kfree_data(hostArchKey, hostArchKeySize);
5711 }
5712 return result;
5713 }
5714
5715 #if PRAGMA_MARK
5716 #pragma mark Load/Start/Stop/Unload
5717 #endif
5718
5719 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5720
5721 /*********************************************************************
5722 * sExcludeListByID is a dictionary with keys / values of:
5723 * key = bundleID string of kext we will not allow to load
5724 * value = version string(s) of the kext that is to be denied loading.
5725 * The version strings can be comma delimited. For example if kext
5726 * com.foocompany.fookext has two versions that we want to deny
5727 * loading then the version strings might look like:
5728 * 1.0.0, 1.0.1
5729 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5730 * not load the kext.
5731 *
5732 * Value may also be in the form of "LE 2.0.0" (version numbers
5733 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5734 * number less than 2.0.0 will not load)
5735 *
5736 * NOTE - we cannot use the characters "<=" or "<" because we have code
5737 * that serializes plists and treats '<' as a special character.
5738 *********************************************************************/
5739 bool
isInExcludeList(void)5740 OSKext::isInExcludeList(void)
5741 {
5742 OSString * versionString = NULL; // do not release
5743 char * versionCString = NULL; // do not free
5744 size_t i;
5745 boolean_t wantLessThan = false;
5746 boolean_t wantLessThanEqualTo = false;
5747 boolean_t isInExcludeList = true;
5748 char myBuffer[32];
5749
5750 IORecursiveLockLock(sKextLock);
5751
5752 if (!sExcludeListByID) {
5753 isInExcludeList = false;
5754 } else {
5755 /* look up by bundleID in our exclude list and if found get version
5756 * string (or strings) that we will not allow to load
5757 */
5758 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5759 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5760 isInExcludeList = false;
5761 }
5762 }
5763
5764 IORecursiveLockUnlock(sKextLock);
5765
5766 if (!isInExcludeList) {
5767 return false;
5768 }
5769
5770 /* parse version strings */
5771 versionCString = (char *) versionString->getCStringNoCopy();
5772
5773 /* look for "LT" or "LE" form of version string, must be in first two
5774 * positions.
5775 */
5776 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5777 wantLessThan = true;
5778 versionCString += 2;
5779 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5780 wantLessThanEqualTo = true;
5781 versionCString += 2;
5782 }
5783
5784 for (i = 0; *versionCString != 0x00; versionCString++) {
5785 /* skip whitespace */
5786 if (isWhiteSpace(*versionCString)) {
5787 continue;
5788 }
5789
5790 /* peek ahead for version string separator or null terminator */
5791 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5792 /* OK, we have a version string */
5793 myBuffer[i++] = *versionCString;
5794 myBuffer[i] = 0x00;
5795
5796 OSKextVersion excludeVers;
5797 excludeVers = OSKextParseVersionString(myBuffer);
5798
5799 if (wantLessThanEqualTo) {
5800 if (version <= excludeVers) {
5801 return true;
5802 }
5803 } else if (wantLessThan) {
5804 if (version < excludeVers) {
5805 return true;
5806 }
5807 } else if (version == excludeVers) {
5808 return true;
5809 }
5810
5811 /* reset for the next (if any) version string */
5812 i = 0;
5813 wantLessThan = false;
5814 wantLessThanEqualTo = false;
5815 } else {
5816 /* save valid version character */
5817 myBuffer[i++] = *versionCString;
5818
5819 /* make sure bogus version string doesn't overrun local buffer */
5820 if (i >= sizeof(myBuffer)) {
5821 break;
5822 }
5823 }
5824 }
5825
5826 return false;
5827 }
5828
5829 /*********************************************************************
5830 * sNonLoadableKextsByID is a dictionary with keys / values of:
5831 * key = bundleID string of kext we will not allow to load
5832 * value = boolean (true == loadable, false == not loadable)
5833 *
5834 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5835 * i.e., the value for the kext's bundleID will be false. All kexts in
5836 * the primary and system KCs will always be marked as "loadable."
5837 *
5838 * This list ultimately comes from kexts which have been uninstalled
5839 * in user space by deleting the kext from disk, but which have not
5840 * yet been removed from the AuxKC. Because the user could choose to
5841 * re-install the exact same version of the kext, we need to keep
5842 * a dictionary of boolean values so that user space only needs to
5843 * keep a simple list of "uninstalled" or "missing" bundles. When
5844 * a bundle is re-installed, the iokit daemon can use the
5845 * AucKCBundleAvailable predicate to set the individual kext's
5846 * availability to true.
5847 *********************************************************************/
5848 bool
isLoadable(void)5849 OSKext::isLoadable(void)
5850 {
5851 bool isLoadable = true;
5852
5853 if (kc_type != KCKindAuxiliary) {
5854 /* this filtering only applies to kexts in the auxkc */
5855 return true;
5856 }
5857
5858 IORecursiveLockLock(sKextLock);
5859
5860 if (sNonLoadableKextsByID) {
5861 /* look up by bundleID in our exclude list and if found get version
5862 * string (or strings) that we will not allow to load
5863 */
5864 OSBoolean *loadableVal;
5865 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5866 if (loadableVal && !loadableVal->getValue()) {
5867 isLoadable = false;
5868 }
5869 }
5870 IORecursiveLockUnlock(sKextLock);
5871
5872 return isLoadable;
5873 }
5874
5875 /*********************************************************************
5876 *********************************************************************/
5877 /* static */
5878 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5879 OSKext::loadKextWithIdentifier(
5880 const char * kextIdentifierCString,
5881 Boolean allowDeferFlag,
5882 Boolean delayAutounloadFlag,
5883 OSKextExcludeLevel startOpt,
5884 OSKextExcludeLevel startMatchingOpt,
5885 OSArray * personalityNames)
5886 {
5887 OSReturn result = kOSReturnError;
5888 OSSharedPtr<OSString> kextIdentifier;
5889
5890 kextIdentifier = OSString::withCString(kextIdentifierCString);
5891 if (!kextIdentifier) {
5892 result = kOSKextReturnNoMemory;
5893 goto finish;
5894 }
5895 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5896 NULL /* kextRef */,
5897 allowDeferFlag, delayAutounloadFlag,
5898 startOpt, startMatchingOpt, personalityNames);
5899
5900 finish:
5901 return result;
5902 }
5903
5904 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5905 OSKext::loadKextWithIdentifier(
5906 OSString * kextIdentifier,
5907 OSSharedPtr<OSObject> &kextRef,
5908 Boolean allowDeferFlag,
5909 Boolean delayAutounloadFlag,
5910 OSKextExcludeLevel startOpt,
5911 OSKextExcludeLevel startMatchingOpt,
5912 OSArray * personalityNames)
5913 {
5914 OSObject * kextRefRaw = NULL;
5915 OSReturn result;
5916
5917 result = loadKextWithIdentifier(kextIdentifier,
5918 &kextRefRaw,
5919 allowDeferFlag,
5920 delayAutounloadFlag,
5921 startOpt,
5922 startMatchingOpt,
5923 personalityNames);
5924 if ((kOSReturnSuccess == result) && kextRefRaw) {
5925 kextRef.reset(kextRefRaw, OSNoRetain);
5926 }
5927 return result;
5928 }
5929
5930 /*********************************************************************
5931 *********************************************************************/
5932 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5933 OSKext::loadKextWithIdentifier(
5934 OSString * kextIdentifier,
5935 OSObject ** kextRef,
5936 Boolean allowDeferFlag,
5937 Boolean delayAutounloadFlag,
5938 OSKextExcludeLevel startOpt,
5939 OSKextExcludeLevel startMatchingOpt,
5940 OSArray * personalityNames)
5941 {
5942 OSReturn result = kOSReturnError;
5943 OSReturn pingResult = kOSReturnError;
5944 OSKext * theKext = NULL; // do not release
5945 OSSharedPtr<OSDictionary> loadRequest;
5946 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5947
5948 if (kextRef) {
5949 *kextRef = NULL;
5950 }
5951
5952 IORecursiveLockLock(sKextLock);
5953
5954 if (!kextIdentifier) {
5955 result = kOSKextReturnInvalidArgument;
5956 goto finish;
5957 }
5958
5959 OSKext::recordIdentifierRequest(kextIdentifier);
5960
5961 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5962 if (!theKext) {
5963 if (!allowDeferFlag) {
5964 OSKextLog(/* kext */ NULL,
5965 kOSKextLogErrorLevel |
5966 kOSKextLogLoadFlag,
5967 "Can't load kext %s - not found.",
5968 kextIdentifier->getCStringNoCopy());
5969 goto finish;
5970 }
5971
5972 if (!sKernelRequestsEnabled) {
5973 OSKextLog(theKext,
5974 kOSKextLogErrorLevel |
5975 kOSKextLogLoadFlag,
5976 "Can't load kext %s - requests to user space are disabled.",
5977 kextIdentifier->getCStringNoCopy());
5978 result = kOSKextReturnDisabled;
5979 goto finish;
5980 }
5981
5982 /* Create a new request unless one is already sitting
5983 * in sKernelRequests for this bundle identifier
5984 */
5985 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5986 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5987 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5988 loadRequest);
5989 if (result != kOSReturnSuccess) {
5990 goto finish;
5991 }
5992 if (!_OSKextSetRequestArgument(loadRequest.get(),
5993 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5994 result = kOSKextReturnNoMemory;
5995 goto finish;
5996 }
5997 if (!sKernelRequests->setObject(loadRequest.get())) {
5998 result = kOSKextReturnNoMemory;
5999 goto finish;
6000 }
6001
6002 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6003 result = kOSKextReturnNoMemory;
6004 goto finish;
6005 }
6006
6007 OSKextLog(theKext,
6008 kOSKextLogDebugLevel |
6009 kOSKextLogLoadFlag,
6010 "Kext %s not found; queued load request to user space.",
6011 kextIdentifier->getCStringNoCopy());
6012 }
6013
6014 pingResult = OSKext::pingIOKitDaemon();
6015 if (pingResult == kOSKextReturnDisabled) {
6016 OSKextLog(/* kext */ NULL,
6017 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
6018 kOSKextLogLoadFlag,
6019 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
6020 kextIdentifier->getCStringNoCopy());
6021 }
6022
6023 result = kOSKextReturnDeferred;
6024 goto finish;
6025 }
6026
6027 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
6028
6029 if (result != kOSReturnSuccess) {
6030 OSKextLog(theKext,
6031 kOSKextLogErrorLevel |
6032 kOSKextLogLoadFlag,
6033 "Failed to load kext %s (error 0x%x).",
6034 kextIdentifier->getCStringNoCopy(), (int)result);
6035
6036 if (theKext->kc_type == KCKindUnknown) {
6037 OSKext::removeKext(theKext,
6038 /* terminateService/removePersonalities */ true);
6039 }
6040 goto finish;
6041 }
6042
6043 if (delayAutounloadFlag) {
6044 OSKextLog(theKext,
6045 kOSKextLogProgressLevel |
6046 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6047 "Setting delayed autounload for %s.",
6048 kextIdentifier->getCStringNoCopy());
6049 theKext->flags.delayAutounload = 1;
6050 }
6051
6052 finish:
6053 if ((kOSReturnSuccess == result) && kextRef) {
6054 *kextRef = theKext;
6055 theKext->matchingRefCount++;
6056 theKext->retain();
6057 }
6058
6059 IORecursiveLockUnlock(sKextLock);
6060
6061 return result;
6062 }
6063
6064 /*********************************************************************
6065 *********************************************************************/
6066 /* static */
6067 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)6068 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
6069 {
6070 OSReturn result = kOSReturnError;
6071
6072 OSBoolean *delayAutounloadBool = NULL; // do not release
6073 OSNumber *startKextExcludeNum = NULL; // do not release
6074 OSNumber *startMatchingExcludeNum = NULL; // do not release
6075 OSArray *personalityNames = NULL; // do not release
6076
6077 /*
6078 * Default values for these options:
6079 * regular autounload behavior
6080 * start the kext
6081 * send all personalities to the catalog
6082 */
6083 Boolean delayAutounload = false;
6084 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
6085 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
6086
6087 IORecursiveLockLock(sKextLock);
6088
6089 OSKextLog(/* kext */ NULL,
6090 kOSKextLogDebugLevel |
6091 kOSKextLogIPCFlag,
6092 "Received kext KC load request from user space.");
6093
6094 /* Regardless of processing, the fact that we have gotten here means some
6095 * user-space program is up and talking to us, so we'll switch our kext
6096 * registration to reflect that.
6097 */
6098 if (!sUserLoadsActive) {
6099 OSKextLog(/* kext */ NULL,
6100 kOSKextLogProgressLevel |
6101 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6102 "Switching to late startup (user-space) kext loading policy.");
6103 sUserLoadsActive = true;
6104 }
6105
6106 delayAutounloadBool = OSDynamicCast(OSBoolean,
6107 _OSKextGetRequestArgument(requestDict,
6108 kKextRequestArgumentDelayAutounloadKey));
6109 startKextExcludeNum = OSDynamicCast(OSNumber,
6110 _OSKextGetRequestArgument(requestDict,
6111 kKextRequestArgumentStartExcludeKey));
6112 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6113 _OSKextGetRequestArgument(requestDict,
6114 kKextRequestArgumentStartMatchingExcludeKey));
6115 personalityNames = OSDynamicCast(OSArray,
6116 _OSKextGetRequestArgument(requestDict,
6117 kKextRequestArgumentPersonalityNamesKey));
6118
6119 if (delayAutounloadBool) {
6120 delayAutounload = delayAutounloadBool->getValue();
6121 }
6122 if (startKextExcludeNum) {
6123 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6124 }
6125 if (startMatchingExcludeNum) {
6126 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6127 }
6128
6129 OSKextLog(/* kext */ NULL,
6130 kOSKextLogProgressLevel |
6131 kOSKextLogIPCFlag,
6132 "Received request from user space to load KC kext %s.",
6133 theKext->getIdentifierCString());
6134
6135 /* this could be in the Auxiliary KC, so record the load request */
6136 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6137
6138 /*
6139 * Load the kext
6140 */
6141 result = theKext->load(startKextExcludeLevel,
6142 startMatchingExcludeLevel, personalityNames);
6143
6144 if (result != kOSReturnSuccess) {
6145 OSKextLog(theKext,
6146 kOSKextLogErrorLevel |
6147 kOSKextLogLoadFlag,
6148 "Failed to load kext %s (error 0x%x).",
6149 theKext->getIdentifierCString(), (int)result);
6150
6151 OSKext::removeKext(theKext,
6152 /* terminateService/removePersonalities */ true);
6153 goto finish;
6154 } else {
6155 OSKextLog(theKext,
6156 kOSKextLogProgressLevel |
6157 kOSKextLogLoadFlag,
6158 "Kext %s Loaded successfully from %s KC",
6159 theKext->getIdentifierCString(), theKext->getKCTypeString());
6160 }
6161
6162 if (delayAutounload) {
6163 OSKextLog(theKext,
6164 kOSKextLogProgressLevel |
6165 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6166 "Setting delayed autounload for %s.",
6167 theKext->getIdentifierCString());
6168 theKext->flags.delayAutounload = 1;
6169 }
6170
6171 finish:
6172 IORecursiveLockUnlock(sKextLock);
6173
6174 return result;
6175 }
6176
6177 /*********************************************************************
6178 *********************************************************************/
6179 /* static */
6180 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)6181 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6182 {
6183 OSReturn result = kOSReturnError;
6184 OSDictionary *anInfoDict = NULL; // do not release
6185
6186 anInfoDict = OSDynamicCast(OSDictionary,
6187 _OSKextGetRequestArgument(requestDict,
6188 kKextRequestArgumentCodelessInfoKey));
6189 if (anInfoDict == NULL) {
6190 OSKextLog(/* kext */ NULL,
6191 kOSKextLogErrorLevel |
6192 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6193 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6194 kextIdentifier->getCStringNoCopy());
6195 return kOSKextReturnInvalidArgument;
6196 }
6197
6198 IORecursiveLockLock(sKextLock);
6199
6200 OSKextLog(/* kext */ NULL,
6201 kOSKextLogProgressLevel |
6202 kOSKextLogIPCFlag,
6203 "Received request from user space to load codeless kext %s.",
6204 kextIdentifier->getCStringNoCopy());
6205
6206 {
6207 // instantiate a new kext, and don't hold a reference
6208 // (the kext subsystem will hold one implicitly)
6209 OSKextInitResult ret;
6210 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, &ret);
6211 if (!newKext) {
6212 /*
6213 * We might have failed to create a new OSKext
6214 * because the old one should still be used.
6215 * Check if that is the case.
6216 */
6217 if (ret != kOSKextInitFailure) {
6218 result = kOSReturnSuccess;
6219 goto finish;
6220 }
6221 OSKextLog(/* kext */ NULL,
6222 kOSKextLogErrorLevel |
6223 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6224 "Could not instantiate codeless kext.");
6225 result = kOSKextReturnNotLoadable;
6226 goto finish;
6227 }
6228 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
6229 OSKextLog(/* kext */ NULL,
6230 kOSKextLogErrorLevel |
6231 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6232 "Codeless kext identifiers don't match '%s' != '%s'",
6233 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6234
6235 OSKext::removeKext(newKext.get(), false);
6236 result = kOSKextReturnInvalidArgument;
6237 goto finish;
6238 }
6239
6240 /* Record the request for the codeless kext */
6241 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6242
6243 result = kOSReturnSuccess;
6244 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6245 result = newKext->sendPersonalitiesToCatalog(true, NULL);
6246 }
6247
6248 finish:
6249 IORecursiveLockUnlock(sKextLock);
6250
6251 return result;
6252 }
6253
6254 /*********************************************************************
6255 *********************************************************************/
6256 /* static */
6257 void
dropMatchingReferences(OSSet * kexts)6258 OSKext::dropMatchingReferences(
6259 OSSet * kexts)
6260 {
6261 IORecursiveLockLock(sKextLock);
6262 kexts->iterateObjects(^bool (OSObject * obj) {
6263 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6264 if (!thisKext) {
6265 return false;
6266 }
6267 thisKext->matchingRefCount--;
6268 return false;
6269 });
6270 IORecursiveLockUnlock(sKextLock);
6271 }
6272
6273 /*********************************************************************
6274 *********************************************************************/
6275 /* static */
6276 void
recordIdentifierRequest(OSString * kextIdentifier)6277 OSKext::recordIdentifierRequest(
6278 OSString * kextIdentifier)
6279 {
6280 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6281 bool fail = false;
6282
6283 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6284 goto finish;
6285 }
6286
6287 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6288 if (!kextIdentifierSymbol) {
6289 // xxx - this is really a basic alloc failure
6290 fail = true;
6291 goto finish;
6292 }
6293
6294 IORecursiveLockLock(sKextLock);
6295 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6296 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6297 fail = true;
6298 } else {
6299 // xxx - need to find a way to associate this whole func w/the kext
6300 OSKextLog(/* kext */ NULL,
6301 // xxx - check level
6302 kOSKextLogStepLevel |
6303 kOSKextLogArchiveFlag,
6304 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6305 kextIdentifier->getCStringNoCopy());
6306 }
6307 }
6308 IORecursiveLockUnlock(sKextLock);
6309
6310 finish:
6311
6312 if (fail) {
6313 OSKextLog(/* kext */ NULL,
6314 kOSKextLogErrorLevel |
6315 kOSKextLogArchiveFlag,
6316 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6317 kextIdentifier->getCStringNoCopy());
6318 }
6319 return;
6320 }
6321
6322 /*********************************************************************
6323 *********************************************************************/
6324 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6325 OSKext::load(
6326 OSKextExcludeLevel startOpt,
6327 OSKextExcludeLevel startMatchingOpt,
6328 OSArray * personalityNames)
6329 {
6330 OSReturn result = kOSReturnError;
6331 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6332 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6333 unsigned int i, count;
6334 Boolean alreadyLoaded = false;
6335 OSKext * lastLoadedKext = NULL; // do not release
6336
6337 if (isInExcludeList()) {
6338 OSKextLog(this,
6339 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6340 kOSKextLogLoadFlag,
6341 "Kext %s is in exclude list, not loadable",
6342 getIdentifierCString());
6343
6344 result = kOSKextReturnNotLoadable;
6345 goto finish;
6346 }
6347 if (!isLoadable()) {
6348 OSKextLog(this,
6349 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6350 kOSKextLogLoadFlag,
6351 "Kext %s is not loadable",
6352 getIdentifierCString());
6353
6354 result = kOSKextReturnNotLoadable;
6355 goto finish;
6356 }
6357
6358 if (isLoaded()) {
6359 alreadyLoaded = true;
6360 result = kOSReturnSuccess;
6361
6362 OSKextLog(this,
6363 kOSKextLogDebugLevel |
6364 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6365 "Kext %s is already loaded.",
6366 getIdentifierCString());
6367 goto loaded;
6368 }
6369
6370 #if CONFIG_MACF
6371 /*
6372 * On kxld and on embedded, only call into the MAC hook when on a
6373 * user thread, for access control over userspace kextloads.
6374 *
6375 * On non-kxld systems, additionally check the MAC hook for kexts in
6376 * the Pageable and Aux KCs, regardless of whether we are on a user
6377 * thread or not. This means on Apple silicon devices that the MAC
6378 * hook will only be useful to block 3rd party kexts loaded via
6379 * matching, and any kexts loaded from userspace kextloads.
6380 *
6381 * Note that this should _not_ be called on kexts loaded from the
6382 * kernel bootstrap thread as the kernel proc's cred struct is not
6383 * yet initialized! This won't happen on macOS because all the kexts
6384 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6385 */
6386 if (current_task() != kernel_task
6387 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6388 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6389 #endif
6390 ) {
6391 int macCheckResult = 0;
6392 kauth_cred_t cred = NULL;
6393
6394 cred = kauth_cred_get_with_ref();
6395 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
6396 kauth_cred_unref(&cred);
6397
6398 if (macCheckResult != 0) {
6399 result = kOSReturnError;
6400 OSKextLog(this,
6401 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6402 "Failed to load kext %s (MAC policy error 0x%x).",
6403 getIdentifierCString(), macCheckResult);
6404 goto finish;
6405 }
6406 }
6407 #endif /* CONFIG_MACF */
6408
6409 if (!sLoadEnabled) {
6410 OSKextLog(this,
6411 kOSKextLogErrorLevel |
6412 kOSKextLogLoadFlag,
6413 "Kext loading is disabled (attempt to load kext %s).",
6414 getIdentifierCString());
6415 result = kOSKextReturnDisabled;
6416 goto finish;
6417 }
6418
6419 /* If we've pushed the next available load tag to the invalid value,
6420 * we can't load any more kexts.
6421 */
6422 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6423 OSKextLog(this,
6424 kOSKextLogErrorLevel |
6425 kOSKextLogLoadFlag,
6426 "Can't load kext %s - no more load tags to assign.",
6427 getIdentifierCString());
6428 result = kOSKextReturnNoResources;
6429 goto finish;
6430 }
6431
6432 /* This is a bit of a hack, because we shouldn't be handling
6433 * personalities within the load function.
6434 */
6435 if (!declaresExecutable()) {
6436 /* There is a special case where a non-executable kext can be loaded: the
6437 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6438 * load its metadata into the global data structures, if appropriate
6439 */
6440 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6441 boolean_t updated = updateExcludeList(infoDict.get());
6442 if (updated) {
6443 OSKextLog(this,
6444 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6445 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6446 }
6447 }
6448
6449 if (isDriverKit()) {
6450 if (loadTag == 0) {
6451 sLoadedDriverKitKexts->setObject(this);
6452 loadTag = sNextLoadTag++;
6453 }
6454 }
6455 result = kOSReturnSuccess;
6456 goto loaded;
6457 }
6458
6459 /* Are we in safe boot?
6460 */
6461 if (sSafeBoot && !isLoadableInSafeBoot()) {
6462 OSKextLog(this,
6463 kOSKextLogErrorLevel |
6464 kOSKextLogLoadFlag,
6465 "Can't load kext %s - not loadable during safe boot.",
6466 getIdentifierCString());
6467 result = kOSKextReturnBootLevel;
6468 goto finish;
6469 }
6470
6471 OSKextLog(this,
6472 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6473 "Loading kext %s.",
6474 getIdentifierCString());
6475
6476 #if !VM_MAPPED_KEXTS
6477 if (isPrelinked() == false) {
6478 OSKextLog(this,
6479 kOSKextLogErrorLevel |
6480 kOSKextLogLoadFlag,
6481 "Can't load kext %s - not in a kext collection.",
6482 getIdentifierCString());
6483 result = kOSKextReturnDisabled;
6484 goto finish;
6485 }
6486 #endif /* defined(__x86_64__) */
6487
6488 #if CONFIG_KXLD
6489 if (!sKxldContext) {
6490 kern_return_t kxldResult;
6491 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6492 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6493 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6494 if (kxldResult) {
6495 OSKextLog(this,
6496 kOSKextLogErrorLevel |
6497 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6498 "Can't load kext %s - failed to create link context.",
6499 getIdentifierCString());
6500 result = kOSKextReturnNoMemory;
6501 goto finish;
6502 }
6503 }
6504 #endif // CONFIG_KXLD
6505
6506 /* We only need to resolve dependencies once for the whole graph, but
6507 * resolveDependencies will just return if there's no work to do, so it's
6508 * safe to call it more than once.
6509 */
6510 if (!resolveDependencies()) {
6511 // xxx - check resolveDependencies() for log msg
6512 OSKextLog(this,
6513 kOSKextLogErrorLevel |
6514 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6515 "Can't load kext %s - failed to resolve library dependencies.",
6516 getIdentifierCString());
6517 result = kOSKextReturnDependencies;
6518 goto finish;
6519 }
6520
6521 /* If we are excluding just the kext being loaded now (and not its
6522 * dependencies), drop the exclusion level to none so dependencies
6523 * start and/or add their personalities.
6524 */
6525 if (dependenciesStartOpt == kOSKextExcludeKext) {
6526 dependenciesStartOpt = kOSKextExcludeNone;
6527 }
6528
6529 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6530 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6531 }
6532
6533 /* Load the dependencies, recursively.
6534 */
6535 count = getNumDependencies();
6536 for (i = 0; i < count; i++) {
6537 OSKext * dependency = OSDynamicCast(OSKext,
6538 dependencies->getObject(i));
6539 if (dependency == NULL) {
6540 OSKextLog(this,
6541 kOSKextLogErrorLevel |
6542 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6543 "Internal error loading kext %s; dependency disappeared.",
6544 getIdentifierCString());
6545 result = kOSKextReturnInternalError;
6546 goto finish;
6547 }
6548
6549 /* Dependencies must be started accorting to the opt,
6550 * but not given the personality names of the main kext.
6551 */
6552 result = dependency->load(dependenciesStartOpt,
6553 dependenciesStartMatchingOpt,
6554 /* personalityNames */ NULL);
6555 if (result != KERN_SUCCESS) {
6556 OSKextLog(this,
6557 kOSKextLogErrorLevel |
6558 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6559 "Dependency %s of kext %s failed to load.",
6560 dependency->getIdentifierCString(),
6561 getIdentifierCString());
6562
6563 OSKext::removeKext(dependency,
6564 /* terminateService/removePersonalities */ true);
6565 result = kOSKextReturnDependencyLoadError;
6566
6567 goto finish;
6568 }
6569 }
6570
6571 result = loadExecutable();
6572 if (result != KERN_SUCCESS) {
6573 goto finish;
6574 }
6575
6576 pendingPgoHead.next = &pendingPgoHead;
6577 pendingPgoHead.prev = &pendingPgoHead;
6578
6579 // The kernel PRNG is not initialized when the first kext is
6580 // loaded, so use early random
6581 uuid_generate_early_random(instance_uuid);
6582 account = IOMallocType(OSKextAccount);
6583
6584 account->loadTag = kmod_info->id;
6585 account->site.refcount = 0;
6586 account->site.flags = VM_TAG_KMOD;
6587
6588 #if DEVELOPMENT || DEBUG
6589 /* Setup the task reference group. */
6590 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6591 "task_%s", getIdentifierCString());
6592 account->task_refgrp.grp_name = account->task_refgrp_name;
6593 account->task_refgrp.grp_parent = &task_external_refgrp;
6594 account->task_refgrp.grp_flags = OS_REFGRP_F_ALWAYS_ENABLED;
6595 os_ref_log_init(&account->task_refgrp);
6596 #endif /* DEVELOPMENT || DEBUG */
6597
6598 account->kext = this;
6599 if (gIOSurfaceIdentifier == bundleID) {
6600 vm_tag_alloc(&account->site);
6601 gIOSurfaceTag = account->site.tag;
6602 }
6603
6604 flags.loaded = true;
6605
6606 /* Add the kext to the list of loaded kexts and update the kmod_info
6607 * struct to point to that of the last loaded kext (which is the way
6608 * it's always been done, though I'd rather do them in order now).
6609 */
6610 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6611 sLoadedKexts->setObject(this);
6612
6613 /* Keep the kernel itself out of the kmod list.
6614 */
6615 if (lastLoadedKext->isKernel()) {
6616 lastLoadedKext = NULL;
6617 }
6618
6619 if (lastLoadedKext) {
6620 kmod_info->next = lastLoadedKext->kmod_info;
6621 }
6622
6623 notifyKextLoadObservers(this, kmod_info);
6624
6625 /* Make the global kmod list point at the just-loaded kext. Note that the
6626 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6627 * although we do report it in kextstat these days by using the newer
6628 * OSArray of loaded kexts, which does contain it.
6629 *
6630 * (The OSKext object representing the kernel doesn't even have a kmod_info
6631 * struct, though I suppose we could stick a pointer to it from the
6632 * static struct in OSRuntime.cpp.)
6633 */
6634 kmod = kmod_info;
6635
6636 /* Save the list of loaded kexts in case we panic.
6637 */
6638 OSKext::saveLoadedKextPanicList();
6639
6640 if (isExecutable()) {
6641 OSKext::updateLoadedKextSummaries();
6642 savePanicString(/* isLoading */ true);
6643
6644 #if CONFIG_DTRACE
6645 registerWithDTrace();
6646 #else
6647 jettisonLinkeditSegment();
6648 #endif /* CONFIG_DTRACE */
6649
6650 #if !VM_MAPPED_KEXTS
6651 /* If there is a page (or more) worth of padding after the end
6652 * of the last data section but before the end of the data segment
6653 * then free it in the same manner the LinkeditSegment is freed
6654 */
6655 jettisonDATASegmentPadding();
6656 #endif
6657 }
6658
6659 loaded:
6660 if (isExecutable() && !flags.started) {
6661 if (startOpt == kOSKextExcludeNone) {
6662 result = start();
6663 if (result != kOSReturnSuccess) {
6664 OSKextLog(this,
6665 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6666 "Kext %s start failed (result 0x%x).",
6667 getIdentifierCString(), result);
6668 result = kOSKextReturnStartStopError;
6669 }
6670 }
6671 }
6672
6673 /* If not excluding matching, send the personalities to the kernel.
6674 * This never affects the result of the load operation.
6675 * This is a bit of a hack, because we shouldn't be handling
6676 * personalities within the load function.
6677 */
6678 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6679 result = sendPersonalitiesToCatalog(true, personalityNames);
6680 }
6681
6682 finish:
6683
6684 if (result != kOSReturnSuccess) {
6685 OSKextLog(this,
6686 kOSKextLogErrorLevel |
6687 kOSKextLogLoadFlag,
6688 "Kext %s failed to load (0x%x).",
6689 getIdentifierCString(), (int)result);
6690 } else if (!alreadyLoaded) {
6691 OSKextLog(this,
6692 kOSKextLogProgressLevel |
6693 kOSKextLogLoadFlag,
6694 "Kext %s loaded.",
6695 getIdentifierCString());
6696
6697 queueKextNotification(kKextRequestPredicateLoadNotification,
6698 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
6699 }
6700 return result;
6701 }
6702
6703 #if CONFIG_KXLD
6704 /*********************************************************************
6705 *
6706 *********************************************************************/
6707 static char *
strdup(const char * string)6708 strdup(const char * string)
6709 {
6710 char * result = NULL;
6711 size_t size;
6712
6713 if (!string) {
6714 goto finish;
6715 }
6716
6717 size = 1 + strlen(string);
6718 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6719 if (!result) {
6720 goto finish;
6721 }
6722
6723 memcpy(result, string, size);
6724
6725 finish:
6726 return result;
6727 }
6728 #endif // CONFIG_KXLD
6729
6730 /*********************************************************************
6731 *
6732 *********************************************************************/
6733
6734 kernel_section_t *
lookupSection(const char * segname,const char * secname)6735 OSKext::lookupSection(const char *segname, const char *secname)
6736 {
6737 kernel_section_t * found_section = NULL;
6738 kernel_mach_header_t * mh = NULL;
6739 kernel_segment_command_t * seg = NULL;
6740 kernel_section_t * sec = NULL;
6741
6742 if (!linkedExecutable) {
6743 return NULL;
6744 }
6745
6746 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6747
6748 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6749 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
6750 continue;
6751 }
6752
6753 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6754 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
6755 found_section = sec;
6756 goto out;
6757 }
6758 }
6759 }
6760
6761 out:
6762 return found_section;
6763 }
6764
6765 /*********************************************************************
6766 *
6767 *********************************************************************/
6768
6769 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6770 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6771 {
6772 OSReturn result = kOSKextReturnBadData;
6773 kernel_mach_header_t * mh = NULL;
6774 kernel_segment_command_t * seg = NULL;
6775 kernel_segment_command_t * linkeditSeg = NULL;
6776 kernel_section_t * sec = NULL;
6777 char * linkeditBase = NULL;
6778 bool haveLinkeditBase = false;
6779 char * relocBase = NULL;
6780 bool haveRelocBase = false;
6781 struct dysymtab_command * dysymtab = NULL;
6782 struct linkedit_data_command * segmentSplitInfo = NULL;
6783 struct symtab_command * symtab = NULL;
6784 kernel_nlist_t * sym = NULL;
6785 struct relocation_info * reloc = NULL;
6786 uint32_t i = 0;
6787 int reloc_size;
6788 vm_offset_t new_kextsize;
6789 kc_format format = KCFormatUnknown;
6790
6791 if (linkedExecutable == NULL || flags.builtin) {
6792 result = kOSReturnSuccess;
6793 goto finish;
6794 }
6795
6796 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6797 if (kernel_mach_header_is_in_fileset(mh)) {
6798 // kexts in filesets are slid as part of collection sliding
6799 result = kOSReturnSuccess;
6800 goto finish;
6801 }
6802
6803 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6804
6805 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6806 if (!seg->vmaddr) {
6807 continue;
6808 }
6809
6810 seg->vmaddr = ml_static_slide(seg->vmaddr);
6811
6812 #if KASLR_KEXT_DEBUG
6813 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6814 seg->segname,
6815 (unsigned long)ml_static_unslide(seg->vmaddr),
6816 (unsigned long)seg->vmaddr);
6817 #endif
6818
6819 if (!haveRelocBase) {
6820 relocBase = (char *) seg->vmaddr;
6821 haveRelocBase = true;
6822 }
6823 if (!strcmp(seg->segname, "__LINKEDIT")) {
6824 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6825 haveLinkeditBase = true;
6826 linkeditSeg = seg;
6827 }
6828 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6829 sec->addr = ml_static_slide(sec->addr);
6830
6831 #if KASLR_KEXT_DEBUG
6832 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6833 sec->sectname,
6834 (unsigned long)ml_static_unslide(sec->addr),
6835 (unsigned long)sec->addr);
6836 #endif
6837 }
6838 }
6839
6840 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6841
6842 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6843
6844 if (symtab != NULL && doCoalescedSlides == false) {
6845 /* Some pseudo-kexts have symbol tables without segments.
6846 * Ignore them. */
6847 if (symtab->nsyms > 0 && haveLinkeditBase) {
6848 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6849 for (i = 0; i < symtab->nsyms; i++) {
6850 if (sym[i].n_type & N_STAB) {
6851 continue;
6852 }
6853 sym[i].n_value = ml_static_slide(sym[i].n_value);
6854
6855 #if KASLR_KEXT_DEBUG
6856 #define MAX_SYMS_TO_LOG 5
6857 if (i < MAX_SYMS_TO_LOG) {
6858 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6859 (unsigned long)ml_static_unslide(sym[i].n_value),
6860 (unsigned long)sym[i].n_value);
6861 }
6862 #endif
6863 }
6864 }
6865 }
6866
6867 if (dysymtab != NULL && doCoalescedSlides == false) {
6868 if (dysymtab->nextrel > 0) {
6869 OSKextLog(this,
6870 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6871 kOSKextLogLinkFlag,
6872 "Sliding kext %s: External relocations found.",
6873 getIdentifierCString());
6874 goto finish;
6875 }
6876
6877 if (dysymtab->nlocrel > 0) {
6878 if (!haveLinkeditBase) {
6879 OSKextLog(this,
6880 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6881 kOSKextLogLinkFlag,
6882 "Sliding kext %s: No linkedit segment.",
6883 getIdentifierCString());
6884 goto finish;
6885 }
6886
6887 if (!haveRelocBase) {
6888 OSKextLog(this,
6889 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6890 kOSKextLogLinkFlag,
6891 #if __x86_64__
6892 "Sliding kext %s: No writable segments.",
6893 #else
6894 "Sliding kext %s: No segments.",
6895 #endif
6896 getIdentifierCString());
6897 goto finish;
6898 }
6899
6900 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6901 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6902
6903 for (i = 0; i < dysymtab->nlocrel; i++) {
6904 if (reloc[i].r_extern != 0
6905 || reloc[i].r_type != 0
6906 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6907 ) {
6908 OSKextLog(this,
6909 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6910 kOSKextLogLinkFlag,
6911 "Sliding kext %s: Unexpected relocation found.",
6912 getIdentifierCString());
6913 goto finish;
6914 }
6915 if (reloc[i].r_pcrel != 0) {
6916 continue;
6917 }
6918 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6919 *relocAddr = ml_static_slide(*relocAddr);
6920
6921 #if KASLR_KEXT_DEBUG
6922 #define MAX_DYSYMS_TO_LOG 5
6923 if (i < MAX_DYSYMS_TO_LOG) {
6924 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6925 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6926 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6927 }
6928 #endif
6929 }
6930
6931 /* We should free these relocations, not just delete the reference to them.
6932 * <rdar://problem/10535549> Free relocations from PIE kexts.
6933 *
6934 * For now, we do not free LINKEDIT for kexts with split segments.
6935 */
6936 new_kextsize = round_page(kmod_info->size - reloc_size);
6937 if (new_kextsize > UINT_MAX) {
6938 OSKextLog(this,
6939 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6940 kOSKextLogLinkFlag,
6941 "Kext %s: new kext size is too large.",
6942 getIdentifierCString());
6943 goto finish;
6944 }
6945 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6946 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6947 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6948 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6949 size_t bytes_remaining = endofkext - endofrelocInfo;
6950 OSSharedPtr<OSData> new_osdata;
6951
6952 /* fix up symbol offsets if they are after the dsymtab local relocs */
6953 if (symtab) {
6954 if (dysymtab->locreloff < symtab->symoff) {
6955 symtab->symoff -= reloc_size;
6956 }
6957 if (dysymtab->locreloff < symtab->stroff) {
6958 symtab->stroff -= reloc_size;
6959 }
6960 }
6961 if (dysymtab->locreloff < dysymtab->extreloff) {
6962 dysymtab->extreloff -= reloc_size;
6963 }
6964
6965 /* move data behind reloc info down to new offset */
6966 if (endofrelocInfo < endofkext) {
6967 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6968 }
6969
6970 /* Create a new OSData for the smaller kext object and reflect
6971 * new linkedit segment size.
6972 */
6973 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6974 linkeditSeg->filesize = linkeditSeg->vmsize;
6975
6976 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6977 if (new_osdata) {
6978 /* Fix up kmod info and linkedExecutable.
6979 */
6980 kmod_info->size = new_kextsize;
6981 /*
6982 * Fileset KCs are mapped as a whole by iBoot.
6983 * Individual kext executables should not be unmapped
6984 * by xnu.
6985 * Doing so may result in panics like rdar://85419651
6986 */
6987 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
6988 new_osdata->setDeallocFunction(NULL);
6989 } else { // Not from a Fileset KC
6990 #if VM_MAPPED_KEXTS
6991 new_osdata->setDeallocFunction(osdata_kext_free);
6992 #else
6993 new_osdata->setDeallocFunction(osdata_phys_free);
6994 #endif
6995 }
6996 linkedExecutable->setDeallocFunction(NULL);
6997 linkedExecutable = os::move(new_osdata);
6998
6999 #if VM_MAPPED_KEXTS
7000 kext_free(new_endofkext, (endofkext - new_endofkext));
7001 #else
7002 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
7003 #endif
7004 }
7005 }
7006 dysymtab->nlocrel = 0;
7007 dysymtab->locreloff = 0;
7008 }
7009 }
7010
7011 result = kOSReturnSuccess;
7012 finish:
7013 return result;
7014 }
7015
7016 /*********************************************************************
7017 * called only by load()
7018 *********************************************************************/
7019 OSReturn
loadExecutable()7020 OSKext::loadExecutable()
7021 {
7022 OSReturn result = kOSReturnError;
7023 OSSharedPtr<OSArray> linkDependencies;
7024 uint32_t num_kmod_refs = 0;
7025 OSData * theExecutable = NULL; // do not release
7026 OSString * versString = NULL; // do not release
7027 const char * versCString = NULL; // do not free
7028 const char * string = NULL; // do not free
7029
7030 #if CONFIG_KXLD
7031 unsigned int i;
7032 uint32_t numDirectDependencies = 0;
7033 kern_return_t kxldResult;
7034 KXLDDependency * kxlddeps = NULL; // must kfree
7035 uint32_t num_kxlddeps = 0;
7036 struct mach_header ** kxldHeaderPtr = NULL; // do not free
7037 struct mach_header * kxld_header = NULL; // xxx - need to free here?
7038 #endif // CONFIG_KXLD
7039
7040 /* We need the version string for a variety of bits below.
7041 */
7042 versString = OSDynamicCast(OSString,
7043 getPropertyForHostArch(kCFBundleVersionKey));
7044 if (!versString) {
7045 goto finish;
7046 }
7047 versCString = versString->getCStringNoCopy();
7048
7049 if (isKernelComponent()) {
7050 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
7051 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
7052 OSKextLog(this,
7053 kOSKextLogErrorLevel |
7054 kOSKextLogLoadFlag,
7055 "Kernel component %s has incorrect version %s; "
7056 "expected %s.",
7057 getIdentifierCString(),
7058 versCString, KERNEL6_VERSION);
7059 result = kOSKextReturnInternalError;
7060 goto finish;
7061 } else if (strcmp(versCString, osrelease)) {
7062 OSKextLog(this,
7063 kOSKextLogErrorLevel |
7064 kOSKextLogLoadFlag,
7065 "Kernel component %s has incorrect version %s; "
7066 "expected %s.",
7067 getIdentifierCString(),
7068 versCString, osrelease);
7069 result = kOSKextReturnInternalError;
7070 goto finish;
7071 }
7072 }
7073 }
7074
7075 #if defined(__x86_64__) || defined(__i386__)
7076 if (flags.resetSegmentsFromVnode) {
7077 /* Fixup the chains and slide the mach headers */
7078 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
7079
7080 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
7081 result = kOSKextReturnValidation;
7082 goto finish;
7083 }
7084 }
7085 #endif //(__x86_64__) || defined(__i386__)
7086
7087 if (isPrelinked()) {
7088 goto register_kmod;
7089 }
7090
7091 /* <rdar://problem/21444003> all callers must be entitled */
7092 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7093 OSKextLog(this,
7094 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7095 "Not entitled to link kext '%s'",
7096 getIdentifierCString());
7097 result = kOSKextReturnNotPrivileged;
7098 goto finish;
7099 }
7100
7101 theExecutable = getExecutable();
7102 if (!theExecutable) {
7103 if (declaresExecutable()) {
7104 OSKextLog(this,
7105 kOSKextLogErrorLevel |
7106 kOSKextLogLoadFlag,
7107 "Can't load kext %s - executable is missing.",
7108 getIdentifierCString());
7109 result = kOSKextReturnValidation;
7110 goto finish;
7111 }
7112 goto register_kmod;
7113 }
7114
7115 if (isInterface()) {
7116 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
7117 if (executableCopy) {
7118 setLinkedExecutable(executableCopy.get());
7119 }
7120 goto register_kmod;
7121 }
7122
7123 #if CONFIG_KXLD
7124 numDirectDependencies = getNumDependencies();
7125
7126 if (flags.hasBleedthrough) {
7127 linkDependencies = dependencies;
7128 } else {
7129 linkDependencies = OSArray::withArray(dependencies.get());
7130 if (!linkDependencies) {
7131 OSKextLog(this,
7132 kOSKextLogErrorLevel |
7133 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7134 "Can't allocate link dependencies to load kext %s.",
7135 getIdentifierCString());
7136 goto finish;
7137 }
7138
7139 for (i = 0; i < numDirectDependencies; ++i) {
7140 OSKext * dependencyKext = OSDynamicCast(OSKext,
7141 dependencies->getObject(i));
7142 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7143 }
7144 }
7145
7146 num_kxlddeps = linkDependencies->getCount();
7147 if (!num_kxlddeps) {
7148 OSKextLog(this,
7149 kOSKextLogErrorLevel |
7150 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7151 "Can't load kext %s - it has no library dependencies.",
7152 getIdentifierCString());
7153 goto finish;
7154 }
7155
7156 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7157 if (!kxlddeps) {
7158 OSKextLog(this,
7159 kOSKextLogErrorLevel |
7160 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7161 "Can't allocate link context to load kext %s.",
7162 getIdentifierCString());
7163 goto finish;
7164 }
7165 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7166
7167 for (i = 0; i < num_kxlddeps; ++i) {
7168 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7169
7170 if (dependency->isInterface()) {
7171 OSKext *interfaceTargetKext = NULL; //do not release
7172 OSData * interfaceTarget = NULL; //do not release
7173
7174 if (dependency->isKernelComponent()) {
7175 interfaceTargetKext = sKernelKext;
7176 interfaceTarget = sKernelKext->linkedExecutable.get();
7177 } else {
7178 interfaceTargetKext = OSDynamicCast(OSKext,
7179 dependency->dependencies->getObject(0));
7180
7181 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7182 }
7183
7184 if (!interfaceTarget) {
7185 // panic?
7186 goto finish;
7187 }
7188
7189 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7190 * it will be useful to have them in the debugger.
7191 * strdup() failing isn't critical right here so we don't check that.
7192 */
7193 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7194 kxlddeps[i].kext_size = interfaceTarget->getLength();
7195 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7196
7197 if (dependency->linkedExecutable != NULL) {
7198 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7199 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7200 } else {
7201 kxlddeps[i].interface = (u_char *) NULL;
7202 kxlddeps[i].interface_size = 0;
7203 }
7204 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7205 } else {
7206 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7207 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7208 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7209 }
7210
7211 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7212 }
7213
7214 kxldHeaderPtr = &kxld_header;
7215
7216 #if DEBUG
7217 OSKextLog(this,
7218 kOSKextLogExplicitLevel |
7219 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7220 "Kext %s - calling kxld_link_file:\n"
7221 " kxld_context: %p\n"
7222 " executable: %p executable_length: %d\n"
7223 " user_data: %p\n"
7224 " kxld_dependencies: %p num_dependencies: %d\n"
7225 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7226 getIdentifierCString(), sKxldContext,
7227 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7228 this, kxlddeps, num_kxlddeps,
7229 kxldHeaderPtr, &kmod_info);
7230 #endif
7231
7232 /* After this call, the linkedExecutable instance variable
7233 * should exist.
7234 */
7235 kxldResult = kxld_link_file(sKxldContext,
7236 (u_char *)theExecutable->getBytesNoCopy(),
7237 theExecutable->getLength(),
7238 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7239 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7240
7241 if (kxldResult != KERN_SUCCESS) {
7242 // xxx - add kxldResult here?
7243 OSKextLog(this,
7244 kOSKextLogErrorLevel |
7245 kOSKextLogLoadFlag,
7246 "Can't load kext %s - link failed.",
7247 getIdentifierCString());
7248 result = kOSKextReturnLinkError;
7249 goto finish;
7250 }
7251
7252 /* We've written data & instructions into kernel memory, so flush the data
7253 * cache and invalidate the instruction cache.
7254 * I/D caches are coherent on x86
7255 */
7256 #if !defined(__i386__) && !defined(__x86_64__)
7257 flush_dcache(kmod_info->address, kmod_info->size, false);
7258 invalidate_icache(kmod_info->address, kmod_info->size, false);
7259 #endif
7260
7261 #else // !CONFIG_KXLD
7262 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7263 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7264 result = kOSKextReturnLinkError;
7265 goto finish;
7266 #endif // CONFIG_KXLD
7267
7268 register_kmod:
7269
7270 if (isInterface()) {
7271 /* Whip up a fake kmod_info entry for the interface kext.
7272 */
7273 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7274 if (!kmod_info) {
7275 result = KERN_MEMORY_ERROR;
7276 goto finish;
7277 }
7278
7279 /* A pseudokext has almost nothing in its kmod_info struct.
7280 */
7281 kmod_info->info_version = KMOD_INFO_VERSION;
7282
7283 /* An interface kext doesn't have a linkedExecutable, so save a
7284 * copy of the UUID out of the original executable via copyUUID()
7285 * while we still have the original executable.
7286 */
7287 interfaceUUID = copyUUID();
7288 }
7289
7290 kmod_info->id = loadTag = sNextLoadTag++;
7291 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7292
7293 /* Stamp the bundle ID and version from the OSKext over anything
7294 * resident inside the kmod_info.
7295 */
7296 string = getIdentifierCString();
7297 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
7298
7299 string = versCString;
7300 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
7301
7302 /* Add the dependencies' kmod_info structs as kmod_references.
7303 */
7304 num_kmod_refs = getNumDependencies();
7305 if (num_kmod_refs) {
7306 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7307 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7308 if (!kmod_info->reference_list) {
7309 result = KERN_MEMORY_ERROR;
7310 goto finish;
7311 }
7312 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7313 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7314 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7315 ref->info = refKext->kmod_info;
7316 ref->info->reference_count++;
7317
7318 if (refIndex + 1 < num_kmod_refs) {
7319 ref->next = kmod_info->reference_list + refIndex + 1;
7320 }
7321 }
7322 }
7323
7324 if (kmod_info->hdr_size > UINT32_MAX) {
7325 OSKextLog(this,
7326 kOSKextLogErrorLevel |
7327 kOSKextLogLoadFlag,
7328 #if __LP64__
7329 "Kext %s header size is too large (%lu > UINT32_MAX).",
7330 #else
7331 "Kext %s header size is too large (%u > UINT32_MAX).",
7332 #endif
7333 kmod_info->name,
7334 kmod_info->hdr_size);
7335 result = KERN_FAILURE;
7336 goto finish;
7337 }
7338
7339 if (kmod_info->size > UINT32_MAX) {
7340 OSKextLog(this,
7341 kOSKextLogErrorLevel |
7342 kOSKextLogLoadFlag,
7343 #if __LP64__
7344 "Kext %s size is too large (%lu > UINT32_MAX).",
7345 #else
7346 "Kext %s size is too large (%u > UINT32_MAX).",
7347 #endif
7348 kmod_info->name,
7349 kmod_info->size);
7350 result = KERN_FAILURE;
7351 goto finish;
7352 }
7353
7354 if (!isInterface() && linkedExecutable) {
7355 OSKextLog(this,
7356 kOSKextLogProgressLevel |
7357 kOSKextLogLoadFlag,
7358 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7359 kmod_info->name,
7360 (unsigned)kmod_info->size / PAGE_SIZE,
7361 (unsigned long)ml_static_unslide(kmod_info->address),
7362 (unsigned)kmod_info->id);
7363 }
7364
7365 /* VM protections and wiring for the Aux KC are done at collection loading time */
7366 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7367 /* if prelinked and primary KC, VM protections are already set */
7368 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
7369 if (result != KERN_SUCCESS) {
7370 goto finish;
7371 }
7372 }
7373
7374 #if KASAN
7375 if (linkedExecutable) {
7376 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7377 linkedExecutable->getLength(), getIdentifierCString());
7378 }
7379 #else
7380 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7381 OSKextLog(this,
7382 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7383 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7384 getIdentifierCString()
7385 );
7386 result = KERN_FAILURE;
7387 goto finish;
7388 }
7389 #endif
7390
7391 result = kOSReturnSuccess;
7392
7393 finish:
7394
7395 #if CONFIG_KXLD
7396 /* Clear up locally allocated dependency info.
7397 */
7398 for (i = 0; i < num_kxlddeps; ++i) {
7399 size_t size;
7400
7401 if (kxlddeps[i].kext_name) {
7402 size = 1 + strlen(kxlddeps[i].kext_name);
7403 kfree_data(kxlddeps[i].kext_name, size);
7404 }
7405 if (kxlddeps[i].interface_name) {
7406 size = 1 + strlen(kxlddeps[i].interface_name);
7407 kfree_data(kxlddeps[i].interface_name, size);
7408 }
7409 }
7410 if (kxlddeps) {
7411 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7412 }
7413 #endif // CONFIG_KXLD
7414
7415 /* We no longer need the unrelocated executable (which the linker
7416 * has altered anyhow).
7417 */
7418 setExecutable(NULL);
7419
7420 if (result != kOSReturnSuccess) {
7421 OSKextLog(this,
7422 kOSKextLogErrorLevel |
7423 kOSKextLogLoadFlag,
7424 "Failed to load executable for kext %s.",
7425 getIdentifierCString());
7426
7427 if (kmod_info && kmod_info->reference_list) {
7428 kfree_type(kmod_reference_t, num_kmod_refs,
7429 kmod_info->reference_list);
7430 }
7431 if (isInterface()) {
7432 kfree_type(kmod_info_t, kmod_info);
7433 kmod_info = NULL;
7434 }
7435 if (kc_type == KCKindUnknown) {
7436 kmod_info = NULL;
7437 if (linkedExecutable) {
7438 linkedExecutable.reset();
7439 }
7440 }
7441 }
7442
7443 return result;
7444 }
7445
7446 /* static */
7447 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)7448 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7449 {
7450 kernel_segment_command_t *linkeditseg = NULL;
7451
7452 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
7453 if (linkeditseg == NULL) {
7454 panic("FileSet booted with no Linkedit segment");
7455 }
7456
7457 #if VM_MAPPED_KEXTS
7458 /* BootKC on x86_64 is not vm mapped */
7459 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7460
7461 OSKextLog(/* kext */ NULL,
7462 kOSKextLogProgressLevel |
7463 kOSKextLogGeneralFlag,
7464 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7465 linkeditseg->vmaddr, linkeditseg->vmsize);
7466 #else
7467 /* BootKC on arm64 is not vm mapped, but is slid */
7468 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7469
7470 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7471
7472 OSKextLog(/* kext */ NULL,
7473 kOSKextLogProgressLevel |
7474 kOSKextLogGeneralFlag,
7475 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7476 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7477 #endif /* VM_MAPPED_KEXTS */
7478 }
7479
7480 /*********************************************************************
7481 * The linkedit segment is used by the kext linker for dependency
7482 * resolution, and by dtrace for probe initialization. We can free it
7483 * for non-library kexts, since no kexts depend on non-library kexts
7484 * by definition, once dtrace has been initialized.
7485 *********************************************************************/
7486 void
jettisonLinkeditSegment(void)7487 OSKext::jettisonLinkeditSegment(void)
7488 {
7489 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7490 kernel_segment_command_t * linkedit = NULL;
7491 vm_offset_t start;
7492 vm_size_t linkeditsize, kextsize;
7493 OSSharedPtr<OSData> data;
7494 kc_format format = KCFormatUnknown;
7495
7496 if (isInFileset()) {
7497 return;
7498 }
7499
7500 #if NO_KEXTD
7501 /* We can free symbol tables for all embedded kexts because we don't
7502 * support runtime kext linking.
7503 */
7504 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7505 #else
7506 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7507 #endif
7508 goto finish;
7509 }
7510
7511 /* Find the linkedit segment. If it's not the last segment, then freeing
7512 * it will fragment the kext into multiple VM regions, which OSKext is not
7513 * designed to handle, so we'll have to skip it.
7514 */
7515 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
7516 if (!linkedit) {
7517 goto finish;
7518 }
7519
7520 if (round_page(kmod_info->address + kmod_info->size) !=
7521 round_page(linkedit->vmaddr + linkedit->vmsize)) {
7522 goto finish;
7523 }
7524
7525 /* Create a new OSData for the smaller kext object.
7526 */
7527 linkeditsize = round_page(linkedit->vmsize);
7528 kextsize = kmod_info->size - linkeditsize;
7529 start = linkedit->vmaddr;
7530
7531 if (kextsize > UINT_MAX) {
7532 goto finish;
7533 }
7534 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
7535 if (!data) {
7536 goto finish;
7537 }
7538
7539 /* Fix the kmod info and linkedExecutable.
7540 */
7541 kmod_info->size = kextsize;
7542
7543 /*
7544 * Fileset KCs are mapped as a whole by iBoot.
7545 * Individual kext executables should not be unmapped by xnu
7546 * Doing so may result in panics like rdar://85419651
7547 */
7548 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7549 data->setDeallocFunction(NULL);
7550 } else { // Not from a Fileset KC
7551 #if VM_MAPPED_KEXTS
7552 data->setDeallocFunction(osdata_kext_free);
7553 #else
7554 data->setDeallocFunction(osdata_phys_free);
7555 #endif
7556 }
7557 linkedExecutable->setDeallocFunction(NULL);
7558 linkedExecutable = os::move(data);
7559 flags.jettisonLinkeditSeg = 1;
7560
7561 /* Free the linkedit segment.
7562 */
7563 #if VM_MAPPED_KEXTS
7564 kext_free(start, linkeditsize);
7565 #else
7566 ml_static_mfree(start, linkeditsize);
7567 #endif
7568
7569 finish:
7570 return;
7571 }
7572
7573 /*********************************************************************
7574 * If there are whole pages that are unused betweem the last section
7575 * of the DATA segment and the end of the DATA segment then we can free
7576 * them
7577 *********************************************************************/
7578 void
7579 OSKext::jettisonDATASegmentPadding(void)
7580 {
7581 kernel_mach_header_t * mh;
7582 kernel_segment_command_t * dataSeg;
7583 kernel_section_t * sec, * lastSec;
7584 vm_offset_t dataSegEnd, lastSecEnd;
7585 vm_size_t padSize;
7586
7587 if (flags.builtin) {
7588 return;
7589 }
7590 mh = (kernel_mach_header_t *)kmod_info->address;
7591
7592 if (isInFileset()) {
7593 return;
7594 }
7595
7596 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
7597 if (dataSeg == NULL) {
7598 return;
7599 }
7600
7601 lastSec = NULL;
7602 sec = firstsect(dataSeg);
7603 while (sec != NULL) {
7604 lastSec = sec;
7605 sec = nextsect(dataSeg, sec);
7606 }
7607
7608 if (lastSec == NULL) {
7609 return;
7610 }
7611
7612 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
7613 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
7614 return;
7615 }
7616
7617 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7618 lastSecEnd = round_page(lastSec->addr + lastSec->size);
7619
7620 if (dataSegEnd <= lastSecEnd) {
7621 return;
7622 }
7623
7624 padSize = dataSegEnd - lastSecEnd;
7625
7626 if (padSize >= PAGE_SIZE) {
7627 #if VM_MAPPED_KEXTS
7628 kext_free(lastSecEnd, padSize);
7629 #else
7630 ml_static_mfree(lastSecEnd, padSize);
7631 #endif
7632 }
7633 }
7634
7635 /*********************************************************************
7636 *********************************************************************/
7637 void
7638 OSKext::setLinkedExecutable(OSData * anExecutable)
7639 {
7640 if (linkedExecutable) {
7641 panic("Attempt to set linked executable on kext "
7642 "that already has one (%s).\n",
7643 getIdentifierCString());
7644 }
7645 linkedExecutable.reset(anExecutable, OSRetain);
7646 return;
7647 }
7648
7649 #if CONFIG_DTRACE
7650 /*********************************************************************
7651 * Go through all loaded kexts and tell them to register with dtrace.
7652 * The instance method only registers if necessary.
7653 *********************************************************************/
7654 /* static */
7655 void
7656 OSKext::registerKextsWithDTrace(void)
7657 {
7658 uint32_t count = sLoadedKexts->getCount();
7659 uint32_t i;
7660
7661 IORecursiveLockLock(sKextLock);
7662
7663 for (i = 0; i < count; i++) {
7664 OSKext * thisKext = NULL; // do not release
7665
7666 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7667 if (!thisKext || !thisKext->isExecutable()) {
7668 continue;
7669 }
7670
7671 thisKext->registerWithDTrace();
7672 }
7673
7674 IORecursiveLockUnlock(sKextLock);
7675
7676 return;
7677 }
7678
7679 extern "C" {
7680 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7681 extern int (*dtrace_modunload)(struct kmod_info *);
7682 };
7683
7684 /*********************************************************************
7685 *********************************************************************/
7686 void
7687 OSKext::registerWithDTrace(void)
7688 {
7689 /* Register kext with dtrace. A dtrace_modload failure should not
7690 * prevent a kext from loading, so we ignore the return code.
7691 */
7692 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7693 uint32_t modflag = 0;
7694 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
7695
7696 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7697 if (forceInit == kOSBooleanTrue) {
7698 OSKextLog(this,
7699 kOSKextLogBasicLevel |
7700 kOSKextLogGeneralFlag,
7701 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7702 getIdentifierCString());
7703 forceInit = kOSBooleanFalse;
7704 }
7705 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7706 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7707 }
7708
7709 if (forceInit == kOSBooleanTrue) {
7710 modflag |= KMOD_DTRACE_FORCE_INIT;
7711 }
7712 if (flags.builtin) {
7713 modflag |= KMOD_DTRACE_STATIC_KEXT;
7714 }
7715
7716 (void)(*dtrace_modload)(kmod_info, modflag);
7717 flags.dtraceInitialized = true;
7718 jettisonLinkeditSegment();
7719 }
7720 return;
7721 }
7722 /*********************************************************************
7723 *********************************************************************/
7724 void
7725 OSKext::unregisterWithDTrace(void)
7726 {
7727 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7728 * prevent a kext from loading, so we ignore the return code.
7729 */
7730 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7731 (void)(*dtrace_modunload)(kmod_info);
7732 flags.dtraceInitialized = false;
7733 }
7734 return;
7735 }
7736 #endif /* CONFIG_DTRACE */
7737
7738
7739 /*********************************************************************
7740 * called only by loadExecutable()
7741 *********************************************************************/
7742 #if !VM_MAPPED_KEXTS
7743 #if defined(__arm__) || defined(__arm64__)
7744 static inline kern_return_t
7745 OSKext_protect(
7746 kernel_mach_header_t *kext_mh,
7747 vm_map_t map,
7748 vm_map_offset_t start,
7749 vm_map_offset_t end,
7750 vm_prot_t new_prot,
7751 boolean_t set_max,
7752 kc_kind_t kc_type)
7753 {
7754 #pragma unused(kext_mh,map,kc_type)
7755 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7756 assert(start <= end);
7757 if (start >= end) {
7758 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7759 } else if (set_max) {
7760 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7761 } else {
7762 return ml_static_protect(start, end - start, new_prot);
7763 }
7764 }
7765
7766 static inline kern_return_t
7767 OSKext_wire(
7768 kernel_mach_header_t *kext_mh,
7769 vm_map_t map,
7770 vm_map_offset_t start,
7771 vm_map_offset_t end,
7772 vm_prot_t access_type,
7773 boolean_t user_wire,
7774 kc_kind_t kc_type)
7775 {
7776 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7777 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7778 }
7779 #else
7780 #error Unrecognized architecture
7781 #endif
7782 #else
7783 static inline kern_return_t
7784 OSKext_protect(
7785 kernel_mach_header_t *kext_mh,
7786 vm_map_t map,
7787 vm_map_offset_t start,
7788 vm_map_offset_t end,
7789 vm_prot_t new_prot,
7790 boolean_t set_max,
7791 kc_kind_t kc_type)
7792 {
7793 if (start == end) { // 10538581
7794 return KERN_SUCCESS;
7795 }
7796 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7797 /*
7798 * XXX: This will probably need to be different for AuxKC and
7799 * pageableKC!
7800 */
7801 return ml_static_protect(start, end - start, new_prot);
7802 }
7803 return vm_map_protect(map, start, end, new_prot, set_max);
7804 }
7805
7806 static inline kern_return_t
7807 OSKext_wire(
7808 kernel_mach_header_t *kext_mh,
7809 vm_map_t map,
7810 vm_map_offset_t start,
7811 vm_map_offset_t end,
7812 vm_prot_t access_type,
7813 boolean_t user_wire,
7814 kc_kind_t kc_type)
7815 {
7816 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7817 /* TODO: we may need to hook this for the pageableKC */
7818 return KERN_SUCCESS;
7819 }
7820 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7821 }
7822 #endif
7823
7824 OSReturn
7825 OSKext::setVMAttributes(bool protect, bool wire)
7826 {
7827 vm_map_t kext_map = NULL;
7828 kernel_segment_command_t * seg = NULL;
7829 vm_map_offset_t start_protect = 0;
7830 vm_map_offset_t start_wire = 0;
7831 vm_map_offset_t end_protect = 0;
7832 vm_map_offset_t end_wire = 0;
7833 OSReturn result = kOSReturnError;
7834
7835 if (isInterface() || !declaresExecutable() || flags.builtin) {
7836 result = kOSReturnSuccess;
7837 goto finish;
7838 }
7839
7840 /* Get the kext's vm map */
7841 kext_map = kext_get_vm_map(kmod_info);
7842 if (!kext_map) {
7843 result = KERN_MEMORY_ERROR;
7844 goto finish;
7845 }
7846
7847 #if !VM_MAPPED_KEXTS
7848 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7849 /* This is a split kext in a prelinked kernelcache; we'll let the
7850 * platform code take care of protecting it. It is already wired.
7851 */
7852 /* TODO: Should this still allow protections for the first segment
7853 * to go through, in the event that we have a mix of split and
7854 * unsplit kexts?
7855 */
7856 result = KERN_SUCCESS;
7857 goto finish;
7858 }
7859
7860 if (isInFileset() && kc_type != KCKindPageable) {
7861 // kexts in filesets have protections setup as part of collection loading
7862 result = KERN_SUCCESS;
7863 goto finish;
7864 }
7865 #endif
7866
7867 /* Protect the headers as read-only; they do not need to be wired */
7868 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7869 kext_map, kmod_info->address,
7870 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7871 : KERN_SUCCESS;
7872 if (result != KERN_SUCCESS) {
7873 goto finish;
7874 }
7875
7876 /* Set the VM protections and wire down each of the segments */
7877 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7878 while (seg) {
7879 #if __arm__
7880 /* We build all ARM kexts, so we can ensure they are aligned */
7881 assert((seg->vmaddr & PAGE_MASK) == 0);
7882 assert((seg->vmsize & PAGE_MASK) == 0);
7883 #endif
7884
7885 /*
7886 * For the non page aligned segments, the range calculation for protection
7887 * and wiring differ as follows:
7888 *
7889 * Protection: The non page aligned data at the start or at the end of the
7890 * segment is excluded from the protection. This exclusion is needed to make
7891 * sure OSKext_protect is not called twice on same page, if the page is shared
7892 * between two segments.
7893 *
7894 * Wiring: The non page aligned data at the start or at the end of the
7895 * segment is included in the wiring range, this inclusion is needed to make sure
7896 * all the data of the segment is wired.
7897 */
7898 start_protect = round_page(seg->vmaddr);
7899 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7900
7901 start_wire = trunc_page(seg->vmaddr);
7902 end_wire = round_page(seg->vmaddr + seg->vmsize);
7903
7904 /*
7905 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7906 * across kexts and data from kexts is not page aligned
7907 */
7908 if (protect && (end_protect > start_protect) &&
7909 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7910 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7911 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7912 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7913 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7914 if (result != KERN_SUCCESS) {
7915 OSKextLog(this,
7916 kOSKextLogErrorLevel |
7917 kOSKextLogLoadFlag,
7918 "Kext %s failed to set maximum VM protections "
7919 "for segment %s - 0x%x.",
7920 getIdentifierCString(), seg->segname, (int)result);
7921 goto finish;
7922 }
7923
7924 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7925 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7926 if (result != KERN_SUCCESS) {
7927 OSKextLog(this,
7928 kOSKextLogErrorLevel |
7929 kOSKextLogLoadFlag,
7930 "Kext %s failed to set initial VM protections "
7931 "for segment %s - 0x%x.",
7932 getIdentifierCString(), seg->segname, (int)result);
7933 goto finish;
7934 }
7935 }
7936
7937 if (segmentShouldBeWired(seg) && wire) {
7938 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7939 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7940 if (result != KERN_SUCCESS) {
7941 goto finish;
7942 }
7943 }
7944
7945 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7946 }
7947
7948 finish:
7949 return result;
7950 }
7951
7952 /*********************************************************************
7953 *********************************************************************/
7954 boolean_t
7955 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7956 {
7957 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7958 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7959 }
7960
7961 /*********************************************************************
7962 *********************************************************************/
7963 OSReturn
7964 OSKext::validateKextMapping(bool startFlag)
7965 {
7966 OSReturn result = kOSReturnError;
7967 const char * whichOp = startFlag ? "start" : "stop";
7968 kern_return_t kern_result = 0;
7969 vm_map_t kext_map = NULL;
7970 kernel_segment_command_t * seg = NULL;
7971 mach_vm_address_t address = 0;
7972 mach_vm_size_t size = 0;
7973 uint32_t depth = 0;
7974 uint64_t kext_segbase = 0;
7975 uint64_t kext_segsize = 0;
7976 mach_msg_type_number_t count;
7977 vm_region_submap_short_info_data_64_t info;
7978 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7979
7980 if (flags.builtin) {
7981 return kOSReturnSuccess;
7982 }
7983
7984 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7985 bzero(&info, sizeof(info));
7986
7987 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7988 // xxx - sufficient?
7989
7990 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7991 */
7992 if (!kmod_info) {
7993 OSKextLog(this,
7994 kOSKextLogErrorLevel |
7995 kOSKextLogLoadFlag,
7996 "Kext %s - NULL kmod_info pointer.",
7997 getIdentifierCString());
7998 result = kOSKextReturnBadData;
7999 goto finish;
8000 }
8001
8002 if (startFlag) {
8003 address = (mach_vm_address_t)kmod_info->start;
8004 } else {
8005 address = (mach_vm_address_t)kmod_info->stop;
8006 }
8007
8008 if (!address) {
8009 OSKextLog(this,
8010 kOSKextLogErrorLevel |
8011 kOSKextLogLoadFlag,
8012 "Kext %s - NULL module %s pointer.",
8013 getIdentifierCString(), whichOp);
8014 result = kOSKextReturnBadData;
8015 goto finish;
8016 }
8017
8018 kext_map = kext_get_vm_map(kmod_info);
8019 depth = (kernel_map == kext_map) ? 1 : 2;
8020 if (isInFileset()) {
8021 #if defined(HAS_APPLE_PAC)
8022 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
8023 #endif /* defined(HAS_APPLE_PAC) */
8024 }
8025
8026 /* Verify that the start/stop function lies within the kext's address range.
8027 */
8028 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
8029 isInFileset()) {
8030 /* This will likely be how we deal with split kexts; walk the segments to
8031 * check that the function lies inside one of the segments of this kext.
8032 */
8033 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8034 seg != NULL;
8035 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
8036 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
8037 kext_segbase = seg->vmaddr;
8038 kext_segsize = seg->vmsize;
8039 break;
8040 }
8041 }
8042
8043 if (!seg) {
8044 OSKextLog(this,
8045 kOSKextLogErrorLevel |
8046 kOSKextLogLoadFlag,
8047 "Kext %s module %s pointer is outside of kext range "
8048 "(%s %p - kext starts at %p).",
8049 getIdentifierCString(),
8050 whichOp,
8051 whichOp,
8052 (void *)(((uintptr_t)address) - kext_slide),
8053 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
8054 result = kOSKextReturnBadData;
8055 goto finish;
8056 }
8057
8058 seg = NULL;
8059 } else {
8060 if (address < kmod_info->address + kmod_info->hdr_size ||
8061 kmod_info->address + kmod_info->size <= address) {
8062 OSKextLog(this,
8063 kOSKextLogErrorLevel |
8064 kOSKextLogLoadFlag,
8065 "Kext %s module %s pointer is outside of kext range "
8066 "(%s %p - kext at %p-%p).",
8067 getIdentifierCString(),
8068 whichOp,
8069 whichOp,
8070 (void *)(((uintptr_t)address) - kext_slide),
8071 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
8072 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
8073 result = kOSKextReturnBadData;
8074 goto finish;
8075 }
8076 }
8077
8078 /* Only do these checks before calling the start function;
8079 * If anything goes wrong with the mapping while the kext is running,
8080 * we'll likely have panicked well before any attempt to stop the kext.
8081 */
8082 if (startFlag) {
8083 if (!isInFileset() || kc_type != KCKindPrimary) {
8084 /*
8085 * Verify that the start/stop function is executable.
8086 */
8087 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
8088 (vm_region_recurse_info_t)&info, &count);
8089 if (kern_result != KERN_SUCCESS) {
8090 OSKextLog(this,
8091 kOSKextLogErrorLevel |
8092 kOSKextLogLoadFlag,
8093 "Kext %s - bad %s pointer %p.",
8094 getIdentifierCString(),
8095 whichOp, (void *)ml_static_unslide(address));
8096 result = kOSKextReturnBadData;
8097 goto finish;
8098 }
8099 } else {
8100 /*
8101 * Since kexts loaded from the primary KC are held in memory
8102 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8103 * discover that memory's protection flags. Instead, we need to
8104 * get that information from the kernel pmap itself. Above, we
8105 * (potentially) saved the size of the segment in which the address
8106 * in question was located. If we have a non-zero size, verify
8107 * that all pages in the (address, address + kext_segsize) range
8108 * are marked executable. If we somehow did not record the size
8109 * (or the base) just verify the single page that includes the address.
8110 */
8111 if (kext_segbase == 0 || kext_segsize == 0) {
8112 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8113 kext_segsize = PAGE_SIZE;
8114 }
8115 }
8116
8117 #if VM_MAPPED_KEXTS
8118 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8119 ((isInFileset() && kc_type == KCKindPrimary) &&
8120 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8121 OSKextLog(this,
8122 kOSKextLogErrorLevel |
8123 kOSKextLogLoadFlag,
8124 "Kext %s - memory region containing module %s function "
8125 "is not executable.",
8126 getIdentifierCString(), whichOp);
8127 result = kOSKextReturnBadData;
8128 goto finish;
8129 }
8130 #endif
8131
8132 /* Verify that the kext's segments are backed by physical memory.
8133 */
8134 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8135 while (seg) {
8136 if (!verifySegmentMapping(seg)) {
8137 result = kOSKextReturnBadData;
8138 goto finish;
8139 }
8140
8141 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8142 }
8143 }
8144
8145 result = kOSReturnSuccess;
8146 finish:
8147 return result;
8148 }
8149
8150 /*********************************************************************
8151 *********************************************************************/
8152 boolean_t
8153 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8154 {
8155 mach_vm_address_t address = 0;
8156
8157 if (seg->vmsize > UINT32_MAX) {
8158 return false;
8159 }
8160
8161 if (!segmentShouldBeWired(seg)) {
8162 return true;
8163 }
8164
8165 for (address = seg->vmaddr;
8166 address < round_page(seg->vmaddr + seg->vmsize);
8167 address += PAGE_SIZE) {
8168 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
8169 OSKextLog(this,
8170 kOSKextLogErrorLevel |
8171 kOSKextLogLoadFlag,
8172 "Kext %s - page %p is not backed by physical memory.",
8173 getIdentifierCString(),
8174 (void *)address);
8175 return false;
8176 }
8177 }
8178
8179 return true;
8180 }
8181
8182 /*********************************************************************
8183 *********************************************************************/
8184 static void
8185 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8186 {
8187 uint64_t stamp = 0;
8188 firehose_tracepoint_id_u trace_id;
8189 struct firehose_trace_uuid_info_s uuid_info_s;
8190 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8191 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8192 OSSharedPtr<OSData> uuid_data;
8193
8194 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
8195 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8196
8197 uuid_data = aKext->copyTextUUID();
8198 if (uuid_data) {
8199 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
8200 }
8201
8202 uuid_info->ftui_size = size;
8203 if (aKext->isDriverKit()) {
8204 uuid_info->ftui_address = address;
8205 } else {
8206 uuid_info->ftui_address = ml_static_unslide(address);
8207 }
8208 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
8209 return;
8210 }
8211
8212 void
8213 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8214 {
8215 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
8216 }
8217
8218 /*********************************************************************
8219 *********************************************************************/
8220 OSReturn
8221 OSKext::start(bool startDependenciesFlag)
8222 {
8223 OSReturn result = kOSReturnError;
8224 kern_return_t (* startfunc)(kmod_info_t *, void *);
8225 unsigned int i, count;
8226 void * kmodStartData = NULL;
8227
8228 if (isStarted() || isInterface() || isKernelComponent()) {
8229 result = kOSReturnSuccess;
8230 goto finish;
8231 }
8232
8233 if (!isLoaded()) {
8234 OSKextLog(this,
8235 kOSKextLogErrorLevel |
8236 kOSKextLogLoadFlag,
8237 "Attempt to start nonloaded kext %s.",
8238 getIdentifierCString());
8239 result = kOSKextReturnInvalidArgument;
8240 goto finish;
8241 }
8242
8243 if (!sLoadEnabled) {
8244 OSKextLog(this,
8245 kOSKextLogErrorLevel |
8246 kOSKextLogLoadFlag,
8247 "Kext loading is disabled (attempt to start kext %s).",
8248 getIdentifierCString());
8249 result = kOSKextReturnDisabled;
8250 goto finish;
8251 }
8252
8253 result = validateKextMapping(/* start? */ true);
8254 if (result != kOSReturnSuccess) {
8255 goto finish;
8256 }
8257
8258 startfunc = kmod_info->start;
8259
8260 count = getNumDependencies();
8261 for (i = 0; i < count; i++) {
8262 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8263 if (dependency == NULL) {
8264 OSKextLog(this,
8265 kOSKextLogErrorLevel |
8266 kOSKextLogLoadFlag,
8267 "Kext %s start - internal error, dependency disappeared.",
8268 getIdentifierCString());
8269 goto finish;
8270 }
8271 if (!dependency->isStarted()) {
8272 if (startDependenciesFlag) {
8273 OSReturn dependencyResult =
8274 dependency->start(startDependenciesFlag);
8275 if (dependencyResult != KERN_SUCCESS) {
8276 OSKextLog(this,
8277 kOSKextLogErrorLevel |
8278 kOSKextLogLoadFlag,
8279 "Kext %s start - dependency %s failed to start (error 0x%x).",
8280 getIdentifierCString(),
8281 dependency->getIdentifierCString(),
8282 dependencyResult);
8283 goto finish;
8284 }
8285 } else {
8286 OSKextLog(this,
8287 kOSKextLogErrorLevel |
8288 kOSKextLogLoadFlag,
8289 "Not starting %s - dependency %s not started yet.",
8290 getIdentifierCString(),
8291 dependency->getIdentifierCString());
8292 result = kOSKextReturnStartStopError; // xxx - make new return?
8293 goto finish;
8294 }
8295 }
8296 }
8297
8298 OSKextLog(this,
8299 kOSKextLogDetailLevel |
8300 kOSKextLogLoadFlag,
8301 "Kext %s calling module start function.",
8302 getIdentifierCString());
8303
8304 flags.starting = 1;
8305
8306 // Drop a log message so logd can grab the needed information to decode this kext
8307 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
8308 result = OSRuntimeInitializeCPP(this);
8309 if (result == KERN_SUCCESS) {
8310 result = startfunc(kmod_info, kmodStartData);
8311 }
8312
8313 flags.starting = 0;
8314
8315 /* On success overlap the setting of started/starting. On failure just
8316 * clear starting.
8317 */
8318 if (result == KERN_SUCCESS) {
8319 flags.started = 1;
8320
8321 // xxx - log start error from kernel?
8322 OSKextLog(this,
8323 kOSKextLogProgressLevel |
8324 kOSKextLogLoadFlag,
8325 "Kext %s is now started.",
8326 getIdentifierCString());
8327 } else {
8328 invokeOrCancelRequestCallbacks(
8329 /* result not actually used */ kOSKextReturnStartStopError,
8330 /* invokeFlag */ false);
8331 OSKextLog(this,
8332 kOSKextLogWarningLevel |
8333 kOSKextLogLoadFlag,
8334 "Kext %s did not start (return code 0x%x).",
8335 getIdentifierCString(), result);
8336 }
8337
8338 finish:
8339 return result;
8340 }
8341
8342 /*********************************************************************
8343 *********************************************************************/
8344 /* static */
8345 bool
8346 OSKext::canUnloadKextWithIdentifier(
8347 OSString * kextIdentifier,
8348 bool checkClassesFlag)
8349 {
8350 bool result = false;
8351 OSKext * aKext = NULL; // do not release
8352
8353 IORecursiveLockLock(sKextLock);
8354
8355 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8356
8357 if (!aKext) {
8358 goto finish; // can't unload what's not loaded
8359 }
8360
8361 if (aKext->isLoaded()) {
8362 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8363 goto finish;
8364 }
8365 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8366 goto finish;
8367 }
8368 }
8369
8370 result = true;
8371
8372 finish:
8373 IORecursiveLockUnlock(sKextLock);
8374 return result;
8375 }
8376
8377 /*********************************************************************
8378 *********************************************************************/
8379 OSReturn
8380 OSKext::stop(void)
8381 {
8382 OSReturn result = kOSReturnError;
8383 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8384
8385 if (!isStarted() || isInterface()) {
8386 result = kOSReturnSuccess;
8387 goto finish;
8388 }
8389
8390 if (!isLoaded()) {
8391 OSKextLog(this,
8392 kOSKextLogErrorLevel |
8393 kOSKextLogLoadFlag,
8394 "Attempt to stop nonloaded kext %s.",
8395 getIdentifierCString());
8396 result = kOSKextReturnInvalidArgument;
8397 goto finish;
8398 }
8399
8400 /* Refuse to stop if we have clients or instances. It is up to
8401 * the caller to make sure those aren't true.
8402 */
8403 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8404 OSKextLog(this,
8405 kOSKextLogErrorLevel |
8406 kOSKextLogLoadFlag,
8407 "Kext %s - C++ instances; can't stop.",
8408 getIdentifierCString());
8409 result = kOSKextReturnInUse;
8410 goto finish;
8411 }
8412
8413 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8414 OSKextLog(this,
8415 kOSKextLogErrorLevel |
8416 kOSKextLogLoadFlag,
8417 "Kext %s - has references (linkage or tracking object); "
8418 "can't stop.",
8419 getIdentifierCString());
8420 result = kOSKextReturnInUse;
8421 goto finish;
8422 }
8423
8424 /* Note: If validateKextMapping fails on the stop & unload path,
8425 * we are in serious trouble and a kernel panic is likely whether
8426 * we stop & unload the kext or not.
8427 */
8428 result = validateKextMapping(/* start? */ false);
8429 if (result != kOSReturnSuccess) {
8430 goto finish;
8431 }
8432
8433 stopfunc = kmod_info->stop;
8434 if (stopfunc) {
8435 OSKextLog(this,
8436 kOSKextLogDetailLevel |
8437 kOSKextLogLoadFlag,
8438 "Kext %s calling module stop function.",
8439 getIdentifierCString());
8440
8441 flags.stopping = 1;
8442
8443 result = stopfunc(kmod_info, /* userData */ NULL);
8444 if (result == KERN_SUCCESS) {
8445 result = OSRuntimeFinalizeCPP(this);
8446 }
8447
8448 flags.stopping = 0;
8449
8450 if (result == KERN_SUCCESS) {
8451 flags.started = 0;
8452
8453 OSKextLog(this,
8454 kOSKextLogDetailLevel |
8455 kOSKextLogLoadFlag,
8456 "Kext %s is now stopped and ready to unload.",
8457 getIdentifierCString());
8458 } else {
8459 OSKextLog(this,
8460 kOSKextLogErrorLevel |
8461 kOSKextLogLoadFlag,
8462 "Kext %s did not stop (return code 0x%x).",
8463 getIdentifierCString(), result);
8464 result = kOSKextReturnStartStopError;
8465 }
8466 }
8467
8468 finish:
8469 // Drop a log message so logd can update this kext's metadata
8470 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
8471 return result;
8472 }
8473
8474 /*********************************************************************
8475 *********************************************************************/
8476 OSReturn
8477 OSKext::unload(void)
8478 {
8479 OSReturn result = kOSReturnError;
8480 unsigned int index;
8481 uint32_t num_kmod_refs = 0;
8482 OSKextAccount * freeAccount;
8483 bool in_fileset = false;
8484
8485 if (!sUnloadEnabled) {
8486 OSKextLog(this,
8487 kOSKextLogErrorLevel |
8488 kOSKextLogLoadFlag,
8489 "Kext unloading is disabled (%s).",
8490 this->getIdentifierCString());
8491
8492 result = kOSKextReturnDisabled;
8493 goto finish;
8494 }
8495
8496 // cache this result so we don't need to access the kmod_info after
8497 // it's been potentially free'd
8498 in_fileset = isInFileset();
8499
8500 /* Refuse to unload if we have clients or instances. It is up to
8501 * the caller to make sure those aren't true.
8502 */
8503 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8504 // xxx - Don't log under errors? this is more of an info thing
8505 OSKextLog(this,
8506 kOSKextLogErrorLevel |
8507 kOSKextLogKextBookkeepingFlag,
8508 "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8509 getIdentifierCString(), getRetainCount());
8510 result = kOSKextReturnInUse;
8511 goto finish;
8512 }
8513
8514 if (isDriverKit()) {
8515 index = sLoadedDriverKitKexts->getNextIndexOfObject(this, 0);
8516 if (index != (unsigned int)-1) {
8517 sLoadedDriverKitKexts->removeObject(index);
8518 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
8519 loadTag = 0;
8520 }
8521 }
8522
8523 if (!isLoaded()) {
8524 result = kOSReturnSuccess;
8525 goto finish;
8526 }
8527
8528 if (isKernelComponent()) {
8529 result = kOSKextReturnInvalidArgument;
8530 goto finish;
8531 }
8532
8533 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
8534 OSKextLog(this,
8535 kOSKextLogErrorLevel |
8536 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8537 "Can't unload kext %s; classes have instances:",
8538 getIdentifierCString());
8539 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8540 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8541 result = kOSKextReturnInUse;
8542 goto finish;
8543 }
8544
8545 /* Note that the kext is unloading before running any code that
8546 * might be in the kext (request callbacks, module stop function).
8547 * We will deny certain requests made against a kext in the process
8548 * of unloading.
8549 */
8550 flags.unloading = 1;
8551
8552 /* Update the string describing the last kext to unload in case we panic.
8553 */
8554 savePanicString(/* isLoading */ false);
8555
8556 if (isStarted()) {
8557 result = stop();
8558 if (result != KERN_SUCCESS) {
8559 OSKextLog(this,
8560 kOSKextLogErrorLevel |
8561 kOSKextLogLoadFlag,
8562 "Kext %s can't unload - module stop returned 0x%x.",
8563 getIdentifierCString(), (unsigned)result);
8564 result = kOSKextReturnStartStopError;
8565 goto finish;
8566 }
8567 }
8568
8569 OSKextLog(this,
8570 kOSKextLogProgressLevel |
8571 kOSKextLogLoadFlag,
8572 "Kext %s unloading.",
8573 getIdentifierCString());
8574
8575 {
8576 struct list_head *p;
8577 struct list_head *prev;
8578 struct list_head *next;
8579 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8580 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8581 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
8582 prev = p->prev;
8583 next = p->next;
8584 prev->next = next;
8585 next->prev = prev;
8586 p->prev = p;
8587 p->next = p;
8588 IORecursiveLockWakeup(sKextLock, s, false);
8589 }
8590 }
8591
8592
8593 /* Even if we don't call the stop function, we want to be sure we
8594 * have no OSMetaClass references before unloading the kext executable
8595 * from memory. OSMetaClasses may have pointers into the kext executable
8596 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8597 */
8598 if (metaClasses) {
8599 metaClasses->flushCollection();
8600 }
8601 (void) OSRuntimeFinalizeCPP(this);
8602
8603 /* Remove the kext from the list of loaded kexts, patch the gap
8604 * in the kmod_info_t linked list, and reset "kmod" to point to the
8605 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8606 */
8607 index = sLoadedKexts->getNextIndexOfObject(this, 0);
8608 if (index != (unsigned int)-1) {
8609 sLoadedKexts->removeObject(index);
8610
8611 OSKext * nextKext = OSDynamicCast(OSKext,
8612 sLoadedKexts->getObject(index));
8613
8614 if (nextKext) {
8615 if (index > 0) {
8616 OSKext * gapKext = OSDynamicCast(OSKext,
8617 sLoadedKexts->getObject(index - 1));
8618
8619 nextKext->kmod_info->next = gapKext->kmod_info;
8620 } else { /* index == 0 */
8621 nextKext->kmod_info->next = NULL;
8622 }
8623 }
8624
8625 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8626 if (lastKext && !lastKext->isKernel()) {
8627 kmod = lastKext->kmod_info;
8628 } else {
8629 kmod = NULL; // clear the global kmod variable
8630 }
8631 }
8632
8633 /* Clear out the kmod references that we're keeping for compatibility
8634 * with current panic backtrace code & kgmacros.
8635 * xxx - will want to update those bits sometime and remove this.
8636 */
8637 num_kmod_refs = getNumDependencies();
8638 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8639 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8640 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8641 ref->info->reference_count--;
8642 }
8643 kfree_type(kmod_reference_t, num_kmod_refs,
8644 kmod_info->reference_list);
8645 }
8646
8647 #if CONFIG_DTRACE
8648 unregisterWithDTrace();
8649 #endif /* CONFIG_DTRACE */
8650
8651 notifyKextUnloadObservers(this);
8652
8653 freeAccount = NULL;
8654 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
8655 account->kext = NULL;
8656 if (account->site.tag) {
8657 account->site.flags |= VM_TAG_UNLOAD;
8658 } else {
8659 freeAccount = account;
8660 }
8661
8662 #if DEVELOPMENT || DEBUG
8663 assertf(account->task_refgrp.grp_count == 0,
8664 "unloading a kext with active task references");
8665 #endif /* DEVELOPMENT || DEBUG */
8666
8667 lck_ticket_unlock(sKextAccountsLock);
8668 if (freeAccount) {
8669 IOFreeType(freeAccount, OSKextAccount);
8670 }
8671
8672 /* Unwire and free the linked executable.
8673 */
8674 if (linkedExecutable) {
8675 #if KASAN
8676 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8677 #endif
8678
8679 #if VM_MAPPED_KEXTS
8680 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8681 kernel_segment_command_t *seg = NULL;
8682 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8683
8684 if (!kext_map) {
8685 OSKextLog(this,
8686 kOSKextLogErrorLevel |
8687 kOSKextLogLoadFlag,
8688 "Failed to free kext %s; couldn't find the kext map.",
8689 getIdentifierCString());
8690 result = kOSKextReturnInternalError;
8691 goto finish;
8692 }
8693
8694 OSKextLog(this,
8695 kOSKextLogProgressLevel |
8696 kOSKextLogLoadFlag,
8697 "Kext %s unwiring and unmapping linked executable.",
8698 getIdentifierCString());
8699
8700 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8701 while (seg) {
8702 if (segmentShouldBeWired(seg)) {
8703 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8704 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8705
8706 result = vm_map_unwire(kext_map, start_wire,
8707 end_wire, FALSE);
8708 if (result != KERN_SUCCESS) {
8709 OSKextLog(this,
8710 kOSKextLogErrorLevel |
8711 kOSKextLogLoadFlag,
8712 "Failed to unwire kext %s.",
8713 getIdentifierCString());
8714 result = kOSKextReturnInternalError;
8715 goto finish;
8716 }
8717 }
8718
8719 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8720 }
8721 #if defined(__x86_64__) || defined(__i386__)
8722 if (in_fileset && flags.resetSegmentsFromVnode) {
8723 IORecursiveLockLock(sKextLock);
8724 resetKCFileSetSegments();
8725 IORecursiveLockUnlock(sKextLock);
8726 }
8727 #endif // (__x86_64__) || defined(__i386__)
8728 }
8729 #endif /* VM_MAPPED_KEXTS */
8730 if (flags.resetSegmentsFromImmutableCopy) {
8731 result = resetMutableSegments();
8732 if (result != kOSReturnSuccess) {
8733 OSKextLog(this,
8734 kOSKextLogErrorLevel |
8735 kOSKextLogLoadFlag,
8736 "Failed to reset kext %s.",
8737 getIdentifierCString());
8738 result = kOSKextReturnInternalError;
8739 goto finish;
8740 }
8741 }
8742 if (kc_type == KCKindUnknown) {
8743 linkedExecutable.reset();
8744 }
8745 }
8746
8747 /* An interface kext has a fake kmod_info that was allocated,
8748 * so we have to free it.
8749 */
8750 if (isInterface()) {
8751 kfree_type(kmod_info_t, kmod_info);
8752 kmod_info = NULL;
8753 }
8754
8755 if (!in_fileset) {
8756 kmod_info = NULL;
8757 }
8758
8759 flags.loaded = false;
8760 flushDependencies();
8761
8762 /* save a copy of the bundle ID for us to check when deciding to
8763 * rebuild the kernel cache file. If a kext was already in the kernel
8764 * cache and unloaded then later loaded we do not need to rebuild the
8765 * kernel cache. 9055303
8766 */
8767 if (isPrelinked()) {
8768 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
8769 IORecursiveLockLock(sKextLock);
8770 if (sUnloadedPrelinkedKexts) {
8771 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8772 }
8773 IORecursiveLockUnlock(sKextLock);
8774 }
8775 }
8776
8777 OSKextLog(this,
8778 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8779 "Kext %s unloaded.", getIdentifierCString());
8780
8781 queueKextNotification(kKextRequestPredicateUnloadNotification,
8782 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
8783
8784 finish:
8785 OSKext::saveLoadedKextPanicList();
8786 OSKext::updateLoadedKextSummaries();
8787
8788 flags.unloading = 0;
8789 return result;
8790 }
8791
8792 /*********************************************************************
8793 * Assumes sKextLock is held.
8794 *********************************************************************/
8795 /* static */
8796 OSReturn
8797 OSKext::queueKextNotification(
8798 const char * notificationName,
8799 OSString * kextIdentifier,
8800 OSData * dextUniqueIdentifier)
8801 {
8802 OSReturn result = kOSReturnError;
8803 OSSharedPtr<OSDictionary> loadRequest;
8804
8805 if (!kextIdentifier) {
8806 result = kOSKextReturnInvalidArgument;
8807 goto finish;
8808 }
8809
8810 /* Create a new request unless one is already sitting
8811 * in sKernelRequests for this bundle identifier
8812 */
8813 result = _OSKextCreateRequest(notificationName, loadRequest);
8814 if (result != kOSReturnSuccess) {
8815 goto finish;
8816 }
8817 if (!_OSKextSetRequestArgument(loadRequest.get(),
8818 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8819 result = kOSKextReturnNoMemory;
8820 goto finish;
8821 }
8822 if (NULL != dextUniqueIdentifier) {
8823 if (!_OSKextSetRequestArgument(loadRequest.get(),
8824 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
8825 result = kOSKextReturnNoMemory;
8826 goto finish;
8827 }
8828 }
8829 if (!sKernelRequests->setObject(loadRequest.get())) {
8830 result = kOSKextReturnNoMemory;
8831 goto finish;
8832 }
8833
8834 /* We might want to only queue the notification if the IOKit daemon is active,
8835 * but that wouldn't work for embedded. Note that we don't care if
8836 * the ping immediately succeeds here so don't do anything with the
8837 * result of this call.
8838 */
8839 OSKext::pingIOKitDaemon();
8840
8841 result = kOSReturnSuccess;
8842
8843 finish:
8844 return result;
8845 }
8846
8847
8848 #if CONFIG_KXLD
8849 /*********************************************************************
8850 *********************************************************************/
8851 static void
8852 _OSKextConsiderDestroyingLinkContext(
8853 __unused thread_call_param_t p0,
8854 __unused thread_call_param_t p1)
8855 {
8856 /* Take multiple locks in the correct order.
8857 */
8858 IORecursiveLockLock(sKextLock);
8859 IORecursiveLockLock(sKextInnerLock);
8860
8861 /* The first time we destroy the kxldContext is in the first
8862 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8863 * before calling this function. Thereafter any call to this function
8864 * will actually destroy the context.
8865 */
8866 if (sConsiderUnloadsCalled && sKxldContext) {
8867 kxld_destroy_context(sKxldContext);
8868 sKxldContext = NULL;
8869 }
8870
8871 /* Free the thread_call that was allocated to execute this function.
8872 */
8873 if (sDestroyLinkContextThread) {
8874 if (!thread_call_free(sDestroyLinkContextThread)) {
8875 OSKextLog(/* kext */ NULL,
8876 kOSKextLogErrorLevel |
8877 kOSKextLogGeneralFlag,
8878 "thread_call_free() failed for kext link context.");
8879 }
8880 sDestroyLinkContextThread = NULL;
8881 }
8882
8883 IORecursiveLockUnlock(sKextInnerLock);
8884 IORecursiveLockUnlock(sKextLock);
8885
8886 return;
8887 }
8888
8889 /*********************************************************************
8890 * Destroying the kxldContext requires checking variables under both
8891 * sKextInnerLock and sKextLock, so we do it on a separate thread
8892 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8893 * call relationship.
8894 *
8895 * This function must be invoked with sKextInnerLock held.
8896 * Do not call any function that takes sKextLock here!
8897 *********************************************************************/
8898 /* static */
8899 void
8900 OSKext::considerDestroyingLinkContext(void)
8901 {
8902 IORecursiveLockLock(sKextInnerLock);
8903
8904 /* If we have already queued a thread to destroy the link context,
8905 * don't bother resetting; that thread will take care of it.
8906 */
8907 if (sDestroyLinkContextThread) {
8908 goto finish;
8909 }
8910
8911 /* The function to be invoked in the thread will deallocate
8912 * this thread_call, so don't share it around.
8913 */
8914 sDestroyLinkContextThread = thread_call_allocate(
8915 &_OSKextConsiderDestroyingLinkContext, NULL);
8916 if (!sDestroyLinkContextThread) {
8917 OSKextLog(/* kext */ NULL,
8918 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8919 "Can't create thread to destroy kext link context.");
8920 goto finish;
8921 }
8922
8923 thread_call_enter(sDestroyLinkContextThread);
8924
8925 finish:
8926 IORecursiveLockUnlock(sKextInnerLock);
8927 return;
8928 }
8929
8930 #else // !CONFIG_KXLD
8931
8932 /* static */
8933 void
8934 OSKext::considerDestroyingLinkContext(void)
8935 {
8936 return;
8937 }
8938
8939 #endif // CONFIG_KXLD
8940
8941 #if PRAGMA_MARK
8942 #pragma mark Autounload
8943 #endif
8944 /*********************************************************************
8945 * This is a static method because the kext will be deallocated if it
8946 * does unload!
8947 *********************************************************************/
8948 /* static */
8949 OSReturn
8950 OSKext::autounloadKext(OSKext * aKext)
8951 {
8952 OSReturn result = kOSKextReturnInUse;
8953
8954 #if NO_KEXTD
8955 /*
8956 * Do not unload prelinked kexts on platforms that do not have an
8957 * IOKit daemon as there is no way to reload the kext or restart
8958 * matching.
8959 */
8960 if (aKext->isPrelinked()) {
8961 goto finish;
8962 }
8963 #endif /* defined(__x86_64__) */
8964
8965 /* Check for external references to this kext (usu. dependents),
8966 * instances of defined classes (or classes derived from them),
8967 * outstanding requests.
8968 */
8969 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8970 !aKext->flags.autounloadEnabled ||
8971 aKext->isKernelComponent()) {
8972 goto finish;
8973 }
8974
8975 /* Skip a delay-autounload kext, once.
8976 */
8977 if (aKext->flags.delayAutounload) {
8978 OSKextLog(aKext,
8979 kOSKextLogProgressLevel |
8980 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8981 "Kext %s has delayed autounload set; skipping and clearing flag.",
8982 aKext->getIdentifierCString());
8983 aKext->flags.delayAutounload = 0;
8984 goto finish;
8985 }
8986
8987 if (aKext->hasOSMetaClassInstances() ||
8988 aKext->countRequestCallbacks()) {
8989 goto finish;
8990 }
8991
8992 result = OSKext::removeKext(aKext);
8993
8994 finish:
8995 return result;
8996 }
8997
8998 /*********************************************************************
8999 *********************************************************************/
9000 void
9001 _OSKextConsiderUnloads(
9002 __unused thread_call_param_t p0,
9003 __unused thread_call_param_t p1)
9004 {
9005 bool didUnload = false;
9006 unsigned int count, i;
9007
9008 /* Take multiple locks in the correct order
9009 * (note also sKextSummaries lock further down).
9010 */
9011 IORecursiveLockLock(sKextLock);
9012 IORecursiveLockLock(sKextInnerLock);
9013
9014 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
9015
9016 /* If the system is powering down, don't try to unload anything.
9017 */
9018 if (sSystemSleep) {
9019 goto finish;
9020 }
9021
9022 OSKextLog(/* kext */ NULL,
9023 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
9024 "Checking for unused kexts to autounload.");
9025
9026 /*****
9027 * Remove any request callbacks marked as stale,
9028 * and mark as stale any currently in flight.
9029 */
9030 count = sRequestCallbackRecords->getCount();
9031 if (count) {
9032 i = count - 1;
9033 do {
9034 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
9035 sRequestCallbackRecords->getObject(i));
9036 if (callbackRecord) {
9037 OSBoolean * stale = OSDynamicCast(OSBoolean,
9038 callbackRecord->getObject(kKextRequestStaleKey));
9039
9040 if (stale == kOSBooleanTrue) {
9041 OSKext::invokeRequestCallback(callbackRecord,
9042 kOSKextReturnTimeout);
9043 } else {
9044 callbackRecord->setObject(kKextRequestStaleKey,
9045 kOSBooleanTrue);
9046 }
9047 }
9048 } while (i--);
9049 }
9050
9051 /*****
9052 * Make multiple passes through the array of loaded kexts until
9053 * we don't unload any. This handles unwinding of dependency
9054 * chains. We have to go *backwards* through the array because
9055 * kexts are removed from it when unloaded, and we cannot make
9056 * a copy or we'll mess up the retain counts we rely on to
9057 * check whether a kext will unload. If only we could have
9058 * nonretaining collections like CF has....
9059 */
9060 do {
9061 didUnload = false;
9062
9063 count = sLoadedKexts->getCount();
9064 if (count) {
9065 i = count - 1;
9066 do {
9067 OSKext * thisKext = OSDynamicCast(OSKext,
9068 sLoadedKexts->getObject(i));
9069 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
9070 } while (i--);
9071 }
9072 } while (didUnload);
9073
9074 finish:
9075 sConsiderUnloadsPending = false;
9076 sConsiderUnloadsExecuted = true;
9077
9078 (void) OSKext::considerRebuildOfPrelinkedKernel();
9079
9080 IORecursiveLockUnlock(sKextInnerLock);
9081 IORecursiveLockUnlock(sKextLock);
9082
9083 return;
9084 }
9085
9086 /*********************************************************************
9087 * Do not call any function that takes sKextLock here!
9088 *********************************************************************/
9089 void
9090 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
9091 {
9092 AbsoluteTime when;
9093
9094 IORecursiveLockLock(sKextInnerLock);
9095
9096 if (!sUnloadCallout) {
9097 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
9098 }
9099
9100 /* we only reset delay value for unloading if we already have something
9101 * pending. rescheduleOnlyFlag should not start the count down.
9102 */
9103 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9104 goto finish;
9105 }
9106
9107 thread_call_cancel(sUnloadCallout);
9108 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9109 #if !NO_KEXTD
9110 && sIOKitDaemonActive
9111 #endif
9112 ) {
9113 clock_interval_to_deadline(sConsiderUnloadDelay,
9114 1000 * 1000 * 1000, &when);
9115
9116 OSKextLog(/* kext */ NULL,
9117 kOSKextLogProgressLevel |
9118 kOSKextLogLoadFlag,
9119 "%scheduling %sscan for unused kexts in %lu seconds.",
9120 sConsiderUnloadsPending ? "Res" : "S",
9121 sConsiderUnloadsCalled ? "" : "initial ",
9122 (unsigned long)sConsiderUnloadDelay);
9123
9124 sConsiderUnloadsPending = true;
9125 thread_call_enter_delayed(sUnloadCallout, when);
9126 }
9127
9128 finish:
9129 /* The kxld context should be reused throughout boot. We mark the end of
9130 * period as the first time considerUnloads() is called, and we destroy
9131 * the first kxld context in that function. Afterwards, it will be
9132 * destroyed in flushNonloadedKexts.
9133 */
9134 if (!sConsiderUnloadsCalled) {
9135 sConsiderUnloadsCalled = true;
9136 OSKext::considerDestroyingLinkContext();
9137 }
9138
9139 IORecursiveLockUnlock(sKextInnerLock);
9140 return;
9141 }
9142
9143 /*********************************************************************
9144 * Do not call any function that takes sKextLock here!
9145 *********************************************************************/
9146 extern "C" {
9147 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9148 IOReturn
9149 OSKextSystemSleepOrWake(UInt32 messageType)
9150 {
9151 IORecursiveLockLock(sKextInnerLock);
9152
9153 /* If the system is going to sleep, cancel the reaper thread timer,
9154 * and note that we're in a sleep state in case it just fired but hasn't
9155 * taken the lock yet. If we are coming back from sleep, just
9156 * clear the sleep flag; IOService's normal operation will cause
9157 * unloads to be considered soon enough.
9158 */
9159 if (messageType == kIOMessageSystemWillSleep) {
9160 if (sUnloadCallout) {
9161 thread_call_cancel(sUnloadCallout);
9162 }
9163 sSystemSleep = true;
9164 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9165 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9166 sSystemSleep = false;
9167 clock_get_uptime(&sLastWakeTime);
9168 }
9169 IORecursiveLockUnlock(sKextInnerLock);
9170
9171 return kIOReturnSuccess;
9172 }
9173 };
9174
9175
9176 #if PRAGMA_MARK
9177 #pragma mark Prelinked Kernel
9178 #endif
9179
9180 #ifdef CONFIG_KXLD
9181 /*********************************************************************
9182 * Do not access sConsiderUnloads... variables other than
9183 * sConsiderUnloadsExecuted in this function. They are guarded by a
9184 * different lock.
9185 *********************************************************************/
9186 /* static */
9187 void
9188 OSKext::considerRebuildOfPrelinkedKernel(void)
9189 {
9190 static bool requestedPrelink = false;
9191 OSReturn checkResult = kOSReturnError;
9192 OSSharedPtr<OSDictionary> prelinkRequest;
9193 OSSharedPtr<OSCollectionIterator> kextIterator;
9194 const OSSymbol * thisID = NULL; // do not release
9195 bool doRebuild = false;
9196 AbsoluteTime my_abstime;
9197 UInt64 my_ns;
9198 SInt32 delta_secs;
9199
9200 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9201 if (requestedPrelink || !sPrelinkBoot) {
9202 return;
9203 }
9204
9205 /* no direct return from this point */
9206 IORecursiveLockLock(sKextLock);
9207
9208 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9209 * and any new startup kexts loaded.
9210 */
9211 if (!sConsiderUnloadsExecuted ||
9212 !sDeferredLoadSucceeded) {
9213 goto finish;
9214 }
9215
9216 /* we really only care about boot / system start up related kexts so bail
9217 * if we're here after REBUILD_MAX_TIME.
9218 */
9219 if (!_OSKextInPrelinkRebuildWindow()) {
9220 OSKextLog(/* kext */ NULL,
9221 kOSKextLogArchiveFlag,
9222 "%s prebuild rebuild has expired",
9223 __FUNCTION__);
9224 requestedPrelink = true;
9225 goto finish;
9226 }
9227
9228 /* we do not want to trigger a rebuild if we get here too close to waking
9229 * up. (see radar 10233768)
9230 */
9231 IORecursiveLockLock(sKextInnerLock);
9232
9233 clock_get_uptime(&my_abstime);
9234 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9235 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9236 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9237 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9238 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9239 }
9240 IORecursiveLockUnlock(sKextInnerLock);
9241
9242 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9243 /* too close to time of last wake from sleep */
9244 goto finish;
9245 }
9246 requestedPrelink = true;
9247
9248 /* Now it's time to see if we have a reason to rebuild. We may have done
9249 * some loads and unloads but the kernel cache didn't actually change.
9250 * We will rebuild if any kext is not marked prelinked AND is not in our
9251 * list of prelinked kexts that got unloaded. (see radar 9055303)
9252 */
9253 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9254 if (!kextIterator) {
9255 goto finish;
9256 }
9257
9258 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9259 OSKext * thisKext; // do not release
9260
9261 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9262 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9263 continue;
9264 }
9265
9266 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9267 continue;
9268 }
9269 /* kext is loaded and was not in current kernel cache so let's rebuild
9270 */
9271 doRebuild = true;
9272 OSKextLog(/* kext */ NULL,
9273 kOSKextLogArchiveFlag,
9274 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9275 thisKext->bundleID->getCStringNoCopy());
9276 break;
9277 }
9278 sUnloadedPrelinkedKexts->flushCollection();
9279
9280 if (!doRebuild) {
9281 goto finish;
9282 }
9283
9284 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9285 prelinkRequest);
9286 if (checkResult != kOSReturnSuccess) {
9287 goto finish;
9288 }
9289
9290 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9291 goto finish;
9292 }
9293
9294 OSKext::pingIOKitDaemon();
9295
9296 finish:
9297 IORecursiveLockUnlock(sKextLock);
9298
9299 return;
9300 }
9301
9302 #else /* !CONFIG_KXLD */
9303
9304 void
9305 OSKext::considerRebuildOfPrelinkedKernel(void)
9306 {
9307 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9308 return;
9309 }
9310
9311 #endif /* CONFIG_KXLD */
9312
9313 #if PRAGMA_MARK
9314 #pragma mark Dependencies
9315 #endif
9316 /*********************************************************************
9317 *********************************************************************/
9318 bool
9319 OSKext::resolveDependencies(
9320 OSArray * loopStack)
9321 {
9322 bool result = false;
9323 OSSharedPtr<OSArray> localLoopStack;
9324 bool addedToLoopStack = false;
9325 OSDictionary * libraries = NULL; // do not release
9326 OSSharedPtr<OSCollectionIterator> libraryIterator;
9327 OSString * libraryID = NULL; // do not release
9328 OSKext * libraryKext = NULL; // do not release
9329 bool hasRawKernelDependency = false;
9330 bool hasKernelDependency = false;
9331 bool hasKPIDependency = false;
9332 bool hasPrivateKPIDependency = false;
9333 unsigned int count;
9334
9335 #if CONFIG_KXLD
9336 OSString * infoString = NULL; // do not release
9337 OSString * readableString = NULL; // do not release
9338 #endif // CONFIG_KXLD
9339
9340 /* A kernel component will automatically have this flag set,
9341 * and a loaded kext should also have it set (as should all its
9342 * loaded dependencies).
9343 */
9344 if (flags.hasAllDependencies) {
9345 result = true;
9346 goto finish;
9347 }
9348
9349 /* Check for loops in the dependency graph.
9350 */
9351 if (loopStack) {
9352 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
9353 OSKextLog(this,
9354 kOSKextLogErrorLevel |
9355 kOSKextLogDependenciesFlag,
9356 "Kext %s has a dependency loop; can't resolve dependencies.",
9357 getIdentifierCString());
9358 goto finish;
9359 }
9360 } else {
9361 OSKextLog(this,
9362 kOSKextLogStepLevel |
9363 kOSKextLogDependenciesFlag,
9364 "Kext %s resolving dependencies.",
9365 getIdentifierCString());
9366
9367 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
9368 if (!localLoopStack) {
9369 OSKextLog(this,
9370 kOSKextLogErrorLevel |
9371 kOSKextLogDependenciesFlag,
9372 "Kext %s can't create bookkeeping stack to resolve dependencies.",
9373 getIdentifierCString());
9374 goto finish;
9375 }
9376 loopStack = localLoopStack.get();
9377 }
9378 if (!loopStack->setObject(this)) {
9379 OSKextLog(this,
9380 kOSKextLogErrorLevel |
9381 kOSKextLogDependenciesFlag,
9382 "Kext %s - internal error resolving dependencies.",
9383 getIdentifierCString());
9384 goto finish;
9385 }
9386 addedToLoopStack = true;
9387
9388 /* Purge any existing kexts in the dependency list and start over.
9389 */
9390 flushDependencies();
9391 if (dependencies) {
9392 OSKextLog(this,
9393 kOSKextLogErrorLevel |
9394 kOSKextLogDependenciesFlag,
9395 "Kext %s - internal error resolving dependencies.",
9396 getIdentifierCString());
9397 }
9398
9399 libraries = OSDynamicCast(OSDictionary,
9400 getPropertyForHostArch(kOSBundleLibrariesKey));
9401 if (libraries == NULL || libraries->getCount() == 0) {
9402 OSKextLog(this,
9403 kOSKextLogErrorLevel |
9404 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9405 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9406 getIdentifierCString(), kOSBundleLibrariesKey);
9407 goto finish;
9408 }
9409
9410 /* Make a new array to hold the dependencies (flush freed the old one).
9411 */
9412 dependencies = OSArray::withCapacity(libraries->getCount());
9413 if (!dependencies) {
9414 OSKextLog(this,
9415 kOSKextLogErrorLevel |
9416 kOSKextLogDependenciesFlag,
9417 "Kext %s - can't allocate dependencies array.",
9418 getIdentifierCString());
9419 goto finish;
9420 }
9421
9422 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9423 // xxx - compat: if none were declared.
9424
9425 libraryIterator = OSCollectionIterator::withCollection(libraries);
9426 if (!libraryIterator) {
9427 OSKextLog(this,
9428 kOSKextLogErrorLevel |
9429 kOSKextLogDependenciesFlag,
9430 "Kext %s - can't allocate dependencies iterator.",
9431 getIdentifierCString());
9432 goto finish;
9433 }
9434
9435 while ((libraryID = OSDynamicCast(OSString,
9436 libraryIterator->getNextObject()))) {
9437 const char * library_id = libraryID->getCStringNoCopy();
9438
9439 OSString * libraryVersion = OSDynamicCast(OSString,
9440 libraries->getObject(libraryID));
9441 if (libraryVersion == NULL) {
9442 OSKextLog(this,
9443 kOSKextLogErrorLevel |
9444 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9445 "Kext %s - illegal type in OSBundleLibraries.",
9446 getIdentifierCString());
9447 goto finish;
9448 }
9449
9450 OSKextVersion libraryVers =
9451 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
9452 if (libraryVers == -1) {
9453 OSKextLog(this,
9454 kOSKextLogErrorLevel |
9455 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9456 "Kext %s - invalid library version %s.",
9457 getIdentifierCString(),
9458 libraryVersion->getCStringNoCopy());
9459 goto finish;
9460 }
9461
9462 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9463 if (libraryKext == NULL) {
9464 OSKextLog(this,
9465 kOSKextLogErrorLevel |
9466 kOSKextLogDependenciesFlag,
9467 "Kext %s - library kext %s not found.",
9468 getIdentifierCString(), library_id);
9469 goto finish;
9470 }
9471
9472 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
9473 OSKextLog(this,
9474 kOSKextLogErrorLevel |
9475 kOSKextLogDependenciesFlag,
9476 "Kext %s - library kext %s not compatible "
9477 "with requested version %s.",
9478 getIdentifierCString(), library_id,
9479 libraryVersion->getCStringNoCopy());
9480 goto finish;
9481 }
9482
9483 /* If a nonprelinked library somehow got into the mix for a
9484 * prelinked kext, at any point in the chain, we must fail
9485 * because the prelinked relocs for the library will be all wrong.
9486 */
9487 if (this->isPrelinked() &&
9488 libraryKext->declaresExecutable() &&
9489 !libraryKext->isPrelinked()) {
9490 OSKextLog(this,
9491 kOSKextLogErrorLevel |
9492 kOSKextLogDependenciesFlag,
9493 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9494 getIdentifierCString(), library_id,
9495 libraryVersion->getCStringNoCopy());
9496 goto finish;
9497 }
9498
9499 if (!libraryKext->resolveDependencies(loopStack)) {
9500 goto finish;
9501 }
9502
9503 /* Add the library directly only if it has an executable to link.
9504 * Otherwise it's just used to collect other dependencies, so put
9505 * *its* dependencies on the list for this kext.
9506 */
9507 // xxx - We are losing info here; would like to make fake entries or
9508 // xxx - keep these in the dependency graph for loaded kexts.
9509 // xxx - I really want to make kernel components not a special case!
9510 if (libraryKext->declaresExecutable() ||
9511 libraryKext->isInterface()) {
9512 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
9513 dependencies->setObject(libraryKext);
9514
9515 OSKextLog(this,
9516 kOSKextLogDetailLevel |
9517 kOSKextLogDependenciesFlag,
9518 "Kext %s added dependency %s.",
9519 getIdentifierCString(),
9520 libraryKext->getIdentifierCString());
9521 }
9522 } else {
9523 int numLibDependencies = libraryKext->getNumDependencies();
9524 OSArray * libraryDependencies = libraryKext->getDependencies();
9525 int index;
9526
9527 if (numLibDependencies) {
9528 // xxx - this msg level should be 1 lower than the per-kext one
9529 OSKextLog(this,
9530 kOSKextLogDetailLevel |
9531 kOSKextLogDependenciesFlag,
9532 "Kext %s pulling %d dependencies from codeless library %s.",
9533 getIdentifierCString(),
9534 numLibDependencies,
9535 libraryKext->getIdentifierCString());
9536 }
9537 for (index = 0; index < numLibDependencies; index++) {
9538 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9539 libraryDependencies->getObject(index));
9540 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
9541 dependencies->setObject(thisLibDependency);
9542 OSKextLog(this,
9543 kOSKextLogDetailLevel |
9544 kOSKextLogDependenciesFlag,
9545 "Kext %s added dependency %s from codeless library %s.",
9546 getIdentifierCString(),
9547 thisLibDependency->getIdentifierCString(),
9548 libraryKext->getIdentifierCString());
9549 }
9550 }
9551 }
9552
9553 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
9554 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
9555 hasRawKernelDependency = true;
9556 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9557 hasKernelDependency = true;
9558 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9559 hasKPIDependency = true;
9560 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
9561 hasPrivateKPIDependency = true;
9562 }
9563 }
9564 }
9565
9566 if (hasRawKernelDependency) {
9567 OSKextLog(this,
9568 kOSKextLogErrorLevel |
9569 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9570 "Error - kext %s declares a dependency on %s, which is not permitted.",
9571 getIdentifierCString(), KERNEL_LIB);
9572 goto finish;
9573 }
9574 #if __LP64__
9575 if (hasKernelDependency) {
9576 OSKextLog(this,
9577 kOSKextLogErrorLevel |
9578 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9579 "Error - kext %s declares %s dependencies. "
9580 "Only %s* dependencies are supported for 64-bit kexts.",
9581 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9582 goto finish;
9583 }
9584 if (!hasKPIDependency) {
9585 OSKextLog(this,
9586 kOSKextLogWarningLevel |
9587 kOSKextLogDependenciesFlag,
9588 "Warning - kext %s declares no %s* dependencies. "
9589 "If it uses any KPIs, the link may fail with undefined symbols.",
9590 getIdentifierCString(), KPI_LIB_PREFIX);
9591 }
9592 #else /* __LP64__ */
9593 // xxx - will change to flatly disallow "kernel" dependencies at some point
9594 // xxx - is it invalid to do both "com.apple.kernel" and any
9595 // xxx - "com.apple.kernel.*"?
9596
9597 if (hasKernelDependency && hasKPIDependency) {
9598 OSKextLog(this,
9599 kOSKextLogWarningLevel |
9600 kOSKextLogDependenciesFlag,
9601 "Warning - kext %s has immediate dependencies on both "
9602 "%s* and %s* components; use only one style.",
9603 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9604 }
9605
9606 if (!hasKernelDependency && !hasKPIDependency) {
9607 // xxx - do we want to use validation flag for these too?
9608 OSKextLog(this,
9609 kOSKextLogWarningLevel |
9610 kOSKextLogDependenciesFlag,
9611 "Warning - %s declares no kernel dependencies; using %s.",
9612 getIdentifierCString(), KERNEL6_LIB);
9613 OSKext * kernelKext = OSDynamicCast(OSKext,
9614 sKextsByID->getObject(KERNEL6_LIB));
9615 if (kernelKext) {
9616 dependencies->setObject(kernelKext);
9617 } else {
9618 OSKextLog(this,
9619 kOSKextLogErrorLevel |
9620 kOSKextLogDependenciesFlag,
9621 "Error - Library %s not found for %s.",
9622 KERNEL6_LIB, getIdentifierCString());
9623 }
9624 }
9625
9626 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9627 * its indirect dependencies to simulate old-style linking. XXX - Should
9628 * check for duplicates.
9629 */
9630 if (!hasKPIDependency) {
9631 unsigned int i;
9632
9633 flags.hasBleedthrough = true;
9634
9635 count = getNumDependencies();
9636
9637 /* We add to the dependencies array in this loop, but do not iterate
9638 * past its original count.
9639 */
9640 for (i = 0; i < count; i++) {
9641 OSKext * dependencyKext = OSDynamicCast(OSKext,
9642 dependencies->getObject(i));
9643 dependencyKext->addBleedthroughDependencies(dependencies.get());
9644 }
9645 }
9646 #endif /* __LP64__ */
9647
9648 #if CONFIG_KXLD
9649 /*
9650 * If we're not dynamically linking kexts, then we don't need to check
9651 * copyright strings. The linker in user space has already done this.
9652 */
9653 if (hasPrivateKPIDependency) {
9654 bool hasApplePrefix = false;
9655 bool infoCopyrightIsValid = false;
9656 bool readableCopyrightIsValid = false;
9657
9658 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9659 APPLE_KEXT_PREFIX);
9660
9661 infoString = OSDynamicCast(OSString,
9662 getPropertyForHostArch("CFBundleGetInfoString"));
9663 if (infoString) {
9664 infoCopyrightIsValid =
9665 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9666 }
9667
9668 readableString = OSDynamicCast(OSString,
9669 getPropertyForHostArch("NSHumanReadableCopyright"));
9670 if (readableString) {
9671 readableCopyrightIsValid =
9672 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9673 }
9674
9675 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9676 OSKextLog(this,
9677 kOSKextLogErrorLevel |
9678 kOSKextLogDependenciesFlag,
9679 "Error - kext %s declares a dependency on %s. "
9680 "Only Apple kexts may declare a dependency on %s.",
9681 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9682 goto finish;
9683 }
9684 }
9685 #endif // CONFIG_KXLD
9686
9687 result = true;
9688 flags.hasAllDependencies = 1;
9689
9690 finish:
9691
9692 if (addedToLoopStack) {
9693 count = loopStack->getCount();
9694 if (count > 0 && (this == loopStack->getObject(count - 1))) {
9695 loopStack->removeObject(count - 1);
9696 } else {
9697 OSKextLog(this,
9698 kOSKextLogErrorLevel |
9699 kOSKextLogDependenciesFlag,
9700 "Kext %s - internal error resolving dependencies.",
9701 getIdentifierCString());
9702 }
9703 }
9704
9705 if (result && localLoopStack) {
9706 OSKextLog(this,
9707 kOSKextLogStepLevel |
9708 kOSKextLogDependenciesFlag,
9709 "Kext %s successfully resolved dependencies.",
9710 getIdentifierCString());
9711 }
9712
9713 return result;
9714 }
9715
9716 /*********************************************************************
9717 *********************************************************************/
9718 bool
9719 OSKext::addBleedthroughDependencies(OSArray * anArray)
9720 {
9721 bool result = false;
9722 unsigned int dependencyIndex, dependencyCount;
9723
9724 dependencyCount = getNumDependencies();
9725
9726 for (dependencyIndex = 0;
9727 dependencyIndex < dependencyCount;
9728 dependencyIndex++) {
9729 OSKext * dependency = OSDynamicCast(OSKext,
9730 dependencies->getObject(dependencyIndex));
9731 if (!dependency) {
9732 OSKextLog(this,
9733 kOSKextLogErrorLevel |
9734 kOSKextLogDependenciesFlag,
9735 "Kext %s - internal error propagating compatibility dependencies.",
9736 getIdentifierCString());
9737 goto finish;
9738 }
9739 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
9740 anArray->setObject(dependency);
9741 }
9742 dependency->addBleedthroughDependencies(anArray);
9743 }
9744
9745 result = true;
9746
9747 finish:
9748 return result;
9749 }
9750
9751 /*********************************************************************
9752 *********************************************************************/
9753 bool
9754 OSKext::flushDependencies(bool forceFlag)
9755 {
9756 bool result = false;
9757
9758 /* Only clear the dependencies if the kext isn't loaded;
9759 * we need the info for loaded kexts to track references.
9760 */
9761 if (!isLoaded() || forceFlag) {
9762 if (dependencies) {
9763 // xxx - check level
9764 OSKextLog(this,
9765 kOSKextLogProgressLevel |
9766 kOSKextLogDependenciesFlag,
9767 "Kext %s flushing dependencies.",
9768 getIdentifierCString());
9769 dependencies.reset();
9770 }
9771 if (!isKernelComponent()) {
9772 flags.hasAllDependencies = 0;
9773 }
9774 result = true;
9775 }
9776
9777 return result;
9778 }
9779
9780 /*********************************************************************
9781 *********************************************************************/
9782 uint32_t
9783 OSKext::getNumDependencies(void)
9784 {
9785 if (!dependencies) {
9786 return 0;
9787 }
9788 return dependencies->getCount();
9789 }
9790
9791 /*********************************************************************
9792 *********************************************************************/
9793 OSArray *
9794 OSKext::getDependencies(void)
9795 {
9796 return dependencies.get();
9797 }
9798
9799 bool
9800 OSKext::hasDependency(const OSSymbol * depID)
9801 {
9802 bool result __block;
9803
9804 if (depID == getIdentifier()) {
9805 return true;
9806 }
9807 if (!dependencies) {
9808 return false;
9809 }
9810 result = false;
9811 dependencies->iterateObjects(^bool (OSObject * obj) {
9812 OSKext * kext;
9813 kext = OSDynamicCast(OSKext, obj);
9814 if (!kext) {
9815 return false;
9816 }
9817 result = (depID == kext->getIdentifier());
9818 return result;
9819 });
9820 return result;
9821 }
9822
9823 #if PRAGMA_MARK
9824 #pragma mark OSMetaClass Support
9825 #endif
9826 /*********************************************************************
9827 *********************************************************************/
9828 OSReturn
9829 OSKext::addClass(
9830 OSMetaClass * aClass,
9831 uint32_t numClasses)
9832 {
9833 OSReturn result = kOSMetaClassNoInsKModSet;
9834
9835 if (!metaClasses) {
9836 metaClasses = OSSet::withCapacity(numClasses);
9837 if (!metaClasses) {
9838 goto finish;
9839 }
9840 }
9841
9842 if (metaClasses->containsObject(aClass)) {
9843 OSKextLog(this,
9844 kOSKextLogWarningLevel |
9845 kOSKextLogLoadFlag,
9846 "Notice - kext %s has already registered class %s.",
9847 getIdentifierCString(),
9848 aClass->getClassName());
9849 result = kOSReturnSuccess;
9850 goto finish;
9851 }
9852
9853 if (!metaClasses->setObject(aClass)) {
9854 goto finish;
9855 } else {
9856 OSKextLog(this,
9857 kOSKextLogDetailLevel |
9858 kOSKextLogLoadFlag,
9859 "Kext %s registered class %s.",
9860 getIdentifierCString(),
9861 aClass->getClassName());
9862 }
9863
9864 if (!flags.autounloadEnabled) {
9865 const OSMetaClass * metaScan = NULL; // do not release
9866
9867 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9868 if (metaScan == OSTypeID(IOService)) {
9869 OSKextLog(this,
9870 kOSKextLogProgressLevel |
9871 kOSKextLogLoadFlag,
9872 "Kext %s has IOService subclass %s; enabling autounload.",
9873 getIdentifierCString(),
9874 aClass->getClassName());
9875
9876 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9877 break;
9878 }
9879 }
9880 }
9881
9882 notifyAddClassObservers(this, aClass, flags);
9883
9884 result = kOSReturnSuccess;
9885
9886 finish:
9887 if (result != kOSReturnSuccess) {
9888 OSKextLog(this,
9889 kOSKextLogErrorLevel |
9890 kOSKextLogLoadFlag,
9891 "Kext %s failed to register class %s.",
9892 getIdentifierCString(),
9893 aClass->getClassName());
9894 }
9895
9896 return result;
9897 }
9898
9899 /*********************************************************************
9900 *********************************************************************/
9901 OSReturn
9902 OSKext::removeClass(
9903 OSMetaClass * aClass)
9904 {
9905 OSReturn result = kOSMetaClassNoKModSet;
9906
9907 if (!metaClasses) {
9908 goto finish;
9909 }
9910
9911 if (!metaClasses->containsObject(aClass)) {
9912 OSKextLog(this,
9913 kOSKextLogWarningLevel |
9914 kOSKextLogLoadFlag,
9915 "Notice - kext %s asked to unregister unknown class %s.",
9916 getIdentifierCString(),
9917 aClass->getClassName());
9918 result = kOSReturnSuccess;
9919 goto finish;
9920 }
9921
9922 OSKextLog(this,
9923 kOSKextLogDetailLevel |
9924 kOSKextLogLoadFlag,
9925 "Kext %s unregistering class %s.",
9926 getIdentifierCString(),
9927 aClass->getClassName());
9928
9929 metaClasses->removeObject(aClass);
9930
9931 notifyRemoveClassObservers(this, aClass, flags);
9932
9933 result = kOSReturnSuccess;
9934
9935 finish:
9936 if (result != kOSReturnSuccess) {
9937 OSKextLog(this,
9938 kOSKextLogErrorLevel |
9939 kOSKextLogLoadFlag,
9940 "Failed to unregister kext %s class %s.",
9941 getIdentifierCString(),
9942 aClass->getClassName());
9943 }
9944 return result;
9945 }
9946
9947 /*********************************************************************
9948 *********************************************************************/
9949 OSSet *
9950 OSKext::getMetaClasses(void)
9951 {
9952 return metaClasses.get();
9953 }
9954
9955 /*********************************************************************
9956 *********************************************************************/
9957 bool
9958 OSKext::hasOSMetaClassInstances(void)
9959 {
9960 bool result = false;
9961 OSSharedPtr<OSCollectionIterator> classIterator;
9962 OSMetaClass * checkClass = NULL; // do not release
9963
9964 if (!metaClasses) {
9965 goto finish;
9966 }
9967
9968 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9969 if (!classIterator) {
9970 // xxx - log alloc failure?
9971 goto finish;
9972 }
9973 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9974 if (checkClass->getInstanceCount()) {
9975 result = true;
9976 goto finish;
9977 }
9978 }
9979
9980 finish:
9981 return result;
9982 }
9983
9984 /*********************************************************************
9985 *********************************************************************/
9986 /* static */
9987 void
9988 OSKext::reportOSMetaClassInstances(
9989 const char * kextIdentifier,
9990 OSKextLogSpec msgLogSpec)
9991 {
9992 OSSharedPtr<OSKext> theKext;
9993
9994 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9995 if (!theKext) {
9996 goto finish;
9997 }
9998
9999 theKext->reportOSMetaClassInstances(msgLogSpec);
10000 finish:
10001 return;
10002 }
10003
10004 /*********************************************************************
10005 *********************************************************************/
10006 void
10007 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
10008 {
10009 OSSharedPtr<OSCollectionIterator> classIterator;
10010 OSMetaClass * checkClass = NULL; // do not release
10011
10012 if (!metaClasses) {
10013 goto finish;
10014 }
10015
10016 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10017 if (!classIterator) {
10018 goto finish;
10019 }
10020 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10021 if (checkClass->getInstanceCount()) {
10022 OSKextLog(this,
10023 msgLogSpec,
10024 " Kext %s class %s has %d instance%s.",
10025 getIdentifierCString(),
10026 checkClass->getClassName(),
10027 checkClass->getInstanceCount(),
10028 checkClass->getInstanceCount() == 1 ? "" : "s");
10029 }
10030 }
10031
10032 finish:
10033 return;
10034 }
10035
10036 #if PRAGMA_MARK
10037 #pragma mark User-Space Requests
10038 #endif
10039
10040 static kern_return_t
10041 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
10042 {
10043 OSReturn result = kOSReturnSuccess;
10044 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
10045 OSDictionary * request = NULL; //do not release
10046 IOUserServerCheckInToken * token = NULL; //do not release
10047 OSString * requestPredicate = NULL; //do not release
10048 OSSharedPtr<OSNumber> portNameNumber;
10049 mach_port_name_t portName = 0;
10050 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
10051 if (!request) {
10052 OSKextLog(/* kext */ NULL,
10053 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10054 "Elements of request should be of type OSDictionary");
10055 result = kOSKextReturnInternalError;
10056 goto finish;
10057 }
10058 requestPredicate = _OSKextGetRequestPredicate(request);
10059 if (!requestPredicate) {
10060 OSKextLog(/* kext */ NULL,
10061 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10062 "Failed to get request predicate");
10063 result = kOSKextReturnInternalError;
10064 goto finish;
10065 }
10066 // is this a dext launch?
10067 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
10068 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
10069 if (!token) {
10070 OSKextLog(/* kext */ NULL,
10071 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10072 "Could not find a IOUserServerCheckInToken in daemon launch request.");
10073 result = kOSKextReturnInternalError;
10074 goto finish;
10075 }
10076 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
10077 if (portName == 0 || portName == MACH_PORT_DEAD) {
10078 OSKextLog(/* kext */ NULL,
10079 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10080 "Could not create send right for object.");
10081 result = kOSKextReturnInternalError;
10082 goto finish;
10083 }
10084 // Store the mach port name as a OSNumber
10085 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
10086 if (!portNameNumber) {
10087 OSKextLog(/* kext */ NULL,
10088 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10089 "Could not create OSNumber object.");
10090 result = kOSKextReturnNoMemory;
10091 goto finish;
10092 }
10093 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
10094 OSKextLog(/* kext */ NULL,
10095 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10096 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
10097 result = kOSKextReturnNoMemory;
10098 goto finish;
10099 }
10100 }
10101 finish:
10102 if (result != kOSReturnSuccess) {
10103 break;
10104 }
10105 }
10106 return result;
10107 }
10108
10109 bool
10110 OSKext::iokitDaemonActive()
10111 {
10112 bool result;
10113 IORecursiveLockLock(sKextLock);
10114 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10115 IORecursiveLockUnlock(sKextLock);
10116 return result;
10117 }
10118
10119 /*********************************************************************
10120 * XXX - this function is a big ugly mess
10121 *********************************************************************/
10122 /* static */
10123 OSReturn
10124 OSKext::handleRequest(
10125 host_priv_t hostPriv,
10126 OSKextLogSpec clientLogFilter,
10127 char * requestBuffer,
10128 uint32_t requestLength,
10129 char ** responseOut,
10130 uint32_t * responseLengthOut,
10131 char ** logInfoOut,
10132 uint32_t * logInfoLengthOut)
10133 {
10134 OSReturn result = kOSReturnError;
10135 kern_return_t kmem_result = KERN_FAILURE;
10136
10137 char * response = NULL; // returned by reference
10138 uint32_t responseLength = 0;
10139
10140 bool taskCanManageAllKCs = false;
10141 bool taskOnlyManagesBootKC = false;
10142
10143 OSSharedPtr<OSObject> parsedXML;
10144 OSDictionary * requestDict = NULL; // do not release
10145 OSSharedPtr<OSString> errorString;
10146
10147 OSSharedPtr<OSObject> responseObject;
10148
10149 OSSharedPtr<OSSerialize> serializer;
10150
10151 OSSharedPtr<OSArray> logInfoArray;
10152
10153 OSString * predicate = NULL; // do not release
10154 OSString * kextIdentifier = NULL; // do not release
10155 OSArray * kextIdentifiers = NULL; // do not release
10156 OSKext * theKext = NULL; // do not release
10157 OSBoolean * boolArg = NULL; // do not release
10158
10159
10160 IORecursiveLockLock(sKextLock);
10161
10162 if (responseOut) {
10163 *responseOut = NULL;
10164 *responseLengthOut = 0;
10165 }
10166 if (logInfoOut) {
10167 *logInfoOut = NULL;
10168 *logInfoLengthOut = 0;
10169 }
10170
10171 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
10172
10173 /* XML must be nul-terminated.
10174 */
10175 if (requestBuffer[requestLength - 1] != '\0') {
10176 OSKextLog(/* kext */ NULL,
10177 kOSKextLogErrorLevel |
10178 kOSKextLogIPCFlag,
10179 "Invalid request from user space (not nul-terminated).");
10180 result = kOSKextReturnBadData;
10181 goto finish;
10182 }
10183 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
10184 if (parsedXML) {
10185 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10186 }
10187 if (!requestDict) {
10188 const char * errorCString = "(unknown error)";
10189
10190 if (errorString && errorString->getCStringNoCopy()) {
10191 errorCString = errorString->getCStringNoCopy();
10192 } else if (parsedXML) {
10193 errorCString = "not a dictionary";
10194 }
10195 OSKextLog(/* kext */ NULL,
10196 kOSKextLogErrorLevel |
10197 kOSKextLogIPCFlag,
10198 "Error unserializing request from user space: %s.",
10199 errorCString);
10200 result = kOSKextReturnSerialization;
10201 goto finish;
10202 }
10203
10204 predicate = _OSKextGetRequestPredicate(requestDict);
10205 if (!predicate) {
10206 OSKextLog(/* kext */ NULL,
10207 kOSKextLogErrorLevel |
10208 kOSKextLogIPCFlag,
10209 "Recieved kext request from user space with no predicate.");
10210 result = kOSKextReturnInvalidArgument;
10211 goto finish;
10212 }
10213 OSKextLog(/* kext */ NULL,
10214 kOSKextLogDebugLevel |
10215 kOSKextLogIPCFlag,
10216 "Received '%s' request from user space.",
10217 predicate->getCStringNoCopy());
10218
10219 /*
10220 * All management of file sets requires an entitlement
10221 */
10222 result = kOSKextReturnNotPrivileged;
10223 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10224 predicate->isEqualTo(kKextRequestPredicateStart) ||
10225 predicate->isEqualTo(kKextRequestPredicateStop) ||
10226 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10227 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10228 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10229 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10230 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10231 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10232 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10233 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10234 if (!iokitDaemonAvailable()) {
10235 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10236 }
10237 if (hostPriv == HOST_PRIV_NULL) {
10238 OSKextLog(/* kext */ NULL,
10239 kOSKextLogErrorLevel |
10240 kOSKextLogIPCFlag,
10241 "Access Failure - must be root user.");
10242 goto finish;
10243 }
10244 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10245 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10246
10247 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10248 OSKextLog(/* kext */ NULL,
10249 kOSKextLogErrorLevel |
10250 kOSKextLogIPCFlag,
10251 "Access Failure - client not entitled to manage file sets.");
10252 goto finish;
10253 }
10254
10255 /*
10256 * The OnlyBootKC entitlement restricts the
10257 * collection-management entitlement to only managing kexts in
10258 * the BootKC. All other predicates that alter global state or
10259 * add new KCs are disallowed.
10260 */
10261 if (taskOnlyManagesBootKC &&
10262 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10263 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10264 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10265 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10266 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10267 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10268 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10269 OSKextLog(/* kext */ NULL,
10270 kOSKextLogErrorLevel |
10271 kOSKextLogIPCFlag,
10272 "Access Failure - client not entitled to manage non-primary KCs");
10273 goto finish;
10274 }
10275
10276 /*
10277 * If we get here, then the process either has the full KC
10278 * management entitlement, or it has the BootKC-only
10279 * entitlement and the request is about the BootKC.
10280 */
10281 }
10282
10283 /* Get common args in anticipation of use.
10284 */
10285 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10286 requestDict, kKextRequestArgumentBundleIdentifierKey));
10287 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10288 requestDict, kKextRequestArgumentBundleIdentifierKey));
10289 if (kextIdentifier) {
10290 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10291 }
10292 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10293 requestDict, kKextRequestArgumentValueKey));
10294
10295 if (taskOnlyManagesBootKC &&
10296 theKext &&
10297 theKext->isInFileset() &&
10298 theKext->kc_type != KCKindPrimary) {
10299 OSKextLog(/* kext */ NULL,
10300 kOSKextLogErrorLevel |
10301 kOSKextLogIPCFlag,
10302 "Access Failure - client not entitled to manage kext in non-primary KC");
10303 result = kOSKextReturnNotPrivileged;
10304 goto finish;
10305 }
10306 result = kOSKextReturnInvalidArgument;
10307
10308 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10309 if (!kextIdentifier) {
10310 OSKextLog(/* kext */ NULL,
10311 kOSKextLogErrorLevel |
10312 kOSKextLogIPCFlag,
10313 "Invalid arguments to kext start request.");
10314 } else if (!theKext) {
10315 OSKextLog(/* kext */ NULL,
10316 kOSKextLogErrorLevel |
10317 kOSKextLogIPCFlag,
10318 "Kext %s not found for start request.",
10319 kextIdentifier->getCStringNoCopy());
10320 result = kOSKextReturnNotFound;
10321 } else {
10322 result = theKext->start();
10323 }
10324 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10325 if (!kextIdentifier) {
10326 OSKextLog(/* kext */ NULL,
10327 kOSKextLogErrorLevel |
10328 kOSKextLogIPCFlag,
10329 "Invalid arguments to kext stop request.");
10330 } else if (!theKext) {
10331 OSKextLog(/* kext */ NULL,
10332 kOSKextLogErrorLevel |
10333 kOSKextLogIPCFlag,
10334 "Kext %s not found for stop request.",
10335 kextIdentifier->getCStringNoCopy());
10336 result = kOSKextReturnNotFound;
10337 } else {
10338 result = theKext->stop();
10339 }
10340 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10341 result = OSKext::setMissingAuxKCBundles(requestDict);
10342 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10343 if (!kextIdentifier) {
10344 OSKextLog(/* kext */ NULL,
10345 kOSKextLogErrorLevel |
10346 kOSKextLogIPCFlag,
10347 "Invalid arguments to AuxKC Bundle Available request.");
10348 } else {
10349 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10350 }
10351 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10352 if (!kextIdentifier) {
10353 OSKextLog(/* kext */ NULL,
10354 kOSKextLogErrorLevel |
10355 kOSKextLogIPCFlag,
10356 "Invalid arguments to kext load from KC request.");
10357 } else if (!theKext) {
10358 OSKextLog(/* kext */ NULL,
10359 kOSKextLogErrorLevel |
10360 kOSKextLogIPCFlag,
10361 "Kext %s not found for load from KC request.",
10362 kextIdentifier->getCStringNoCopy());
10363 result = kOSKextReturnNotFound;
10364 } else if (!theKext->isInFileset()) {
10365 OSKextLog(/* kext */ NULL,
10366 kOSKextLogErrorLevel |
10367 kOSKextLogIPCFlag,
10368 "Kext %s does not exist in a KC: refusing to load.",
10369 kextIdentifier->getCStringNoCopy());
10370 result = kOSKextReturnNotLoadable;
10371 } else {
10372 result = OSKext::loadKextFromKC(theKext, requestDict);
10373 }
10374 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10375 if (!kextIdentifier) {
10376 OSKextLog(/* kext */ NULL,
10377 kOSKextLogErrorLevel |
10378 kOSKextLogIPCFlag,
10379 "Invalid arguments to codeless kext load interface (missing identifier).");
10380 } else {
10381 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10382 }
10383 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10384 if (!kextIdentifier) {
10385 OSKextLog(/* kext */ NULL,
10386 kOSKextLogErrorLevel |
10387 kOSKextLogIPCFlag,
10388 "Invalid arguments to kext unload request.");
10389 } else if (!theKext) {
10390 OSKextLog(/* kext */ NULL,
10391 kOSKextLogErrorLevel |
10392 kOSKextLogIPCFlag,
10393 "Kext %s not found for unload request.",
10394 kextIdentifier->getCStringNoCopy());
10395 result = kOSKextReturnNotFound;
10396 } else {
10397 if (theKext->isDriverKit()) {
10398 result = OSKext::removeDext(theKext);
10399 } else {
10400 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10401 _OSKextGetRequestArgument(requestDict,
10402 kKextRequestArgumentTerminateIOServicesKey));
10403 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
10404 }
10405 }
10406 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10407 result = OSKext::dispatchResource(requestDict);
10408 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10409 OSNumber *lookupNum = NULL;
10410 lookupNum = OSDynamicCast(OSNumber,
10411 _OSKextGetRequestArgument(requestDict,
10412 kKextRequestArgumentLookupAddressKey));
10413
10414 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
10415 if (responseObject) {
10416 result = kOSReturnSuccess;
10417 } else {
10418 goto finish;
10419 }
10420 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10421 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10422 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10423 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10424 OSBoolean * delayAutounloadBool = NULL;
10425 OSObject * infoKeysRaw = NULL;
10426 OSArray * infoKeys = NULL;
10427 uint32_t infoKeysCount = 0;
10428
10429 delayAutounloadBool = OSDynamicCast(OSBoolean,
10430 _OSKextGetRequestArgument(requestDict,
10431 kKextRequestArgumentDelayAutounloadKey));
10432
10433 /* If asked to delay autounload, reset the timer if it's currently set.
10434 * (That is, don't schedule an unload if one isn't already pending.
10435 */
10436 if (delayAutounloadBool == kOSBooleanTrue) {
10437 OSKext::considerUnloads(/* rescheduleOnly? */ true);
10438 }
10439
10440 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10441 kKextRequestArgumentInfoKeysKey);
10442 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10443 if (infoKeysRaw && !infoKeys) {
10444 OSKextLog(/* kext */ NULL,
10445 kOSKextLogErrorLevel |
10446 kOSKextLogIPCFlag,
10447 "Invalid arguments to kext info request.");
10448 goto finish;
10449 }
10450
10451 if (infoKeys) {
10452 infoKeysCount = infoKeys->getCount();
10453 for (uint32_t i = 0; i < infoKeysCount; i++) {
10454 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10455 OSKextLog(/* kext */ NULL,
10456 kOSKextLogErrorLevel |
10457 kOSKextLogIPCFlag,
10458 "Invalid arguments to kext info request.");
10459 goto finish;
10460 }
10461 }
10462 }
10463
10464 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10465 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
10466 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10467 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
10468 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10469 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10470 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10471 responseObject = OSKext::copyDextsInfo(kextIdentifiers, infoKeys);
10472 }
10473
10474 if (!responseObject) {
10475 result = kOSKextReturnInternalError;
10476 } else {
10477 OSKextLog(/* kext */ NULL,
10478 kOSKextLogDebugLevel |
10479 kOSKextLogIPCFlag,
10480 "Returning loaded kext info.");
10481 result = kOSReturnSuccess;
10482 }
10483 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10484 /* Hand the current sKernelRequests array to the caller
10485 * (who must release it), and make a new one.
10486 */
10487 responseObject = os::move(sKernelRequests);
10488 sKernelRequests = OSArray::withCapacity(0);
10489 sPostedKextLoadIdentifiers->flushCollection();
10490 OSKextLog(/* kext */ NULL,
10491 kOSKextLogDebugLevel |
10492 kOSKextLogIPCFlag,
10493 "Returning kernel requests.");
10494 result = kOSReturnSuccess;
10495 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10496 /* Return the set of all requested bundle identifiers */
10497 responseObject = sAllKextLoadIdentifiers;
10498 OSKextLog(/* kext */ NULL,
10499 kOSKextLogDebugLevel |
10500 kOSKextLogIPCFlag,
10501 "Returning load requests.");
10502 result = kOSReturnSuccess;
10503 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10504 printf("KextLog: Loading FileSet KC(s)\n");
10505 result = OSKext::loadFileSetKexts(requestDict);
10506 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10507 bool active = iokitDaemonActive();
10508 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10509 if (sOSKextWasResetAfterUserspaceReboot) {
10510 printf("KextLog: was reset after userspace reboot\n");
10511 }
10512 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10513 } else {
10514 OSKextLog(/* kext */ NULL,
10515 kOSKextLogDebugLevel |
10516 kOSKextLogIPCFlag,
10517 "Received '%s' invalid request from user space.",
10518 predicate->getCStringNoCopy());
10519 goto finish;
10520 }
10521
10522 /**********
10523 * Now we have handle the request, or not. Gather up the response & logging
10524 * info to ship to user space.
10525 *********/
10526
10527 /* Note: Nothing in OSKext is supposed to retain requestDict,
10528 * but you never know....
10529 */
10530 if (requestDict->getRetainCount() > 1) {
10531 OSKextLog(/* kext */ NULL,
10532 kOSKextLogWarningLevel |
10533 kOSKextLogIPCFlag,
10534 "Request from user space still retained by a kext; "
10535 "probable memory leak.");
10536 }
10537
10538 if (responseOut && responseObject) {
10539 serializer = OSSerialize::withCapacity(0);
10540 if (!serializer) {
10541 result = kOSKextReturnNoMemory;
10542 goto finish;
10543 }
10544 /*
10545 * Before serializing the kernel requests, patch the dext launch requests so
10546 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10547 * IOUserServerCheckInToken kernel object.
10548 */
10549 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10550 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10551 task_t calling_task = current_task();
10552 if (!requests) {
10553 OSKextLog(/* kext */ NULL,
10554 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10555 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10556 result = kOSKextReturnInternalError;
10557 goto finish;
10558 }
10559 result = patchDextLaunchRequests(calling_task, requests);
10560 if (result != kOSReturnSuccess) {
10561 OSKextLog(/* kext */ NULL,
10562 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10563 "Failed to patch dext launch requests.");
10564 goto finish;
10565 }
10566 }
10567
10568 if (!responseObject->serialize(serializer.get())) {
10569 OSKextLog(/* kext */ NULL,
10570 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10571 "Failed to serialize response to request from user space.");
10572 result = kOSKextReturnSerialization;
10573 goto finish;
10574 }
10575
10576 response = (char *)serializer->text();
10577 responseLength = serializer->getLength();
10578 }
10579
10580 if (responseOut && response) {
10581 char * buffer;
10582
10583 /* This kmem_alloc sets the return value of the function.
10584 */
10585 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
10586 round_page(responseLength), KMA_DATA, VM_KERN_MEMORY_OSKEXT);
10587 if (kmem_result != KERN_SUCCESS) {
10588 OSKextLog(/* kext */ NULL,
10589 kOSKextLogErrorLevel |
10590 kOSKextLogIPCFlag,
10591 "Failed to copy response to request from user space.");
10592 result = kmem_result;
10593 goto finish;
10594 } else {
10595 /* 11981737 - clear uninitialized data in last page */
10596 bzero((void *)(buffer + responseLength),
10597 (round_page(responseLength) - responseLength));
10598 memcpy(buffer, response, responseLength);
10599 *responseOut = buffer;
10600 *responseLengthOut = responseLength;
10601 }
10602 }
10603
10604 finish:
10605
10606 /* Gather up the collected log messages for user space. Any messages
10607 * messages past this call will not make it up as log messages but
10608 * will be in the system log. Note that we ignore the return of the
10609 * serialize; it has no bearing on the operation at hand even if we
10610 * fail to get the log messages.
10611 */
10612 logInfoArray = OSKext::clearUserSpaceLogFilter();
10613
10614 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10615 (void)OSKext::serializeLogInfo(logInfoArray.get(),
10616 logInfoOut, logInfoLengthOut);
10617 }
10618
10619 IORecursiveLockUnlock(sKextLock);
10620
10621 return result;
10622 }
10623
10624 #if PRAGMA_MARK
10625 #pragma mark Linked Kext Collection Support
10626 #endif
10627
10628 static int
10629 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10630 {
10631 for (int i = 0; i < segCount; i++) {
10632 vm_offset_t segStart = segAddrs[i];
10633 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10634
10635 if (theAddr >= segStart && theAddr < segEnd) {
10636 return i;
10637 }
10638 }
10639 return -1;
10640 }
10641
10642 static void
10643 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
10644 kernel_segment_command_t *kextTextSeg,
10645 OSData *kaslrOffsets)
10646 {
10647 static const char *plk_segNames[] = {
10648 "__TEXT",
10649 "__TEXT_EXEC",
10650 "__DATA",
10651 "__DATA_CONST",
10652 "__LINKEDIT",
10653 "__PRELINK_TEXT",
10654 "__PLK_TEXT_EXEC",
10655 "__PRELINK_DATA",
10656 "__PLK_DATA_CONST",
10657 "__PLK_LLVM_COV",
10658 "__PLK_LINKEDIT",
10659 "__PRELINK_INFO"
10660 };
10661 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10662
10663 unsigned long plk_segSizes[num_plk_seg];
10664 vm_offset_t plk_segAddrs[num_plk_seg];
10665
10666 for (size_t i = 0; i < num_plk_seg; i++) {
10667 plk_segSizes[i] = 0;
10668 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10669 }
10670
10671 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10672
10673 int slidKextAddrCount = 0;
10674 int badSlideAddr = 0;
10675 int badSlideTarget = 0;
10676
10677 struct kaslrPackedOffsets {
10678 uint32_t count; /* number of offsets */
10679 uint32_t offsetsArray[]; /* offsets to slide */
10680 };
10681 const struct kaslrPackedOffsets *myOffsets = NULL;
10682 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10683
10684 for (uint32_t j = 0; j < myOffsets->count; j++) {
10685 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10686 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10687 int slideAddrSegIndex = -1;
10688 int addrToSlideSegIndex = -1;
10689
10690 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10691 if (slideAddrSegIndex >= 0) {
10692 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10693 if (addrToSlideSegIndex < 0) {
10694 badSlideTarget++;
10695 continue;
10696 }
10697 } else {
10698 badSlideAddr++;
10699 continue;
10700 }
10701
10702 slidKextAddrCount++;
10703 *slideAddr = ml_static_slide(*slideAddr);
10704 } // for ...
10705 }
10706
10707
10708
10709 /********************************************************************
10710 * addKextsFromKextCollection
10711 *
10712 * Input: MachO header of kext collection. The MachO is assumed to
10713 * have a section named 'info_seg_name,info_sect_name' that
10714 * contains a serialized XML info dictionary. This dictionary
10715 * contains a UUID, possibly a set of relocations (for older
10716 * kxld-built binaries), and an array of kext personalities.
10717 *
10718 ********************************************************************/
10719 bool
10720 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10721 OSDictionary *infoDict, const char *text_seg_name,
10722 OSData **kcUUID, kc_kind_t type)
10723 {
10724 bool result = false;
10725
10726 OSArray *kextArray = NULL; // do not release
10727 OSData *infoDictKCUUID = NULL; // do not release
10728 OSData *kaslrOffsets = NULL; // do not release
10729
10730 IORegistryEntry *registryRoot = NULL; // do not release
10731 OSSharedPtr<OSNumber> kcKextCount;
10732
10733 /* extract the KC UUID from the dictionary */
10734 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10735 if (infoDictKCUUID) {
10736 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10737 panic("kcUUID length is %d, expected %lu",
10738 infoDictKCUUID->getLength(), sizeof(uuid_t));
10739 }
10740 }
10741
10742 /* locate the array of kext dictionaries */
10743 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10744 if (!kextArray) {
10745 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10746 "The given KC has no kext info dictionaries");
10747 goto finish;
10748 }
10749
10750 /*
10751 * old-style KASLR offsets may be present in the info dictionary. If
10752 * we find them, use them and eventually slide them.
10753 */
10754 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10755
10756 /*
10757 * Before processing any kexts, locate the special kext bundle which
10758 * contains a list of kexts that we are to prevent from loading.
10759 */
10760 createExcludeListFromPrelinkInfo(kextArray);
10761
10762 /*
10763 * Create OSKext objects for each kext we find in the array of kext
10764 * info plist dictionaries.
10765 */
10766 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10767 OSDictionary *kextDict = NULL;
10768 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10769 if (!kextDict) {
10770 OSKextLog(/* kext */ NULL,
10771 kOSKextLogErrorLevel |
10772 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10773 "Kext info dictionary for kext #%d isn't a dictionary?", i);
10774 continue;
10775 }
10776
10777 /*
10778 * Create the kext for the entry, then release it, because the
10779 * kext system keeps a reference around until the kext is
10780 * explicitly removed. Any creation/registration failures are
10781 * already logged for us.
10782 */
10783 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
10784 }
10785
10786 /*
10787 * slide old-style kxld relocations
10788 * NOTE: this is still used on embedded KCs built with kcgen
10789 * TODO: Remove this once we use the new kext linker everywhere!
10790 */
10791 if (kaslrOffsets && vm_kernel_slide > 0) {
10792 kernel_segment_command_t *text_segment = NULL;
10793 text_segment = getsegbynamefromheader(mh, text_seg_name);
10794 if (!text_segment) {
10795 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10796 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10797 goto finish;
10798 }
10799
10800 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
10801 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10802 setAllVMAttributes();
10803 }
10804
10805 /* Store the number of prelinked kexts in the registry so we can tell
10806 * when the system has been started from a prelinked kernel.
10807 */
10808 registryRoot = IORegistryEntry::getRegistryRoot();
10809 assert(registryRoot);
10810
10811 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10812 assert(kcKextCount);
10813 if (kcKextCount) {
10814 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10815 OSNumber *num;
10816 num = OSDynamicCast(OSNumber, prop.get());
10817 if (num) {
10818 kcKextCount->addValue(num->unsigned64BitValue());
10819 }
10820 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10821 }
10822
10823 OSKextLog(/* kext */ NULL,
10824 kOSKextLogProgressLevel |
10825 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10826 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10827 "%u prelinked kexts", infoDict->getCount());
10828
10829
10830 if (kcUUID && infoDictKCUUID) {
10831 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10832 }
10833
10834 result = true;
10835
10836 finish:
10837 return result;
10838 }
10839
10840 bool
10841 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10842 OSDictionary *infoDict, const char *text_seg_name,
10843 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10844 {
10845 OSData *result = NULL;
10846 bool success = addKextsFromKextCollection(mh,
10847 infoDict,
10848 text_seg_name,
10849 &result,
10850 type);
10851 if (success) {
10852 kcUUID.reset(result, OSNoRetain);
10853 }
10854 return success;
10855 }
10856
10857 static OSSharedPtr<OSObject> deferredAuxKCXML;
10858 bool
10859 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10860 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10861 {
10862 if (type != KCKindAuxiliary) {
10863 return false;
10864 }
10865
10866 kernel_mach_header_t *_mh;
10867 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
10868 if (!_mh || _mh != mh) {
10869 return false;
10870 }
10871
10872 if (deferredAuxKCXML) {
10873 /* only allow this to be called once */
10874 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10875 "An Aux KC has already been registered for deferred processing.");
10876 return false;
10877 }
10878
10879 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
10880 if (!infoDict) {
10881 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10882 "The Aux KC has info dictionary");
10883 return false;
10884 }
10885
10886 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10887 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10888 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10889 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10890 return false;
10891 }
10892
10893 /*
10894 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10895 * sysctl can return the UUID to user space which will check this
10896 * value for errors.
10897 */
10898 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10899 kcUUID->getLength());
10900 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10901 auxkc_uuid_valid = TRUE;
10902
10903 deferredAuxKCXML = parsedXML;
10904
10905 return true;
10906 }
10907
10908 OSSharedPtr<OSObject>
10909 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10910 {
10911 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10912 return NULL;
10913 }
10914
10915 return os::move(deferredAuxKCXML);
10916 }
10917
10918 #if PRAGMA_MARK
10919 #pragma mark Profile-Guided-Optimization Support
10920 #endif
10921
10922 // #include <InstrProfiling.h>
10923 extern "C" {
10924 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10925 const char *DataEnd,
10926 const char *CountersBegin,
10927 const char *CountersEnd,
10928 const char *NamesBegin,
10929 const char *NamesEnd);
10930 int __llvm_profile_write_buffer_internal(char *Buffer,
10931 const char *DataBegin,
10932 const char *DataEnd,
10933 const char *CountersBegin,
10934 const char *CountersEnd,
10935 const char *NamesBegin,
10936 const char *NamesEnd);
10937 }
10938
10939
10940 static
10941 void
10942 OSKextPgoMetadataPut(char *pBuffer,
10943 size_t *position,
10944 size_t bufferSize,
10945 uint32_t *num_pairs,
10946 const char *key,
10947 const char *value)
10948 {
10949 size_t strlen_key = strlen(key);
10950 size_t strlen_value = strlen(value);
10951 size_t len = strlen(key) + 1 + strlen(value) + 1;
10952 char *pos = pBuffer + *position;
10953 *position += len;
10954 if (pBuffer && bufferSize && *position <= bufferSize) {
10955 memcpy(pos, key, strlen_key); pos += strlen_key;
10956 *(pos++) = '=';
10957 memcpy(pos, value, strlen_value); pos += strlen_value;
10958 *(pos++) = 0;
10959 if (num_pairs) {
10960 (*num_pairs)++;
10961 }
10962 }
10963 }
10964
10965
10966 static
10967 void
10968 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10969 {
10970 *position += strlen(key) + 1 + value_max + 1;
10971 }
10972
10973
10974 static
10975 void
10976 OSKextPgoMetadataPutAll(OSKext *kext,
10977 uuid_t instance_uuid,
10978 char *pBuffer,
10979 size_t *position,
10980 size_t bufferSize,
10981 uint32_t *num_pairs)
10982 {
10983 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10984 //log_10 2^16 ≈ 4.82
10985 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10986 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10987
10988 if (!pBuffer) {
10989 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10990 OSKextPgoMetadataPutMax(position, "UUID", 36);
10991 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10992 } else {
10993 uuid_string_t instance_uuid_string;
10994 uuid_unparse(instance_uuid, instance_uuid_string);
10995 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10996 "INSTANCE", instance_uuid_string);
10997
10998 OSSharedPtr<OSData> uuid_data;
10999 uuid_t uuid;
11000 uuid_string_t uuid_string;
11001 uuid_data = kext->copyUUID();
11002 if (uuid_data) {
11003 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
11004 uuid_unparse(uuid, uuid_string);
11005 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11006 "UUID", uuid_string);
11007 }
11008
11009 clock_sec_t secs;
11010 clock_usec_t usecs;
11011 clock_get_calendar_microtime(&secs, &usecs);
11012 assert(usecs < 1000000);
11013 char timestamp[max_timestamp_string_size + 1];
11014 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
11015 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
11016 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11017 "TIMESTAMP", timestamp);
11018 }
11019
11020 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11021 "NAME", kext->getIdentifierCString());
11022
11023 char versionCString[kOSKextVersionMaxLength];
11024 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
11025 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11026 "VERSION", versionCString);
11027 }
11028
11029 static
11030 size_t
11031 OSKextPgoMetadataSize(OSKext *kext)
11032 {
11033 size_t position = 0;
11034 uuid_t fakeuuid = {};
11035 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
11036 return position;
11037 }
11038
11039 int
11040 OSKextGrabPgoDataLocked(OSKext *kext,
11041 bool metadata,
11042 uuid_t instance_uuid,
11043 uint64_t *pSize,
11044 char *pBuffer,
11045 uint64_t bufferSize)
11046 {
11047 int err = 0;
11048
11049 kernel_section_t *sect_prf_data = NULL;
11050 kernel_section_t *sect_prf_name = NULL;
11051 kernel_section_t *sect_prf_cnts = NULL;
11052 uint64_t size;
11053 size_t metadata_size = 0;
11054 size_t offset_to_pairs = 0;
11055
11056 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
11057 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
11058 if (!sect_prf_name) {
11059 // kextcache sometimes truncates the section name to 15 chars
11060 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
11061 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
11062 }
11063 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11064
11065 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
11066 err = ENOTSUP;
11067 goto out;
11068 }
11069
11070 size = __llvm_profile_get_size_for_buffer_internal(
11071 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11072 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11073 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11074
11075 if (metadata) {
11076 metadata_size = OSKextPgoMetadataSize(kext);
11077 size += metadata_size;
11078 size += sizeof(pgo_metadata_footer);
11079 }
11080
11081
11082 if (pSize) {
11083 *pSize = size;
11084 }
11085
11086 if (pBuffer && bufferSize) {
11087 if (bufferSize < size) {
11088 err = ERANGE;
11089 goto out;
11090 }
11091
11092 err = __llvm_profile_write_buffer_internal(
11093 pBuffer,
11094 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11095 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11096 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11097
11098 if (err) {
11099 err = EIO;
11100 goto out;
11101 }
11102
11103 if (metadata) {
11104 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11105 if (offset_to_pairs > UINT32_MAX) {
11106 err = E2BIG;
11107 goto out;
11108 }
11109
11110 char *end_of_buffer = pBuffer + size;
11111 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11112 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11113
11114 size_t metadata_position = 0;
11115 uint32_t num_pairs = 0;
11116 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
11117 while (metadata_position < metadata_size) {
11118 metadata_buffer[metadata_position++] = 0;
11119 }
11120
11121 struct pgo_metadata_footer footer;
11122 footer.magic = htonl(0x6d657461);
11123 footer.number_of_pairs = htonl( num_pairs );
11124 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11125 memcpy(footerp, &footer, sizeof(footer));
11126 }
11127 }
11128
11129 out:
11130 return err;
11131 }
11132
11133
11134 int
11135 OSKextGrabPgoData(uuid_t uuid,
11136 uint64_t *pSize,
11137 char *pBuffer,
11138 uint64_t bufferSize,
11139 int wait_for_unload,
11140 int metadata)
11141 {
11142 int err = 0;
11143 OSSharedPtr<OSKext> kext;
11144
11145
11146 IORecursiveLockLock(sKextLock);
11147
11148 kext = OSKext::lookupKextWithUUID(uuid);
11149 if (!kext) {
11150 err = ENOENT;
11151 goto out;
11152 }
11153
11154 if (wait_for_unload) {
11155 OSKextGrabPgoStruct s;
11156
11157 s.metadata = metadata;
11158 s.pSize = pSize;
11159 s.pBuffer = pBuffer;
11160 s.bufferSize = bufferSize;
11161 s.err = EINTR;
11162
11163 struct list_head *prev = &kext->pendingPgoHead;
11164 struct list_head *next = kext->pendingPgoHead.next;
11165
11166 s.list_head.prev = prev;
11167 s.list_head.next = next;
11168
11169 prev->next = &s.list_head;
11170 next->prev = &s.list_head;
11171
11172 kext.reset();
11173
11174 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
11175
11176 prev = s.list_head.prev;
11177 next = s.list_head.next;
11178
11179 prev->next = next;
11180 next->prev = prev;
11181
11182 err = s.err;
11183 } else {
11184 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
11185 }
11186
11187 out:
11188
11189 IORecursiveLockUnlock(sKextLock);
11190
11191 return err;
11192 }
11193
11194 void
11195 OSKextResetPgoCountersLock()
11196 {
11197 IORecursiveLockLock(sKextLock);
11198 }
11199
11200 void
11201 OSKextResetPgoCountersUnlock()
11202 {
11203 IORecursiveLockUnlock(sKextLock);
11204 }
11205
11206
11207 extern unsigned int not_in_kdp;
11208
11209 void
11210 OSKextResetPgoCounters()
11211 {
11212 assert(!not_in_kdp);
11213 uint32_t count = sLoadedKexts->getCount();
11214 for (uint32_t i = 0; i < count; i++) {
11215 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11216 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11217 if (!sect_prf_cnts) {
11218 continue;
11219 }
11220 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
11221 }
11222 }
11223
11224 OSSharedPtr<OSDictionary>
11225 OSKext::copyLoadedKextInfoByUUID(
11226 OSArray * kextIdentifiers,
11227 OSArray * infoKeys)
11228 {
11229 OSSharedPtr<OSDictionary> result;
11230 OSSharedPtr<OSDictionary> kextInfo;
11231 uint32_t max_count, i, j;
11232 uint32_t idCount = 0;
11233 uint32_t idIndex = 0;
11234 IORecursiveLockLock(sKextLock);
11235 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11236 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11237
11238 #if CONFIG_MACF
11239 /* Is the calling process allowed to query kext info? */
11240 if (current_task() != kernel_task) {
11241 int macCheckResult = 0;
11242 kauth_cred_t cred = NULL;
11243
11244 cred = kauth_cred_get_with_ref();
11245 macCheckResult = mac_kext_check_query(cred);
11246 kauth_cred_unref(&cred);
11247
11248 if (macCheckResult != 0) {
11249 OSKextLog(/* kext */ NULL,
11250 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11251 "Failed to query kext info (MAC policy error 0x%x).",
11252 macCheckResult);
11253 goto finish;
11254 }
11255 }
11256 #endif
11257
11258 /* Empty list of UUIDs is equivalent to no list (get all).
11259 */
11260 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11261 kextIdentifiers = NULL;
11262 } else if (kextIdentifiers) {
11263 idCount = kextIdentifiers->getCount();
11264 }
11265
11266 /* Same for keys.
11267 */
11268 if (infoKeys && !infoKeys->getCount()) {
11269 infoKeys = NULL;
11270 }
11271
11272 max_count = count[0] + count[1];
11273 result = OSDictionary::withCapacity(max_count);
11274 if (!result) {
11275 goto finish;
11276 }
11277
11278 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11279 for (i = 0; i < count[j]; i++) {
11280 OSKext *thisKext = NULL; // do not release
11281 Boolean includeThis = true;
11282 uuid_t thisKextUUID;
11283 uuid_t thisKextTextUUID;
11284 OSSharedPtr<OSData> uuid_data;
11285 uuid_string_t uuid_key;
11286
11287 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11288 if (!thisKext) {
11289 continue;
11290 }
11291
11292 uuid_data = thisKext->copyUUID();
11293 if (!uuid_data) {
11294 continue;
11295 }
11296
11297 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
11298
11299 uuid_unparse(thisKextUUID, uuid_key);
11300
11301 uuid_data = thisKext->copyTextUUID();
11302 if (!uuid_data) {
11303 continue;
11304 }
11305 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
11306
11307 /* Skip current kext if we have a list of UUIDs and
11308 * it isn't in the list.
11309 */
11310 if (kextIdentifiers) {
11311 includeThis = false;
11312
11313 for (idIndex = 0; idIndex < idCount; idIndex++) {
11314 const OSString* wantedUUID = OSDynamicCast(OSString,
11315 kextIdentifiers->getObject(idIndex));
11316
11317 uuid_t uuid;
11318 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
11319
11320 if ((0 == uuid_compare(uuid, thisKextUUID))
11321 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
11322 includeThis = true;
11323 /* Only need to find the first kext if multiple match,
11324 * ie. asking for the kernel uuid does not need to find
11325 * interface kexts or builtin static kexts.
11326 */
11327 kextIdentifiers->removeObject(idIndex);
11328 uuid_unparse(uuid, uuid_key);
11329 break;
11330 }
11331 }
11332 }
11333
11334 if (!includeThis) {
11335 continue;
11336 }
11337
11338 kextInfo = thisKext->copyInfo(infoKeys);
11339 if (kextInfo) {
11340 result->setObject(uuid_key, kextInfo.get());
11341 }
11342
11343 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11344 goto finish;
11345 }
11346 }
11347 }
11348
11349 finish:
11350 IORecursiveLockUnlock(sKextLock);
11351
11352 return result;
11353 }
11354
11355 /*********************************************************************
11356 *********************************************************************/
11357 /* static */
11358 OSSharedPtr<OSDictionary>
11359 OSKext::copyKextCollectionInfo(
11360 OSDictionary *requestDict,
11361 OSArray *infoKeys)
11362 {
11363 OSSharedPtr<OSDictionary> result;
11364 OSString *collectionType = NULL;
11365 OSObject *rawLoadedState = NULL;
11366 OSString *loadedState = NULL;
11367
11368 kc_kind_t kc_request_kind = KCKindUnknown;
11369 bool onlyLoaded = false;
11370 bool onlyUnloaded = false;
11371
11372 #if CONFIG_MACF
11373 /* Is the calling process allowed to query kext info? */
11374 if (current_task() != kernel_task) {
11375 int macCheckResult = 0;
11376 kauth_cred_t cred = NULL;
11377
11378 cred = kauth_cred_get_with_ref();
11379 macCheckResult = mac_kext_check_query(cred);
11380 kauth_cred_unref(&cred);
11381
11382 if (macCheckResult != 0) {
11383 OSKextLog(/* kext */ NULL,
11384 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11385 "Failed to query kext info (MAC policy error 0x%x).",
11386 macCheckResult);
11387 goto finish;
11388 }
11389 }
11390 #endif
11391
11392 if (infoKeys && !infoKeys->getCount()) {
11393 infoKeys = NULL;
11394 }
11395
11396 collectionType = OSDynamicCast(OSString,
11397 _OSKextGetRequestArgument(requestDict,
11398 kKextRequestArgumentCollectionTypeKey));
11399 if (!collectionType) {
11400 OSKextLog(/* kext */ NULL,
11401 kOSKextLogErrorLevel |
11402 kOSKextLogIPCFlag,
11403 "Invalid '%s' argument to kext collection info request.",
11404 kKextRequestArgumentCollectionTypeKey);
11405 goto finish;
11406 }
11407 if (collectionType->isEqualTo(kKCTypePrimary)) {
11408 kc_request_kind = KCKindPrimary;
11409 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11410 kc_request_kind = KCKindPageable;
11411 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11412 kc_request_kind = KCKindAuxiliary;
11413 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11414 kc_request_kind = KCKindNone;
11415 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11416 OSKextLog(/* kext */ NULL,
11417 kOSKextLogErrorLevel |
11418 kOSKextLogIPCFlag,
11419 "Invalid '%s' argument value '%s' to kext collection info request.",
11420 kKextRequestArgumentCollectionTypeKey,
11421 collectionType->getCStringNoCopy());
11422 goto finish;
11423 }
11424
11425 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11426 kKextRequestArgumentLoadedStateKey);
11427 if (rawLoadedState) {
11428 loadedState = OSDynamicCast(OSString, rawLoadedState);
11429 if (!loadedState) {
11430 OSKextLog(/* kext */ NULL,
11431 kOSKextLogErrorLevel |
11432 kOSKextLogIPCFlag,
11433 "Invalid '%s' argument to kext collection info request.",
11434 kKextRequestArgumentLoadedStateKey);
11435 goto finish;
11436 }
11437 }
11438 if (loadedState) {
11439 if (loadedState->isEqualTo("Loaded")) {
11440 onlyLoaded = true;
11441 } else if (loadedState->isEqualTo("Unloaded")) {
11442 onlyUnloaded = true;
11443 } else if (!loadedState->isEqualTo("Any")) {
11444 OSKextLog(/* kext */ NULL,
11445 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11446 "Invalid '%s' argument value '%s' for '%s' collection info",
11447 kKextRequestArgumentLoadedStateKey,
11448 loadedState->getCStringNoCopy(),
11449 collectionType->getCStringNoCopy());
11450 goto finish;
11451 }
11452 }
11453
11454 result = OSDictionary::withCapacity(sKextsByID->getCount());
11455 if (!result) {
11456 goto finish;
11457 }
11458
11459 IORecursiveLockLock(sKextLock);
11460 { // start block scope
11461 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11462 {
11463 OSKext *thisKext = NULL; // do not release
11464 OSSharedPtr<OSDictionary> kextInfo;
11465
11466 (void)thisKextID;
11467
11468 thisKext = OSDynamicCast(OSKext, obj);
11469 if (!thisKext) {
11470 return false;
11471 }
11472
11473 /*
11474 * skip the kext if it came from the wrong collection type
11475 * (and the caller requested a specific type)
11476 */
11477 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11478 return false;
11479 }
11480
11481 /*
11482 * respect the caller's desire to find only loaded or
11483 * unloaded kexts
11484 */
11485 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11486 return false;
11487 }
11488 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11489 return false;
11490 }
11491
11492 kextInfo = thisKext->copyInfo(infoKeys);
11493 if (kextInfo) {
11494 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11495 }
11496 return false;
11497 });
11498 } // end block scope
11499 IORecursiveLockUnlock(sKextLock);
11500
11501 finish:
11502 return result;
11503 }
11504
11505 /* static */
11506 OSSharedPtr<OSArray>
11507 OSKext::copyDextsInfo(
11508 OSArray *kextIdentifiers,
11509 OSArray *infoKeys)
11510 {
11511 OSSharedPtr<OSArray> result = NULL;
11512 uint32_t idCount = 0;
11513 bool getActive = false;
11514 bool getLoaded = false;
11515 bool getUnloaded = false;
11516 bool getPendingUpgrade = false;
11517 unsigned int avgDextCount = 0;
11518
11519 #if CONFIG_MACF
11520 /* Is the calling process allowed to query dext info? */
11521 if (current_task() != kernel_task) {
11522 int macCheckResult = 0;
11523 kauth_cred_t cred = NULL;
11524
11525 cred = kauth_cred_get_with_ref();
11526 macCheckResult = mac_kext_check_query(cred);
11527 kauth_cred_unref(&cred);
11528
11529 if (macCheckResult != 0) {
11530 OSKextLog(/* kext */ NULL,
11531 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11532 "Failed to query kext info (MAC policy error 0x%x).",
11533 macCheckResult);
11534 goto finish;
11535 }
11536 }
11537 #endif
11538 /*
11539 * No infoKeys means return everything we
11540 * know about the dexts.
11541 */
11542 if (infoKeys && !infoKeys->getCount()) {
11543 infoKeys = NULL;
11544 }
11545
11546 /*
11547 * Empty list of bundle ids is equivalent to
11548 * no list (get all).
11549 */
11550 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11551 kextIdentifiers = NULL;
11552 } else if (kextIdentifiers) {
11553 idCount = kextIdentifiers->getCount();
11554 }
11555
11556 /*
11557 * Caller can specify which state of dexts to query.
11558 */
11559 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveKey)) {
11560 getActive = true;
11561 }
11562 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11563 getLoaded = true;
11564 }
11565 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11566 getUnloaded = true;
11567 }
11568 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11569 getPendingUpgrade = true;
11570 }
11571
11572 /*
11573 * By default we are going to return all active and pendingUpgrade dexts
11574 * only.
11575 */
11576 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11577 getActive = true;
11578 getPendingUpgrade = true;
11579 }
11580
11581 /*
11582 * We return a dictionary of dexts
11583 * for every group requested.
11584 */
11585 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11586 result = OSArray::withCapacity(avgDextCount);
11587 if (!result) {
11588 goto finish;
11589 }
11590
11591 IORecursiveLockLock(sKextLock);
11592 { // start block scope
11593 if (getActive || getLoaded || getUnloaded) {
11594 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11595 {
11596 OSKext *thisKext = NULL; // do not release
11597 OSSharedPtr<OSDictionary> kextInfo;
11598 Boolean includeThis = true;
11599 (void)thisKextID;
11600
11601 thisKext = OSDynamicCast(OSKext, obj);
11602 if (!thisKext || !thisKext->isDriverKit()) {
11603 return false;
11604 }
11605
11606 /*
11607 * Skip current dext if we have a list of bundle IDs and
11608 * it isn't in the list.
11609 */
11610 if (kextIdentifiers) {
11611 includeThis = false;
11612
11613 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11614 const OSString * thisRequestID = OSDynamicCast(OSString,
11615 kextIdentifiers->getObject(idIndex));
11616 if (thisKextID->isEqualTo(thisRequestID)) {
11617 includeThis = true;
11618 break;
11619 }
11620 }
11621 }
11622
11623 if (!includeThis) {
11624 return false;
11625 }
11626
11627 OSSharedPtr<OSString> state;
11628 if (sLoadedDriverKitKexts->getNextIndexOfObject(thisKext, 0) == -1U) {
11629 if (!(getActive || getUnloaded)) {
11630 return false;
11631 }
11632 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11633 } else {
11634 if (!(getActive || getLoaded)) {
11635 return false;
11636 }
11637 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11638 }
11639
11640 kextInfo = thisKext->copyInfo(infoKeys);
11641 if (kextInfo) {
11642 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11643 result->setObject(kextInfo.get());
11644 }
11645
11646 return false;
11647 });
11648 }
11649
11650 if (getPendingUpgrade) {
11651 sDriverKitToUpgradeByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11652 {
11653 OSKext *thisKext = NULL; // do not release
11654 OSSharedPtr<OSDictionary> kextInfo;
11655 Boolean includeThis = true;
11656 (void)thisKextID;
11657
11658 thisKext = OSDynamicCast(OSKext, obj);
11659 if (!thisKext) {
11660 return false;
11661 }
11662 __assert_only bool isDext = thisKext->isDriverKit();
11663 assert(isDext == true);
11664
11665 /*
11666 * Skip current dext if we have a list of bundle IDs and
11667 * it isn't in the list.
11668 */
11669 if (kextIdentifiers) {
11670 includeThis = false;
11671
11672 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11673 const OSString * thisRequestID = OSDynamicCast(OSString,
11674 kextIdentifiers->getObject(idIndex));
11675 if (thisKextID->isEqualTo(thisRequestID)) {
11676 includeThis = true;
11677 break;
11678 }
11679 }
11680 }
11681
11682 if (!includeThis) {
11683 return false;
11684 }
11685
11686 kextInfo = thisKext->copyInfo(infoKeys);
11687 if (kextInfo) {
11688 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11689 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11690 result->setObject(kextInfo.get());
11691 }
11692 return false;
11693 });
11694 }
11695 } // end block scope
11696 IORecursiveLockUnlock(sKextLock);
11697 finish:
11698 return result;
11699 }
11700
11701 /*********************************************************************
11702 *********************************************************************/
11703 /* static */
11704 OSSharedPtr<OSDictionary>
11705 OSKext::copyLoadedKextInfo(
11706 OSArray * kextIdentifiers,
11707 OSArray * infoKeys)
11708 {
11709 OSSharedPtr<OSDictionary> result;
11710 uint32_t idCount = 0;
11711 bool onlyLoaded;
11712
11713 IORecursiveLockLock(sKextLock);
11714
11715 #if CONFIG_MACF
11716 /* Is the calling process allowed to query kext info? */
11717 if (current_task() != kernel_task) {
11718 int macCheckResult = 0;
11719 kauth_cred_t cred = NULL;
11720
11721 cred = kauth_cred_get_with_ref();
11722 macCheckResult = mac_kext_check_query(cred);
11723 kauth_cred_unref(&cred);
11724
11725 if (macCheckResult != 0) {
11726 OSKextLog(/* kext */ NULL,
11727 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11728 "Failed to query kext info (MAC policy error 0x%x).",
11729 macCheckResult);
11730 goto finish;
11731 }
11732 }
11733 #endif
11734
11735 /* Empty list of bundle ids is equivalent to no list (get all).
11736 */
11737 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11738 kextIdentifiers = NULL;
11739 } else if (kextIdentifiers) {
11740 idCount = kextIdentifiers->getCount();
11741 }
11742
11743 /* Same for keys.
11744 */
11745 if (infoKeys && !infoKeys->getCount()) {
11746 infoKeys = NULL;
11747 }
11748
11749 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
11750
11751 result = OSDictionary::withCapacity(128);
11752 if (!result) {
11753 goto finish;
11754 }
11755
11756 #if 0
11757 OSKextLog(/* kext */ NULL,
11758 kOSKextLogErrorLevel |
11759 kOSKextLogGeneralFlag,
11760 "kaslr: vm_kernel_slide 0x%lx \n",
11761 vm_kernel_slide);
11762 OSKextLog(/* kext */ NULL,
11763 kOSKextLogErrorLevel |
11764 kOSKextLogGeneralFlag,
11765 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11766 vm_kernel_stext, vm_kernel_etext);
11767 OSKextLog(/* kext */ NULL,
11768 kOSKextLogErrorLevel |
11769 kOSKextLogGeneralFlag,
11770 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11771 vm_kernel_base, vm_kernel_top);
11772 OSKextLog(/* kext */ NULL,
11773 kOSKextLogErrorLevel |
11774 kOSKextLogGeneralFlag,
11775 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11776 vm_kext_base, vm_kext_top);
11777 OSKextLog(/* kext */ NULL,
11778 kOSKextLogErrorLevel |
11779 kOSKextLogGeneralFlag,
11780 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11781 vm_prelink_stext, vm_prelink_etext);
11782 OSKextLog(/* kext */ NULL,
11783 kOSKextLogErrorLevel |
11784 kOSKextLogGeneralFlag,
11785 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11786 vm_prelink_sinfo, vm_prelink_einfo);
11787 OSKextLog(/* kext */ NULL,
11788 kOSKextLogErrorLevel |
11789 kOSKextLogGeneralFlag,
11790 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11791 vm_slinkedit, vm_elinkedit);
11792 #endif
11793 { // start block scope
11794 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
11795 {
11796 OSKext * thisKext = NULL; // do not release
11797 Boolean includeThis = true;
11798 OSSharedPtr<OSDictionary> kextInfo;
11799
11800 thisKext = OSDynamicCast(OSKext, obj);
11801 if (!thisKext) {
11802 return false;
11803 }
11804
11805 /* Skip current kext if not yet started and caller didn't request all.
11806 */
11807 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11808 return false;
11809 }
11810
11811 /* Skip current kext if we have a list of bundle IDs and
11812 * it isn't in the list.
11813 */
11814 if (kextIdentifiers) {
11815 includeThis = false;
11816
11817 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11818 const OSString * thisRequestID = OSDynamicCast(OSString,
11819 kextIdentifiers->getObject(idIndex));
11820 if (thisKextID->isEqualTo(thisRequestID)) {
11821 includeThis = true;
11822 break;
11823 }
11824 }
11825 }
11826
11827 if (!includeThis) {
11828 return false;
11829 }
11830
11831 kextInfo = thisKext->copyInfo(infoKeys);
11832 if (kextInfo) {
11833 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11834 }
11835 return false;
11836 });
11837 } // end block scope
11838
11839 finish:
11840 IORecursiveLockUnlock(sKextLock);
11841
11842 return result;
11843 }
11844
11845 /*********************************************************************
11846 * Any info that needs to do allocations must goto finish on alloc
11847 * failure. Info that is just a lookup should just not set the object
11848 * if the info does not exist.
11849 *********************************************************************/
11850 #define _OSKextLoadInfoDictCapacity (12)
11851
11852 OSSharedPtr<OSDictionary>
11853 OSKext::copyInfo(OSArray * infoKeys)
11854 {
11855 OSSharedPtr<OSDictionary> result;
11856 bool success = false;
11857 OSSharedPtr<OSData> headerData;
11858 OSSharedPtr<OSData> logData;
11859 OSSharedPtr<OSNumber> cpuTypeNumber;
11860 OSSharedPtr<OSNumber> cpuSubtypeNumber;
11861 OSString * versionString = NULL; // do not release
11862 OSString * bundleType = NULL; // do not release
11863 uint32_t executablePathCStringSize = 0;
11864 char * executablePathCString = NULL; // must kfree
11865 OSSharedPtr<OSString> executablePathString;
11866 OSSharedPtr<OSData> uuid;
11867 OSSharedPtr<OSArray> dependencyLoadTags;
11868 OSSharedPtr<OSCollectionIterator> metaClassIterator;
11869 OSSharedPtr<OSArray> metaClassInfo;
11870 OSSharedPtr<OSDictionary> metaClassDict;
11871 OSMetaClass * thisMetaClass = NULL; // do not release
11872 OSSharedPtr<OSString> metaClassName;
11873 OSSharedPtr<OSString> superclassName;
11874 kc_format_t kcformat;
11875 uint32_t count, i;
11876
11877 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
11878 if (!result) {
11879 goto finish;
11880 }
11881
11882
11883 /* Empty keys means no keys, but NULL is quicker to check.
11884 */
11885 if (infoKeys && !infoKeys->getCount()) {
11886 infoKeys = NULL;
11887 }
11888
11889 if (!PE_get_primary_kc_format(&kcformat)) {
11890 goto finish;
11891 }
11892
11893 /* Headers, CPU type, and CPU subtype.
11894 */
11895 if (!infoKeys ||
11896 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
11897 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
11898 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
11899 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11900 if (linkedExecutable && !isInterface()) {
11901 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
11902 linkedExecutable->getBytesNoCopy();
11903
11904 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
11905 // do not return macho header info on shipping embedded - 19095897
11906 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
11907 kernel_mach_header_t * temp_kext_mach_hdr;
11908 struct load_command * lcp;
11909
11910 headerData = OSData::withBytes(kext_mach_hdr,
11911 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
11912 if (!headerData) {
11913 goto finish;
11914 }
11915
11916 // unslide any vmaddrs we return to userspace - 10726716
11917 temp_kext_mach_hdr = (kernel_mach_header_t *)
11918 headerData->getBytesNoCopy();
11919 if (temp_kext_mach_hdr == NULL) {
11920 goto finish;
11921 }
11922
11923 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
11924 for (i = 0; (i < temp_kext_mach_hdr->ncmds) && !flags.unslidMachO; i++) {
11925 if (lcp->cmd == LC_SEGMENT_KERNEL) {
11926 kernel_segment_command_t * segp;
11927 kernel_section_t * secp;
11928
11929 segp = (kernel_segment_command_t *) lcp;
11930 // 10543468 - if we jettisoned __LINKEDIT clear size info
11931 if (flags.jettisonLinkeditSeg) {
11932 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
11933 segp->vmsize = 0;
11934 segp->fileoff = 0;
11935 segp->filesize = 0;
11936 }
11937 }
11938
11939 #if __arm__ || __arm64__
11940 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
11941 // and unslide them to avoid vm assertion failures / kernel logging breakage.
11942 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
11943 segp->vmaddr = gVirtBase;
11944 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
11945 secp->size = 0; // paranoia :)
11946 secp->addr = gVirtBase;
11947 }
11948 }
11949 #endif
11950
11951 #if 0
11952 OSKextLog(/* kext */ NULL,
11953 kOSKextLogErrorLevel |
11954 kOSKextLogGeneralFlag,
11955 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
11956 __FUNCTION__, segp->segname, segp->vmaddr,
11957 VM_KERNEL_UNSLIDE(segp->vmaddr),
11958 segp->vmsize, segp->nsects);
11959 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
11960 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
11961 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
11962 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
11963 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
11964 OSKextLog(/* kext */ NULL,
11965 kOSKextLogErrorLevel |
11966 kOSKextLogGeneralFlag,
11967 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
11968 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
11969 }
11970 #endif
11971 segp->vmaddr = ml_static_unslide(segp->vmaddr);
11972
11973 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
11974 secp->addr = ml_static_unslide(secp->addr);
11975 }
11976 }
11977 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
11978 }
11979 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
11980 }
11981 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
11982
11983 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11984 osLogDataHeaderRef *header;
11985 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11986
11987 void *os_log_data = NULL;
11988 void *cstring_data = NULL;
11989 void *asan_cstring_data = NULL;
11990 unsigned long os_log_size = 0;
11991 unsigned long cstring_size = 0;
11992 unsigned long asan_cstring_size = 0;
11993 uint32_t os_log_offset = 0;
11994 uint32_t cstring_offset = 0;
11995 uint32_t asan_cstring_offset = 0;
11996 bool res;
11997
11998 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
11999 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
12000 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
12001
12002 /*
12003 * If the addresses in the Mach-O header are unslid, manually
12004 * slide them to allow for dereferencing.
12005 */
12006 if (flags.unslidMachO) {
12007 os_log_data = (os_log_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)os_log_data) : nullptr;
12008 cstring_data = (cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)cstring_data) : nullptr;
12009 asan_cstring_data = (asan_cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)asan_cstring_data) : nullptr;
12010 }
12011
12012 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
12013 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
12014 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
12015
12016 header = (osLogDataHeaderRef *) headerBytes;
12017 header->version = OS_LOG_HDR_VERSION;
12018 header->sect_count = NUM_OS_LOG_SECTIONS;
12019 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
12020 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
12021 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
12022 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
12023 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
12024 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
12025
12026
12027 logData = OSData::withValue(*header);
12028 if (!logData) {
12029 goto finish;
12030 }
12031 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12032 if (!res) {
12033 goto finish;
12034 }
12035 if (os_log_data) {
12036 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
12037 if (!res) {
12038 goto finish;
12039 }
12040 }
12041 if (cstring_data) {
12042 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
12043 if (!res) {
12044 goto finish;
12045 }
12046 }
12047 if (asan_cstring_data) {
12048 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
12049 if (!res) {
12050 goto finish;
12051 }
12052 }
12053 result->setObject(kOSBundleLogStringsKey, logData.get());
12054 }
12055
12056 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
12057 cpuTypeNumber = OSNumber::withNumber(
12058 (uint64_t) kext_mach_hdr->cputype,
12059 8 * sizeof(kext_mach_hdr->cputype));
12060 if (!cpuTypeNumber) {
12061 goto finish;
12062 }
12063 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
12064 }
12065
12066 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12067 cpuSubtypeNumber = OSNumber::withNumber(
12068 (uint64_t) kext_mach_hdr->cpusubtype,
12069 8 * sizeof(kext_mach_hdr->cpusubtype));
12070 if (!cpuSubtypeNumber) {
12071 goto finish;
12072 }
12073 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
12074 }
12075 } else {
12076 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12077 osLogDataHeaderRef *header;
12078 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12079 bool res;
12080
12081 header = (osLogDataHeaderRef *) headerBytes;
12082 header->version = OS_LOG_HDR_VERSION;
12083 header->sect_count = NUM_OS_LOG_SECTIONS;
12084 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
12085 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
12086 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
12087 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12088 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
12089 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12090
12091 logData = OSData::withValue(*header);
12092 if (!logData) {
12093 goto finish;
12094 }
12095 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12096 if (!res) {
12097 goto finish;
12098 }
12099 result->setObject(kOSBundleLogStringsKey, logData.get());
12100 }
12101 }
12102 }
12103
12104 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
12105 */
12106 result->setObject(kCFBundleIdentifierKey, bundleID.get());
12107
12108 /* kOSBundleDextUniqueIdentifierKey if present.
12109 */
12110 if (isDriverKit() && dextUniqueID != NULL) {
12111 result->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID.get());
12112 }
12113
12114 /* CFBundlePackageType
12115 */
12116 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12117 if (bundleType) {
12118 result->setObject(kCFBundlePackageTypeKey, bundleType);
12119 }
12120
12121 /* CFBundleVersion.
12122 */
12123 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
12124 versionString = OSDynamicCast(OSString,
12125 getPropertyForHostArch(kCFBundleVersionKey));
12126 if (versionString) {
12127 result->setObject(kCFBundleVersionKey, versionString);
12128 }
12129 }
12130
12131 /* OSBundleCompatibleVersion.
12132 */
12133 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
12134 versionString = OSDynamicCast(OSString,
12135 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12136 if (versionString) {
12137 result->setObject(kOSBundleCompatibleVersionKey, versionString);
12138 }
12139 }
12140
12141 /* Path.
12142 */
12143 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
12144 if (path) {
12145 result->setObject(kOSBundlePathKey, path.get());
12146 }
12147 }
12148
12149
12150 /* OSBundleExecutablePath.
12151 */
12152 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
12153 if (path && executableRelPath) {
12154 uint32_t pathLength = path->getLength(); // gets incremented below
12155
12156 // +1 for slash, +1 for \0
12157 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12158
12159 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12160 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12161 if (!executablePathCString) {
12162 goto finish;
12163 }
12164 strlcpy(executablePathCString, path->getCStringNoCopy(),
12165 executablePathCStringSize);
12166 executablePathCString[pathLength++] = '/';
12167 executablePathCString[pathLength++] = '\0';
12168 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
12169 executablePathCStringSize);
12170
12171 executablePathString = OSString::withCString(executablePathCString);
12172
12173 if (!executablePathString) {
12174 goto finish;
12175 }
12176
12177 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12178 } else if (flags.builtin) {
12179 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
12180 } else if (isDriverKit()) {
12181 if (path) {
12182 // +1 for slash, +1 for \0
12183 uint32_t pathLength = path->getLength();
12184 executablePathCStringSize = pathLength + 2;
12185
12186 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12187 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12188 if (!executablePathCString) {
12189 goto finish;
12190 }
12191 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
12192 executablePathCString[pathLength++] = '/';
12193 executablePathCString[pathLength++] = '\0';
12194
12195 executablePathString = OSString::withCString(executablePathCString);
12196
12197 if (!executablePathString) {
12198 goto finish;
12199 }
12200
12201 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12202 }
12203 }
12204 }
12205
12206 /* UUID, if the kext has one.
12207 */
12208 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
12209 uuid = copyUUID();
12210 if (uuid) {
12211 result->setObject(kOSBundleUUIDKey, uuid.get());
12212 }
12213 }
12214 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
12215 uuid = copyTextUUID();
12216 if (uuid) {
12217 result->setObject(kOSBundleTextUUIDKey, uuid.get());
12218 }
12219 }
12220
12221 /*
12222 * Info.plist digest
12223 */
12224 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
12225 OSData *digest;
12226 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12227 if (digest) {
12228 result->setObject(kOSKextInfoPlistDigestKey, digest);
12229 }
12230 }
12231
12232 /*
12233 * Collection type
12234 */
12235 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
12236 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
12237 }
12238
12239 /*
12240 * Collection availability
12241 */
12242 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
12243 result->setObject(kOSKextAuxKCAvailabilityKey,
12244 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12245 }
12246
12247 /*
12248 * Allows user load
12249 */
12250 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
12251 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12252 if (allowUserLoad) {
12253 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
12254 }
12255 }
12256
12257 /*
12258 * Bundle Dependencies (OSBundleLibraries)
12259 */
12260 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
12261 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12262 if (libraries) {
12263 result->setObject(kOSBundleLibrariesKey, libraries);
12264 }
12265 }
12266
12267 /*****
12268 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12269 */
12270 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
12271 result->setObject(kOSKernelResourceKey,
12272 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12273 }
12274
12275 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
12276 result->setObject(kOSBundleIsInterfaceKey,
12277 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12278 }
12279
12280 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
12281 result->setObject(kOSBundlePrelinkedKey,
12282 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12283 }
12284
12285 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
12286 result->setObject(kOSBundleStartedKey,
12287 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12288 }
12289
12290 /* LoadTag (Index).
12291 */
12292 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
12293 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
12294 /* numBits */ 8 * sizeof(loadTag));
12295 if (!scratchNumber) {
12296 goto finish;
12297 }
12298 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
12299 }
12300
12301 /* LoadAddress, LoadSize.
12302 */
12303 if (!infoKeys ||
12304 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
12305 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
12306 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
12307 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
12308 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12309 bool is_dext = isDriverKit();
12310 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12311 /* These go to userspace via serialization, so we don't want any doubts
12312 * about their size.
12313 */
12314 uint64_t loadAddress = 0;
12315 uint32_t loadSize = 0;
12316 uint32_t wiredSize = 0;
12317 uint64_t execLoadAddress = 0;
12318 uint32_t execLoadSize = 0;
12319
12320 /* Interfaces always report 0 load address & size.
12321 * Just the way they roll.
12322 *
12323 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12324 * xxx - shouldn't have one!
12325 */
12326
12327 if (flags.builtin || linkedExecutable) {
12328 kernel_mach_header_t *mh = NULL;
12329 kernel_segment_command_t *seg = NULL;
12330
12331 if (flags.builtin) {
12332 loadAddress = kmod_info->address;
12333 loadSize = (uint32_t)kmod_info->size;
12334 } else {
12335 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12336 loadSize = linkedExecutable->getLength();
12337 }
12338 mh = (kernel_mach_header_t *)loadAddress;
12339 loadAddress = ml_static_unslide(loadAddress);
12340
12341 /* Walk through the kext, looking for the first executable
12342 * segment in case we were asked for its size/address.
12343 */
12344 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
12345 if (seg->initprot & VM_PROT_EXECUTE) {
12346 execLoadAddress = (flags.unslidMachO) ? seg->vmaddr : ml_static_unslide(seg->vmaddr);
12347 execLoadSize = (uint32_t)seg->vmsize;
12348 break;
12349 }
12350 }
12351
12352 /* If we have a kmod_info struct, calculated the wired size
12353 * from that. Otherwise it's the full load size.
12354 */
12355 if (kmod_info) {
12356 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12357 } else {
12358 wiredSize = loadSize;
12359 }
12360 } else if (is_dext) {
12361 /*
12362 * DriverKit userspace executables do not have a kernel linkedExecutable,
12363 * so we "fake" their address range with the LoadTag.
12364 */
12365 if (loadTag) {
12366 loadAddress = execLoadAddress = loadTag;
12367 loadSize = execLoadSize = 1;
12368 }
12369 }
12370
12371 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
12372 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12373 (unsigned long long)(loadAddress),
12374 /* numBits */ 8 * sizeof(loadAddress));
12375 if (!scratchNumber) {
12376 goto finish;
12377 }
12378 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
12379 }
12380 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12381 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
12382 && loadAddress && loadSize) {
12383 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
12384 if (!baseAddress) {
12385 goto finish;
12386 }
12387
12388 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12389 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
12390 /* numBits */ 8 * sizeof(loadAddress));
12391 if (!scratchNumber) {
12392 goto finish;
12393 }
12394 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
12395 }
12396 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
12397 && (this == sKernelKext) && gBuiltinKmodsCount) {
12398 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
12399 }
12400 }
12401
12402 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
12403 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12404 (unsigned long long)(execLoadAddress),
12405 /* numBits */ 8 * sizeof(execLoadAddress));
12406 if (!scratchNumber) {
12407 goto finish;
12408 }
12409 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
12410 }
12411 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
12412 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12413 (unsigned long long)(loadSize),
12414 /* numBits */ 8 * sizeof(loadSize));
12415 if (!scratchNumber) {
12416 goto finish;
12417 }
12418 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
12419 }
12420 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
12421 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12422 (unsigned long long)(execLoadSize),
12423 /* numBits */ 8 * sizeof(execLoadSize));
12424 if (!scratchNumber) {
12425 goto finish;
12426 }
12427 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
12428 }
12429 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12430 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12431 (unsigned long long)(wiredSize),
12432 /* numBits */ 8 * sizeof(wiredSize));
12433 if (!scratchNumber) {
12434 goto finish;
12435 }
12436 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
12437 }
12438 }
12439 }
12440
12441 /* OSBundleDependencies. In descending order for
12442 * easy compatibility with kextstat(8).
12443 */
12444 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
12445 if ((count = getNumDependencies())) {
12446 dependencyLoadTags = OSArray::withCapacity(count);
12447 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
12448
12449 i = count - 1;
12450 do {
12451 OSKext * dependency = OSDynamicCast(OSKext,
12452 dependencies->getObject(i));
12453
12454 if (!dependency) {
12455 continue;
12456 }
12457 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12458 (unsigned long long)dependency->getLoadTag(),
12459 /* numBits*/ 8 * sizeof(loadTag));
12460 if (!scratchNumber) {
12461 goto finish;
12462 }
12463 dependencyLoadTags->setObject(scratchNumber.get());
12464 } while (i--);
12465 }
12466 }
12467
12468 /* OSBundleMetaClasses.
12469 */
12470 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
12471 if (metaClasses && metaClasses->getCount()) {
12472 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
12473 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
12474 if (!metaClassIterator || !metaClassInfo) {
12475 goto finish;
12476 }
12477 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
12478
12479 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12480 metaClassIterator->getNextObject()))) {
12481 metaClassDict = OSDictionary::withCapacity(3);
12482 if (!metaClassDict) {
12483 goto finish;
12484 }
12485
12486 metaClassName = OSString::withCString(thisMetaClass->getClassName());
12487 if (thisMetaClass->getSuperClass()) {
12488 superclassName = OSString::withCString(
12489 thisMetaClass->getSuperClass()->getClassName());
12490 }
12491 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
12492 8 * sizeof(unsigned int));
12493
12494 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12495 * of course.
12496 */
12497 if (!metaClassDict || !metaClassName || !scratchNumber) {
12498 goto finish;
12499 }
12500
12501 metaClassInfo->setObject(metaClassDict.get());
12502 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
12503 if (superclassName) {
12504 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
12505 }
12506 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
12507 }
12508 }
12509 }
12510
12511 /* OSBundleRetainCount.
12512 */
12513 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
12514 {
12515 int kextRetainCount = getRetainCount() - 1;
12516 if (isLoaded()) {
12517 kextRetainCount--;
12518 }
12519 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12520 (int)kextRetainCount,
12521 /* numBits*/ 8 * sizeof(int));
12522 if (scratchNumber) {
12523 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
12524 }
12525 }
12526 }
12527
12528 success = true;
12529
12530 finish:
12531 if (executablePathCString) {
12532 kfree_data(executablePathCString, executablePathCStringSize);
12533 }
12534 if (!success) {
12535 result.reset();
12536 }
12537 return result;
12538 }
12539
12540 /*********************************************************************
12541 *********************************************************************/
12542 /* static */
12543 bool
12544 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12545 {
12546 bool ok;
12547 OSSharedPtr<OSKext> kext;
12548
12549 IORecursiveLockLock(sKextLock);
12550 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12551 IORecursiveLockUnlock(sKextLock);
12552
12553 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12554 return false;
12555 }
12556 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
12557 kext->path->getCStringNoCopy(),
12558 kext->userExecutableRelPath->getCStringNoCopy());
12559 ok = true;
12560
12561 return ok;
12562 }
12563
12564 /*********************************************************************
12565 *********************************************************************/
12566 /* static */
12567 OSReturn
12568 OSKext::requestResource(
12569 const char * kextIdentifierCString,
12570 const char * resourceNameCString,
12571 OSKextRequestResourceCallback callback,
12572 void * context,
12573 OSKextRequestTag * requestTagOut)
12574 {
12575 OSReturn result = kOSReturnError;
12576 OSSharedPtr<OSKext> callbackKext; // looked up
12577
12578 OSKextRequestTag requestTag = -1;
12579 OSSharedPtr<OSNumber> requestTagNum;
12580 OSSharedPtr<OSDictionary> requestDict;
12581 OSSharedPtr<OSString> kextIdentifier;
12582 OSSharedPtr<OSString> resourceName;
12583
12584 OSSharedPtr<OSDictionary> callbackRecord;
12585 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12586
12587 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12588
12589 IORecursiveLockLock(sKextLock);
12590
12591 if (requestTagOut) {
12592 *requestTagOut = kOSKextRequestTagInvalid;
12593 }
12594
12595 /* If requests to user space are disabled, don't go any further */
12596 if (!sKernelRequestsEnabled) {
12597 OSKextLog(/* kext */ NULL,
12598 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12599 "Can't request resource %s for %s - requests to user space are disabled.",
12600 resourceNameCString,
12601 kextIdentifierCString);
12602 result = kOSKextReturnDisabled;
12603 goto finish;
12604 }
12605
12606 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12607 result = kOSKextReturnInvalidArgument;
12608 goto finish;
12609 }
12610
12611 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12612 if (!callbackKext) {
12613 OSKextLog(/* kext */ NULL,
12614 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12615 "Resource request has bad callback address.");
12616 result = kOSKextReturnInvalidArgument;
12617 goto finish;
12618 }
12619 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12620 OSKextLog(/* kext */ NULL,
12621 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12622 "Resource request callback is in a kext that is not started.");
12623 result = kOSKextReturnInvalidArgument;
12624 goto finish;
12625 }
12626
12627 /* Do not allow any new requests to be made on a kext that is unloading.
12628 */
12629 if (callbackKext->flags.stopping) {
12630 result = kOSKextReturnStopping;
12631 goto finish;
12632 }
12633
12634 /* If we're wrapped the next available request tag around to the negative
12635 * numbers, we can't service any more requests.
12636 */
12637 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12638 OSKextLog(/* kext */ NULL,
12639 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12640 "No more request tags available; restart required.");
12641 result = kOSKextReturnNoResources;
12642 goto finish;
12643 }
12644 requestTag = sNextRequestTag++;
12645
12646 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12647 requestDict);
12648 if (result != kOSReturnSuccess) {
12649 goto finish;
12650 }
12651
12652 kextIdentifier = OSString::withCString(kextIdentifierCString);
12653 resourceName = OSString::withCString(resourceNameCString);
12654 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12655 8 * sizeof(requestTag));
12656 if (!kextIdentifier ||
12657 !resourceName ||
12658 !requestTagNum ||
12659 !_OSKextSetRequestArgument(requestDict.get(),
12660 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
12661 !_OSKextSetRequestArgument(requestDict.get(),
12662 kKextRequestArgumentNameKey, resourceName.get()) ||
12663 !_OSKextSetRequestArgument(requestDict.get(),
12664 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
12665 result = kOSKextReturnNoMemory;
12666 goto finish;
12667 }
12668
12669 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
12670 if (!callbackRecord) {
12671 result = kOSKextReturnNoMemory;
12672 goto finish;
12673 }
12674 // we validate callback address at call time
12675 callbackWrapper = OSValueObjectWithValue(callback);
12676 if (context) {
12677 contextWrapper = OSValueObjectWithValue(context);
12678 }
12679 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12680 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
12681 result = kOSKextReturnNoMemory;
12682 goto finish;
12683 }
12684
12685 if (context) {
12686 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12687 kKextRequestArgumentContextKey, contextWrapper.get())) {
12688 result = kOSKextReturnNoMemory;
12689 goto finish;
12690 }
12691 }
12692
12693 /* Only post the requests after all the other potential failure points
12694 * have been passed.
12695 */
12696 if (!sKernelRequests->setObject(requestDict.get()) ||
12697 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12698 result = kOSKextReturnNoMemory;
12699 goto finish;
12700 }
12701
12702 OSKext::pingIOKitDaemon();
12703
12704 result = kOSReturnSuccess;
12705 if (requestTagOut) {
12706 *requestTagOut = requestTag;
12707 }
12708
12709 finish:
12710
12711 /* If we didn't succeed, yank the request & callback
12712 * from their holding arrays.
12713 */
12714 if (result != kOSReturnSuccess) {
12715 unsigned int index;
12716
12717 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
12718 if (index != (unsigned int)-1) {
12719 sKernelRequests->removeObject(index);
12720 }
12721 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
12722 if (index != (unsigned int)-1) {
12723 sRequestCallbackRecords->removeObject(index);
12724 }
12725 }
12726
12727 OSKext::considerUnloads(/* rescheduleOnly? */ true);
12728
12729 IORecursiveLockUnlock(sKextLock);
12730
12731 return result;
12732 }
12733
12734 OSReturn
12735 OSKext::requestDaemonLaunch(
12736 OSString *kextIdentifier,
12737 OSString *serverName,
12738 OSNumber *serverTag,
12739 OSBoolean *reslide,
12740 IOUserServerCheckInToken * checkInToken,
12741 OSData *serverDUI)
12742 {
12743 OSReturn result = kOSReturnError;
12744 OSSharedPtr<OSDictionary> requestDict;
12745 unsigned int size = 0;
12746 const char *dextUniqueIDCString = NULL;
12747
12748 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12749 return kOSKextReturnInvalidArgument;
12750 }
12751
12752 if (serverDUI != NULL) {
12753 dextUniqueIDCString = getDextUniqueIDCString(serverDUI, &size);
12754 }
12755
12756 IORecursiveLockLock(sKextLock);
12757
12758 OSKextLog(/* kext */ NULL,
12759 kOSKextLogDebugLevel |
12760 kOSKextLogGeneralFlag,
12761 "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12762 kextIdentifier->getCStringNoCopy(),
12763 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12764 serverName->getCStringNoCopy(),
12765 serverTag->unsigned64BitValue(),
12766 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12767 );
12768
12769 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
12770 if (result != kOSReturnSuccess) {
12771 goto finish;
12772 }
12773
12774 if (!_OSKextSetRequestArgument(requestDict.get(),
12775 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12776 !_OSKextSetRequestArgument(requestDict.get(),
12777 kKextRequestArgumentDriverExtensionServerName, serverName) ||
12778 !_OSKextSetRequestArgument(requestDict.get(),
12779 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
12780 !_OSKextSetRequestArgument(requestDict.get(),
12781 kKextRequestArgumentDriverExtensionReslideSharedCache, reslide) ||
12782 !_OSKextSetRequestArgument(requestDict.get(),
12783 kKextRequestArgumentCheckInToken, checkInToken)) {
12784 result = kOSKextReturnNoMemory;
12785 goto finish;
12786 }
12787
12788 if (serverDUI) {
12789 if (!_OSKextSetRequestArgument(requestDict.get(),
12790 kOSBundleDextUniqueIdentifierKey, serverDUI)) {
12791 result = kOSKextReturnNoMemory;
12792 goto finish;
12793 }
12794 }
12795
12796 /* Only post the requests after all the other potential failure points
12797 * have been passed.
12798 */
12799 if (!sKernelRequests->setObject(requestDict.get())) {
12800 result = kOSKextReturnNoMemory;
12801 goto finish;
12802 }
12803 OSKext::pingIOKitDaemon();
12804
12805 result = kOSReturnSuccess;
12806 finish:
12807 IORecursiveLockUnlock(sKextLock);
12808 if (dextUniqueIDCString) {
12809 kfree_data(dextUniqueIDCString, size);
12810 }
12811 return result;
12812 }
12813
12814 OSReturn
12815 OSKext::notifyDextUpgrade(
12816 OSString *kextIdentifier,
12817 OSData *dextUniqueIdentifier)
12818 {
12819 OSReturn result = kOSReturnError;
12820 OSSharedPtr<OSDictionary> requestDict;
12821 unsigned int size = 0;
12822 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueIdentifier, &size);
12823 assert(dextUniqueIDCString != NULL);
12824
12825 IORecursiveLockLock(sKextLock);
12826
12827 OSKextLog(NULL,
12828 kOSKextLogDebugLevel |
12829 kOSKextLogGeneralFlag,
12830 "Notifying of dext upgrade for %s with UniqueID %s",
12831 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
12832
12833 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestDict);
12834 if (result != kOSReturnSuccess) {
12835 goto finish;
12836 }
12837
12838 if (!_OSKextSetRequestArgument(requestDict.get(),
12839 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12840 !_OSKextSetRequestArgument(requestDict.get(),
12841 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
12842 result = kOSKextReturnNoMemory;
12843 goto finish;
12844 }
12845
12846 /* Only post the requests after all the other potential failure points
12847 * have been passed.
12848 */
12849 if (!sKernelRequests->setObject(requestDict.get())) {
12850 result = kOSKextReturnNoMemory;
12851 goto finish;
12852 }
12853 OSKext::pingIOKitDaemon();
12854
12855 result = kOSReturnSuccess;
12856 finish:
12857 IORecursiveLockUnlock(sKextLock);
12858
12859 if (dextUniqueIDCString != NULL) {
12860 kfree_data(dextUniqueIDCString, size);
12861 }
12862 return result;
12863 }
12864
12865 /*********************************************************************
12866 * Assumes sKextLock is held.
12867 *********************************************************************/
12868 /* static */
12869 OSReturn
12870 OSKext::dequeueCallbackForRequestTag(
12871 OSKextRequestTag requestTag,
12872 OSSharedPtr<OSDictionary> &callbackRecordOut)
12873 {
12874 OSDictionary * callbackRecordOutRaw = NULL;
12875 OSReturn result;
12876
12877 result = dequeueCallbackForRequestTag(requestTag,
12878 &callbackRecordOutRaw);
12879
12880 if (kOSReturnSuccess == result) {
12881 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
12882 }
12883
12884 return result;
12885 }
12886 OSReturn
12887 OSKext::dequeueCallbackForRequestTag(
12888 OSKextRequestTag requestTag,
12889 OSDictionary ** callbackRecordOut)
12890 {
12891 OSReturn result = kOSReturnError;
12892 OSSharedPtr<OSNumber> requestTagNum;
12893
12894 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12895 8 * sizeof(requestTag));
12896 if (!requestTagNum) {
12897 goto finish;
12898 }
12899
12900 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
12901 callbackRecordOut);
12902
12903 finish:
12904 return result;
12905 }
12906
12907 /*********************************************************************
12908 * Assumes sKextLock is held.
12909 *********************************************************************/
12910 /* static */
12911 OSReturn
12912 OSKext::dequeueCallbackForRequestTag(
12913 OSNumber * requestTagNum,
12914 OSSharedPtr<OSDictionary> &callbackRecordOut)
12915 {
12916 OSDictionary * callbackRecordOutRaw = NULL;
12917 OSReturn result;
12918
12919 result = dequeueCallbackForRequestTag(requestTagNum,
12920 &callbackRecordOutRaw);
12921
12922 if (kOSReturnSuccess == result) {
12923 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
12924 }
12925
12926 return result;
12927 }
12928 OSReturn
12929 OSKext::dequeueCallbackForRequestTag(
12930 OSNumber * requestTagNum,
12931 OSDictionary ** callbackRecordOut)
12932 {
12933 OSReturn result = kOSKextReturnInvalidArgument;
12934 OSDictionary * callbackRecord = NULL; // retain if matched!
12935 OSNumber * callbackTagNum = NULL; // do not release
12936 unsigned int count, i;
12937
12938 result = kOSReturnError;
12939 count = sRequestCallbackRecords->getCount();
12940 for (i = 0; i < count; i++) {
12941 callbackRecord = OSDynamicCast(OSDictionary,
12942 sRequestCallbackRecords->getObject(i));
12943 if (!callbackRecord) {
12944 goto finish;
12945 }
12946
12947 /* If we don't find a tag, we basically have a leak here. Maybe
12948 * we should just remove it.
12949 */
12950 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
12951 callbackRecord, kKextRequestArgumentRequestTagKey));
12952 if (!callbackTagNum) {
12953 goto finish;
12954 }
12955
12956 /* We could be even more paranoid and check that all the incoming
12957 * args match what's in the callback record.
12958 */
12959 if (callbackTagNum->isEqualTo(requestTagNum)) {
12960 if (callbackRecordOut) {
12961 *callbackRecordOut = callbackRecord;
12962 callbackRecord->retain();
12963 }
12964 sRequestCallbackRecords->removeObject(i);
12965 result = kOSReturnSuccess;
12966 goto finish;
12967 }
12968 }
12969 result = kOSKextReturnNotFound;
12970
12971 finish:
12972 return result;
12973 }
12974
12975
12976 /*********************************************************************
12977 * Busy timeout triage
12978 *********************************************************************/
12979 /* static */
12980 bool
12981 OSKext::pendingIOKitDaemonRequests(void)
12982 {
12983 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
12984 }
12985
12986 /*********************************************************************
12987 * Acquires and releases sKextLock
12988 *
12989 * This function is designed to be called by kernelmanagerd and driverkitd
12990 * and it gathers all codeless kext and dext personalities, and then attempts
12991 * to map a System (pageable) KC and an Auxiliary (aux) KC.
12992 *
12993 * The pageable and aux KC can be loaded only once at boot time.
12994 * Even if the pageable or aux KC fail to load - this function will
12995 * not allow a new pageable or aux KC to be installed by subsequent calls.
12996 * This is done to avoid security issues where userspace has been compromised
12997 * or the pageable kc has been tampered with and the attacker
12998 * attempts to re-load a malicious variant.
12999 * However dexts can be dynamically loaded, so this function can be used
13000 * to request the installation of a new set of dexts even after boot time.
13001 *
13002 *
13003 *
13004 * Return: if a KC fails to load the return value will contain:
13005 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
13006 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
13007 * Similarly, if the aux kc load fails, the return value will
13008 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
13009 * compose with each other and with kOSKextReturnKCLoadFailure.
13010 *********************************************************************/
13011 /* static */
13012 OSReturn
13013 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
13014 {
13015 static bool daemon_ready = false;
13016
13017 OSReturn ret = kOSKextReturnInvalidArgument;
13018 OSReturn kcerr = 0;
13019 bool start_matching = false;
13020
13021 bool allow_fileset_load = !daemon_ready;
13022 #if !(defined(__x86_64__) || defined(__i386__))
13023 /* never allow KCs full of kexts on non-x86 machines */
13024 allow_fileset_load = false;
13025 #endif
13026
13027 /*
13028 * Change with 70582300
13029 */
13030 #if 0 || !defined(VM_MAPPED_KEXTS)
13031 /*
13032 * On platforms that don't support the SystemKC or a file-backed
13033 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
13034 * needs to be queried before we load any codeless kexts or release
13035 * any 3rd party kexts to run. On platforms that support a file-backed
13036 * AuxKC, this process is done via the kext audit mechanism.
13037 */
13038
13039 printf("KextLog: waiting for kext receipt to be queried.\n");
13040 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
13041 IOSleep(30);
13042 }
13043 #endif /* !VM_MAPPED_KEXTS */
13044
13045 /*
13046 * Get the args from the request. Right now we need the file
13047 * name for the pageable and the aux kext collection file sets.
13048 */
13049 OSDictionary * requestArgs = NULL; // do not release
13050 OSString * pageable_filepath = NULL; // do not release
13051 OSString * aux_filepath = NULL; // do not release
13052 OSArray * codeless_kexts = NULL; // do not release
13053
13054 kernel_mach_header_t *akc_mh = NULL;
13055
13056 requestArgs = OSDynamicCast(OSDictionary,
13057 requestDict->getObject(kKextRequestArgumentsKey));
13058
13059 if (requestArgs == NULL) {
13060 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13061 "KextLog: No arguments in plist for loading fileset kext\n");
13062 printf("KextLog: No arguments in plist for loading fileset kext\n");
13063 return ret;
13064 }
13065
13066 ret = kOSKextReturnDisabled;
13067
13068 IORecursiveLockLock(sKextLock);
13069
13070 if (!sLoadEnabled) {
13071 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13072 "KextLog: Kext loading is disabled (attempt to load KCs).");
13073 IORecursiveLockUnlock(sKextLock);
13074 return ret;
13075 }
13076
13077 pageable_filepath = OSDynamicCast(OSString,
13078 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
13079
13080 if (allow_fileset_load && pageable_filepath != NULL) {
13081 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
13082
13083 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
13084 if (ret) {
13085 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13086 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13087
13088 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13089 ret = kOSKextReturnKCLoadFailure;
13090 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
13091 goto try_auxkc;
13092 }
13093 /*
13094 * Even if the AuxKC fails to load, we still want to send
13095 * the System KC personalities to the catalog for matching
13096 */
13097 start_matching = true;
13098 } else if (pageable_filepath != NULL) {
13099 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13100 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
13101 ret = kOSKextReturnUnsupported;
13102 }
13103
13104 try_auxkc:
13105 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
13106 if (akc_mh) {
13107 /*
13108 * If we try to load a deferred AuxKC, then don't ever attempt
13109 * a filesystem map of a file
13110 */
13111 allow_fileset_load = false;
13112
13113 /*
13114 * This function is only called once per boot, so we haven't
13115 * yet loaded an AuxKC. If we have registered the AuxKC mach
13116 * header, that means that the kext collection has been placed
13117 * in memory for us by the booter, and is waiting for us to
13118 * process it. Grab the deferred XML plist of info
13119 * dictionaries and add all the kexts.
13120 */
13121 OSSharedPtr<OSObject> parsedXML;
13122 OSSharedPtr<OSData> loaded_kcUUID;
13123 OSDictionary *infoDict;
13124 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
13125 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13126 #if !defined(VM_MAPPED_KEXTS)
13127 /*
13128 * On platforms where we don't dynamically wire-down / page-in
13129 * kext memory, we need to maintain the invariant that if the
13130 * AuxKC in memory does not contain a kext receipt, then we
13131 * should not load any of the kexts.
13132 */
13133 size_t receipt_sz = 0;
13134 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13135 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13136 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13137 ret = kOSKextReturnKCLoadFailure;
13138 goto try_codeless;
13139 }
13140 #endif
13141 if (infoDict) {
13142 bool added;
13143 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13144 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
13145 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
13146 if (!loaded_kcUUID) {
13147 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13148 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13149 } else if (!added) {
13150 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13151 "KextLog: WARNING: Failed to load AuxKC from memory.");
13152 }
13153 /* only return success if the pageable load (above) was successful */
13154 if (ret != kOSKextReturnKCLoadFailure) {
13155 ret = kOSReturnSuccess;
13156 }
13157 /* the registration of the AuxKC parsed out the KC's UUID already */
13158 } else {
13159 if (daemon_ready) {
13160 /*
13161 * Complain, but don't return an error if this isn't the first time the
13162 * IOKit daemon is checking in. If the daemon ever restarts, we will
13163 * hit this case because we've already consumed the deferred personalities.
13164 * We return success here so that a call to this function from a restarted
13165 * daemon with no codeless kexts will succeed.
13166 */
13167 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13168 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13169 if (ret != kOSKextReturnKCLoadFailure) {
13170 ret = kOSReturnSuccess;
13171 }
13172 } else {
13173 /* this is a real error case */
13174 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13175 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13176 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13177 ret = kOSKextReturnKCLoadFailure;
13178 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13179 }
13180 }
13181 }
13182
13183 aux_filepath = OSDynamicCast(OSString,
13184 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13185 if (allow_fileset_load && aux_filepath != NULL) {
13186 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13187
13188 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
13189 if (ret) {
13190 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13191 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13192
13193 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13194 ret = kOSKextReturnKCLoadFailure;
13195 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13196 goto try_codeless;
13197 }
13198 start_matching = true;
13199 } else if (aux_filepath != NULL) {
13200 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13201 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13202 if (ret != kOSKextReturnKCLoadFailure) {
13203 ret = kOSKextReturnUnsupported;
13204 }
13205 }
13206
13207 try_codeless:
13208 /*
13209 * Load codeless kexts last so that there is no possibilty of a
13210 * codeless kext bundle ID preventing a kext in the system KC from
13211 * loading
13212 */
13213 codeless_kexts = OSDynamicCast(OSArray,
13214 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13215 if (codeless_kexts != NULL) {
13216 uint32_t count = codeless_kexts->getCount();
13217 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13218 "KextLog: loading %d codeless kexts/dexts", count);
13219 for (uint32_t i = 0; i < count; i++) {
13220 OSDictionary *infoDict;
13221 infoDict = OSDynamicCast(OSDictionary,
13222 codeless_kexts->getObject(i));
13223 if (!infoDict) {
13224 continue;
13225 }
13226 // instantiate a new kext, and don't hold a reference
13227 // (the kext subsystem will hold one implicitly)
13228 OSKext::withCodelessInfo(infoDict, NULL);
13229 }
13230 /* ignore errors that are not KC load failures */
13231 if (ret != kOSKextReturnKCLoadFailure) {
13232 ret = kOSReturnSuccess;
13233 }
13234 start_matching = true;
13235 }
13236
13237 /* send personalities to the IOCatalog once */
13238 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13239 OSKext::sendAllKextPersonalitiesToCatalog(true);
13240 /*
13241 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13242 * things as active and start all the delayed matching: the
13243 * dext and codeless kext personalities should have all been
13244 * delivered via this one call.
13245 */
13246 if (!daemon_ready) {
13247 OSKext::setIOKitDaemonActive();
13248 OSKext::setDeferredLoadSucceeded(TRUE);
13249 IOService::iokitDaemonLaunched();
13250 }
13251 if (sOSKextWasResetAfterUserspaceReboot) {
13252 sOSKextWasResetAfterUserspaceReboot = false;
13253 OSKext::setIOKitDaemonActive();
13254 IOService::startDeferredMatches();
13255 }
13256 }
13257
13258 if (ret == kOSKextReturnKCLoadFailure) {
13259 ret |= kcerr;
13260 }
13261
13262 /*
13263 * Only allow this function to attempt to load the pageable and
13264 * aux KCs once per boot.
13265 */
13266 daemon_ready = true;
13267
13268 IORecursiveLockUnlock(sKextLock);
13269
13270 return ret;
13271 }
13272
13273 OSReturn
13274 OSKext::resetMutableSegments(void)
13275 {
13276 kernel_segment_command_t *seg = NULL;
13277 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13278 u_int index = 0;
13279 OSKextSavedMutableSegment *savedSegment = NULL;
13280 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
13281 OSReturn err;
13282
13283 if (!savedMutableSegments) {
13284 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13285 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13286 err = kOSKextReturnInternalError;
13287 goto finish;
13288 }
13289
13290 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
13291 if (!segmentIsMutable(seg)) {
13292 continue;
13293 }
13294 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13295 uint64_t vmsize = seg->vmsize;
13296 err = kOSKextReturnInternalError;
13297 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13298 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13299 assert(savedSegment);
13300 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13301 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13302 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13303 err = savedSegment->restoreContents(seg);
13304 if (err != kOSReturnSuccess) {
13305 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13306 }
13307 }
13308 }
13309 if (err != kOSReturnSuccess) {
13310 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13311 }
13312 }
13313 err = kOSReturnSuccess;
13314 finish:
13315 return err;
13316 }
13317
13318
13319 /*********************************************************************
13320 * Assumes sKextLock is held.
13321 *********************************************************************/
13322 /* static */
13323 OSReturn
13324 OSKext::loadKCFileSet(
13325 const char *filepath,
13326 kc_kind_t type)
13327 {
13328 #if VM_MAPPED_KEXTS
13329 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13330 OSReturn err;
13331 struct vnode *vp = NULL;
13332 void *fileset_control;
13333 off_t fsize;
13334 bool pageable = (type == KCKindPageable);
13335
13336 if ((pageable && pageableKCloaded) ||
13337 (!pageable && auxKCloaded)) {
13338 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13339 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13340
13341 return kOSKextReturnInvalidArgument;
13342 }
13343
13344 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13345 if (!pageable && !pageableKCloaded) {
13346 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13347 "Trying to load the Aux KC without loading the Pageable KC");
13348 return kOSKextReturnInvalidArgument;
13349 }
13350
13351 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13352
13353 if (fileset_control == NULL) {
13354 printf("Could not get memory control object for file %s", filepath);
13355
13356 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13357 "Could not get memory control object for file %s", filepath);
13358 return kOSKextReturnInvalidArgument;
13359 }
13360 if (vp == NULL) {
13361 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13362 "Could not find vnode for file %s", filepath);
13363 return kOSKextReturnInvalidArgument;
13364 }
13365
13366 kernel_mach_header_t *mh = NULL;
13367 uintptr_t slide = 0;
13368
13369 #if CONFIG_CSR
13370 /*
13371 * When SIP is enabled, the KC we map must be SIP-protected
13372 */
13373 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13374 struct vnode_attr va;
13375 int error;
13376 VATTR_INIT(&va);
13377 VATTR_WANTED(&va, va_flags);
13378 error = vnode_getattr(vp, &va, vfs_context_current());
13379 if (error) {
13380 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13381 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13382 err = kOSKextReturnInternalError;
13383 goto finish;
13384 }
13385 if (!(va.va_flags & SF_RESTRICTED)) {
13386 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13387 "Path to KC '%s' is not SIP-protected", filepath);
13388 err = kOSKextReturnInvalidArgument;
13389 goto finish;
13390 }
13391 }
13392 #endif
13393
13394 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13395 if (err) {
13396 printf("KextLog: mapKCFileSet returned %d\n", err);
13397
13398 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13399 "mapKCFileSet returned %d\n", err);
13400
13401 err = kOSKextReturnInvalidArgument;
13402 }
13403
13404 #if CONFIG_CSR
13405 finish:
13406 #endif
13407 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13408 assert(vp != NULL);
13409 if (err == kOSReturnSuccess) {
13410 PE_set_kc_vp(type, vp);
13411 if (pageable) {
13412 pageableKCloaded = true;
13413 } else {
13414 auxKCloaded = true;
13415 }
13416 } else {
13417 vnode_put(vp);
13418 }
13419
13420 return err;
13421 #else
13422 (void)filepath;
13423 (void)type;
13424 return kOSKextReturnUnsupported;
13425 #endif // VM_MAPPED_KEXTS
13426 }
13427
13428 #if defined(__x86_64__) || defined(__i386__)
13429 /*********************************************************************
13430 * Assumes sKextLock is held.
13431 *********************************************************************/
13432 /* static */
13433 OSReturn
13434 OSKext::mapKCFileSet(
13435 void *control,
13436 vm_size_t fsize,
13437 kernel_mach_header_t **mhp,
13438 off_t file_offset,
13439 uintptr_t *slidep,
13440 bool pageable,
13441 void *map_entry_list)
13442 {
13443 bool fileset_load = false;
13444 kern_return_t ret;
13445 OSReturn err;
13446 kernel_section_t *infoPlistSection = NULL;
13447 OSDictionary *infoDict = NULL;
13448
13449 OSSharedPtr<OSObject> parsedXML;
13450 OSSharedPtr<OSString> errorString;
13451 OSSharedPtr<OSData> loaded_kcUUID;
13452
13453 /* Check if initial load for file set */
13454 if (*mhp == NULL) {
13455 fileset_load = true;
13456
13457 /* Get a page aligned address from kext map to map the file */
13458 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13459 if (pagealigned_addr == 0) {
13460 return kOSKextReturnNoMemory;
13461 }
13462
13463 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13464
13465 /* Allocate memory for bailout mechanism */
13466 map_entry_list = allocate_kcfileset_map_entry_list();
13467 if (map_entry_list == NULL) {
13468 return kOSKextReturnNoMemory;
13469 }
13470 }
13471
13472 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13473 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13474 /* mhp and slideptr are updated by mapKCTextSegment */
13475 if (err) {
13476 if (fileset_load) {
13477 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13478 }
13479 return err;
13480 }
13481
13482 /* Initialize the kc header globals */
13483 if (fileset_load) {
13484 if (pageable) {
13485 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13486 } else {
13487 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13488 }
13489 }
13490
13491 /* Iterate through all the segments and map necessary segments */
13492 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13493 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13494 vm_map_offset_t start;
13495 kernel_mach_header_t *k_mh = NULL;
13496 kernel_segment_command_t * seg = NULL;
13497 struct fileset_entry_command *fse = NULL;
13498
13499 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13500 seg = (kernel_segment_command_t *)lcp;
13501 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13502 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13503 fse = (struct fileset_entry_command *)lcp;
13504 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13505
13506 /* Map the segments of the mach-o binary */
13507 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13508 if (err) {
13509 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13510 return kOSKextReturnInvalidArgument;
13511 }
13512 continue;
13513 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13514 /* Check if the Aux KC is built pageable style */
13515 if (!pageable && !fileset_load && !auxKCloaded) {
13516 resetAuxKCSegmentOnUnload = true;
13517 }
13518 continue;
13519 } else {
13520 continue;
13521 }
13522
13523 if (fileset_load) {
13524 if (seg->vmsize == 0) {
13525 continue;
13526 }
13527
13528 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13529 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13530 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13531 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13532 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13533 continue;
13534 }
13535 } else {
13536 if (seg->vmsize == 0) {
13537 continue;
13538 }
13539
13540 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13541 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13542 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13543 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13544 continue;
13545 }
13546 }
13547
13548 ret = vm_map_kcfileset_segment(
13549 &start, seg->vmsize,
13550 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13551
13552 if (ret != KERN_SUCCESS) {
13553 if (fileset_load) {
13554 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13555 }
13556 return kOSKextReturnInvalidArgument;
13557 }
13558 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13559 }
13560
13561 /* Return if regular mach-o */
13562 if (!fileset_load) {
13563 return 0;
13564 }
13565
13566 /*
13567 * Fixup for the Pageable KC and the Aux KC is done by
13568 * i386_slide_kext_collection_mh_addrs, but it differs in
13569 * following ways:
13570 *
13571 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13572 * The fixup of kext segments and kext load commands are done at kext
13573 * load time by calling i386_slide_individual_kext.
13574 *
13575 * AuxKC old style: Fixup all the segments and all the load commands.
13576 *
13577 * AuxKC pageable style: Same as the Pageable KC.
13578 */
13579 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13580 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13581 if (ret != KERN_SUCCESS) {
13582 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13583 return kOSKextReturnInvalidArgument;
13584 }
13585
13586 /* Get the prelink info dictionary */
13587 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13588 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13589 if (parsedXML) {
13590 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13591 }
13592
13593 if (!infoDict) {
13594 const char *errorCString = "(unknown error)";
13595
13596 if (errorString && errorString->getCStringNoCopy()) {
13597 errorCString = errorString->getCStringNoCopy();
13598 } else if (parsedXML) {
13599 errorCString = "not a dictionary";
13600 }
13601 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13602 "Error unserializing kext info plist section: %s.", errorCString);
13603 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13604 return kOSKextReturnInvalidArgument;
13605 }
13606
13607 /* Validate that the Kext Collection is prelinked to the loaded KC */
13608 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13609 if (err) {
13610 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13611 return kOSKextReturnInvalidArgument;
13612 }
13613
13614 /* Set Protection of Segments */
13615 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13616
13617 OSKext::addKextsFromKextCollection(*mhp,
13618 infoDict, kPrelinkTextSegment,
13619 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13620
13621 /* Copy in the KC UUID */
13622 if (!loaded_kcUUID) {
13623 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13624 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13625 } else if (pageable) {
13626 pageablekc_uuid_valid = TRUE;
13627 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13628 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13629 } else {
13630 auxkc_uuid_valid = TRUE;
13631 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13632 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13633 }
13634
13635 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13636
13637 return 0;
13638 }
13639
13640 /*********************************************************************
13641 * Assumes sKextLock is held.
13642 *********************************************************************/
13643 /* static */
13644 OSReturn
13645 OSKext::mapKCTextSegment(
13646 void *control,
13647 kernel_mach_header_t **mhp,
13648 off_t file_offset,
13649 uintptr_t *slidep,
13650 void *map_entry_list)
13651 {
13652 kern_return_t ret;
13653 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13654 PAGE_MASK);
13655 vm_map_offset_t load_command_map_size = 0;
13656 kernel_mach_header_t *base_mh = *mhp;
13657
13658 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13659 ret = vm_map_kcfileset_segment(
13660 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13661 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13662
13663 if (ret != KERN_SUCCESS) {
13664 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13665
13666 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13667 "Failed to map mach header of kc fileset with error %d", ret);
13668 return kOSKextReturnInvalidArgument;
13669 }
13670
13671 if (slidep) {
13672 /* Verify that it's an MH_FILESET */
13673 if (base_mh->filetype != MH_FILESET) {
13674 printf("Kext Log: mapKCTextSegment mach header filetype"
13675 " is not an MH_FILESET, it is %x", base_mh->filetype);
13676
13677 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13678 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
13679
13680 /* Unmap the mach header */
13681 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13682 return kOSKextReturnInvalidArgument;
13683 }
13684 }
13685
13686 /* Map the remaining pages of load commands */
13687 if (base_mh->sizeofcmds > mach_header_map_size) {
13688 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13689 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13690
13691 /* Map the load commands */
13692 ret = vm_map_kcfileset_segment(
13693 &load_command_addr, load_command_map_size,
13694 (memory_object_control_t)control, file_offset + mach_header_map_size,
13695 (VM_PROT_READ | VM_PROT_WRITE));
13696
13697 if (ret != KERN_SUCCESS) {
13698 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13699 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13700 "Failed to map load commands of kc fileset with error %d", ret);
13701
13702 /* Unmap the mach header */
13703 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13704 return kOSKextReturnInvalidArgument;
13705 }
13706 }
13707
13708 kernel_segment_command_t *text_seg;
13709 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13710
13711 /* Calculate the slide and vm addr of mach header */
13712 if (slidep) {
13713 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13714 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13715 }
13716
13717 /* Cache the text segment size and file offset before unmapping */
13718 vm_map_offset_t text_segment_size = text_seg->vmsize;
13719 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13720 vm_prot_t text_maxprot = text_seg->maxprot;
13721
13722 /* Unmap the first page and loadcommands and map the text segment */
13723 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13724 assert(ret == KERN_SUCCESS);
13725
13726 if (load_command_map_size) {
13727 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13728 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13729 assert(ret == KERN_SUCCESS);
13730 }
13731
13732 /* Map the text segment at actual vm addr specified in fileset */
13733 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13734 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13735 if (ret != KERN_SUCCESS) {
13736 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13737 "Failed to map Text segment of kc fileset with error %d", ret);
13738 return kOSKextReturnInvalidArgument;
13739 }
13740
13741 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13742 return 0;
13743 }
13744
13745 /*********************************************************************
13746 * Assumes sKextLock is held.
13747 *********************************************************************/
13748 /* static */
13749 OSReturn
13750 OSKext::protectKCFileSet(
13751 kernel_mach_header_t *mh,
13752 kc_kind_t type)
13753 {
13754 vm_map_t kext_map = g_kext_map;
13755 kernel_segment_command_t * seg = NULL;
13756 vm_map_offset_t start = 0;
13757 vm_map_offset_t end = 0;
13758 OSReturn ret = 0;
13759
13760 /* Set VM permissions */
13761 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13762 while (seg) {
13763 start = round_page(seg->vmaddr);
13764 end = trunc_page(seg->vmaddr + seg->vmsize);
13765
13766 /*
13767 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13768 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13769 * for the Aux KC as well.
13770 */
13771 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13772 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13773 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13774 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13775 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13776 ret = OSKext_protect((kernel_mach_header_t *)mh,
13777 kext_map, start, end, seg->maxprot, TRUE, type);
13778 if (ret != KERN_SUCCESS) {
13779 printf("OSKext protect failed with error %d", ret);
13780 return kOSKextReturnInvalidArgument;
13781 }
13782
13783 ret = OSKext_protect((kernel_mach_header_t *)mh,
13784 kext_map, start, end, seg->initprot, FALSE, type);
13785 if (ret != KERN_SUCCESS) {
13786 printf("OSKext protect failed with error %d", ret);
13787 return kOSKextReturnInvalidArgument;
13788 }
13789
13790 ret = OSKext_wire((kernel_mach_header_t *)mh,
13791 kext_map, start, end, seg->initprot, FALSE, type);
13792 if (ret != KERN_SUCCESS) {
13793 printf("OSKext wire failed with error %d", ret);
13794 return kOSKextReturnInvalidArgument;
13795 }
13796 }
13797
13798 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13799 }
13800
13801 return 0;
13802 }
13803
13804 /*********************************************************************
13805 * Assumes sKextLock is held.
13806 *********************************************************************/
13807 /* static */
13808 void
13809 OSKext::freeKCFileSetcontrol(void)
13810 {
13811 PE_reset_all_kc_vp();
13812 }
13813
13814 /*********************************************************************
13815 * Assumes sKextLock is held.
13816 *
13817 * resetKCFileSetSegments: Kext start function expects data segment to
13818 * be pristine on every load, unmap the dirty segments on unload and
13819 * remap them from FileSet on disk. Remap all segments of kext since
13820 * fixups are done per kext and not per segment.
13821 *********************************************************************/
13822 OSReturn
13823 OSKext::resetKCFileSetSegments(void)
13824 {
13825 kernel_segment_command_t *seg = NULL;
13826 kernel_segment_command_t *text_seg;
13827 uint32_t text_fileoff;
13828 kernel_mach_header_t *k_mh = NULL;
13829 uintptr_t slide;
13830 struct vnode *vp = NULL;
13831 void *fileset_control = NULL;
13832 bool pageable = (kc_type == KCKindPageable);
13833 OSReturn err;
13834 kern_return_t kr;
13835
13836 /* Check the vnode reference is still available */
13837 vp = (struct vnode *)PE_get_kc_vp(kc_type);
13838 if (vp == NULL) {
13839 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13840 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
13841 return kOSKextReturnInternalError;
13842 }
13843
13844 fileset_control = ubc_getobject(vp, 0);
13845 assert(fileset_control != NULL);
13846
13847 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13848 "Kext %s resetting all segments", getIdentifierCString());
13849
13850 k_mh = (kernel_mach_header_t *)kmod_info->address;
13851 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
13852 text_fileoff = text_seg->fileoff;
13853 slide = PE_get_kc_slide(kc_type);
13854
13855 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
13856 while (seg) {
13857 if (seg->vmsize == 0) {
13858 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13859 continue;
13860 }
13861
13862 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13863 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13864 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13865 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13866 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13867 continue;
13868 }
13869
13870 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
13871 assert(kr == KERN_SUCCESS);
13872 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
13873 }
13874
13875 /* Unmap the text segment */
13876 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
13877 assert(kr == KERN_SUCCESS);
13878
13879 /* Map all the segments of the kext */
13880 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
13881 if (err) {
13882 panic("Could not reset segments of a mapped kext, error %x", err);
13883 }
13884
13885 /* Update address in kmod_info, since it has been reset */
13886 if (kmod_info->address) {
13887 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
13888 }
13889
13890 return 0;
13891 }
13892
13893 /*********************************************************************
13894 * Mechanism to track all segment mapping while mapping KC fileset.
13895 *********************************************************************/
13896
13897 struct kcfileset_map_entry {
13898 vm_map_offset_t me_start;
13899 vm_map_offset_t me_size;
13900 };
13901
13902 struct kcfileset_map_entry_list {
13903 int kme_list_count;
13904 int kme_list_index;
13905 struct kcfileset_map_entry kme_list[];
13906 };
13907
13908 #define KCFILESET_MAP_ENTRY_MAX (16380)
13909
13910 static void *
13911 allocate_kcfileset_map_entry_list(void)
13912 {
13913 struct kcfileset_map_entry_list *entry_list;
13914
13915 entry_list = kalloc_type(struct kcfileset_map_entry_list,
13916 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
13917
13918 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
13919 entry_list->kme_list_index = 0;
13920 return entry_list;
13921 }
13922
13923 static void
13924 add_kcfileset_map_entry(
13925 void *map_entry_list,
13926 vm_map_offset_t start,
13927 vm_map_offset_t size)
13928 {
13929 if (map_entry_list == NULL) {
13930 return;
13931 }
13932
13933 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
13934
13935 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
13936 panic("Ran out of map kc fileset list");
13937 }
13938
13939 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
13940 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
13941
13942 entry_list->kme_list_index++;
13943 }
13944
13945 static void
13946 deallocate_kcfileset_map_entry_list_and_unmap_entries(
13947 void *map_entry_list,
13948 boolean_t unmap_entries,
13949 bool pageable)
13950 {
13951 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
13952
13953 if (unmap_entries) {
13954 for (int i = 0; i < entry_list->kme_list_index; i++) {
13955 kern_return_t ret;
13956 ret = vm_unmap_kcfileset_segment(
13957 &(entry_list->kme_list[i].me_start),
13958 entry_list->kme_list[i].me_size);
13959 assert(ret == KERN_SUCCESS);
13960 }
13961
13962 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
13963 }
13964
13965 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
13966 KCFILESET_MAP_ENTRY_MAX, entry_list);
13967 }
13968
13969 /*********************************************************************
13970 * Mechanism to map kext segment.
13971 *********************************************************************/
13972
13973 kern_return_t
13974 vm_map_kcfileset_segment(
13975 vm_map_offset_t *start,
13976 vm_map_offset_t size,
13977 void *control,
13978 vm_object_offset_t fileoffset,
13979 vm_prot_t max_prot)
13980 {
13981 vm_map_kernel_flags_t vmk_flags = {
13982 .vmf_fixed = true,
13983 .vmkf_no_copy_on_read = true,
13984 .vmkf_cs_enforcement_override = true,
13985 .vm_tag = VM_KERN_MEMORY_OSKEXT,
13986 };
13987 kern_return_t ret;
13988
13989 /* Add Write to max prot to allow fixups */
13990 max_prot = max_prot | VM_PROT_WRITE;
13991
13992 /*
13993 * Map the segments from file as COPY mappings to
13994 * make sure changes on disk to the file does not affect
13995 * mapped segments.
13996 */
13997 ret = vm_map_enter_mem_object_control(
13998 g_kext_map,
13999 start,
14000 size,
14001 (mach_vm_offset_t)0,
14002 vmk_flags,
14003 (memory_object_control_t)control,
14004 fileoffset,
14005 TRUE, /* copy */
14006 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
14007 VM_INHERIT_NONE);
14008
14009 return ret;
14010 }
14011
14012 kern_return_t
14013 vm_unmap_kcfileset_segment(
14014 vm_map_offset_t *start,
14015 vm_map_offset_t size)
14016 {
14017 return mach_vm_deallocate(g_kext_map, *start, size);
14018 }
14019
14020 #endif //(__x86_64__) || defined(__i386__)
14021
14022 /*********************************************************************
14023 * Assumes sKextLock is held.
14024 *********************************************************************/
14025 /* static */
14026 OSReturn
14027 OSKext::validateKCFileSetUUID(
14028 OSDictionary *infoDict,
14029 kc_kind_t type)
14030 {
14031 OSReturn ret = kOSReturnSuccess;
14032
14033 if (!kernelcache_uuid_valid) {
14034 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14035 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
14036 ret = kOSKextReturnInvalidArgument;
14037 goto finish;
14038 }
14039 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
14040 if (ret != 0) {
14041 goto finish;
14042 }
14043
14044 #if defined(__x86_64__) || defined(__i386__)
14045 /* Check if the Aux KC is prelinked to correct Pageable KC */
14046 if (type == KCKindAuxiliary) {
14047 if (!pageablekc_uuid_valid) {
14048 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14049 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
14050 ret = kOSKextReturnInvalidArgument;
14051 goto finish;
14052 }
14053 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
14054 if (ret != 0) {
14055 goto finish;
14056 }
14057 }
14058 #endif //(__x86_64__) || defined(__i386__)
14059
14060 printf("KextLog: Collection UUID matches with loaded KCs.\n");
14061 finish:
14062 return ret;
14063 }
14064
14065 /*********************************************************************
14066 * Assumes sKextLock is held.
14067 *********************************************************************/
14068 /* static */
14069 OSReturn
14070 OSKext::validateKCUUIDfromPrelinkInfo(
14071 uuid_t *loaded_kcuuid,
14072 kc_kind_t type,
14073 OSDictionary *infoDict,
14074 const char *uuid_key)
14075 {
14076 /* extract the UUID from the dictionary */
14077 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
14078 if (!prelinkinfoKCUUID) {
14079 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14080 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
14081 return kOSKextReturnInvalidArgument;
14082 }
14083
14084 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
14085 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14086 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
14087 return kOSKextReturnInvalidArgument;
14088 }
14089
14090 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
14091 prelinkinfoKCUUID->getLength())) {
14092 OSData *info_dict_uuid;
14093 uuid_string_t info_dict_uuid_str = {};
14094 uuid_string_t expected_uuid_str = {};
14095 uuid_string_t given_uuid_str = {};
14096 uuid_t given_uuid;
14097
14098 /* extract the KC UUID from the dictionary */
14099 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
14100 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
14101 uuid_t tmp_uuid;
14102 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
14103 uuid_unparse(tmp_uuid, info_dict_uuid_str);
14104 }
14105
14106 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
14107 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
14108 uuid_unparse(given_uuid, given_uuid_str);
14109
14110 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14111 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14112 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14113 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14114 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14115 if (type == KCKindPageable && sPanicOnKCMismatch) {
14116 panic("System KC UUID %s linked against %s, but %s is loaded",
14117 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14118 }
14119 return kOSKextReturnInvalidArgument;
14120 }
14121
14122 return 0;
14123 }
14124
14125 /*********************************************************************
14126 * Assumes sKextLock is held.
14127 *********************************************************************/
14128 /* static */
14129 OSReturn
14130 OSKext::dispatchResource(OSDictionary * requestDict)
14131 {
14132 OSReturn result = kOSReturnError;
14133 OSSharedPtr<OSDictionary> callbackRecord;
14134 OSNumber * requestTag = NULL; // do not release
14135 OSNumber * requestResult = NULL; // do not release
14136 OSData * dataObj = NULL; // do not release
14137 uint32_t dataLength = 0;
14138 const void * dataPtr = NULL; // do not free
14139 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14140 OSKextRequestResourceCallback callback = NULL;
14141 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14142 void * context = NULL; // do not free
14143 OSSharedPtr<OSKext> callbackKext;
14144
14145 /* Get the args from the request. Right now we need the tag
14146 * to look up the callback record, and the result for invoking the callback.
14147 */
14148 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14149 kKextRequestArgumentRequestTagKey));
14150 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14151 kKextRequestArgumentResultKey));
14152 if (!requestTag || !requestResult) {
14153 result = kOSKextReturnInvalidArgument;
14154 goto finish;
14155 }
14156
14157 /* Look for a callback record matching this request's tag.
14158 */
14159 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
14160 if (result != kOSReturnSuccess) {
14161 goto finish;
14162 }
14163
14164 /*****
14165 * Get the context pointer of the callback record (if there is one).
14166 */
14167 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14168 callbackRecord.get(), kKextRequestArgumentContextKey));
14169 context = _OSKextExtractPointer(contextWrapper);
14170 if (contextWrapper && !context) {
14171 goto finish;
14172 }
14173
14174 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14175 _OSKextGetRequestArgument(callbackRecord.get(),
14176 kKextRequestArgumentCallbackKey));
14177 callback = _OSKextExtractCallbackPointer(callbackWrapper);
14178 if (!callback) {
14179 goto finish;
14180 }
14181
14182 /* Check for a data obj. We might not have one and that's ok, that means
14183 * we didn't find the requested resource, and we still have to tell the
14184 * caller that via the callback.
14185 */
14186 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14187 kKextRequestArgumentValueKey));
14188 if (dataObj) {
14189 dataPtr = dataObj->getBytesNoCopy();
14190 dataLength = dataObj->getLength();
14191 }
14192
14193 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
14194 if (!callbackKext) {
14195 OSKextLog(/* kext */ NULL,
14196 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14197 "Can't invoke callback for resource request; ");
14198 goto finish;
14199 }
14200 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14201 OSKextLog(/* kext */ NULL,
14202 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14203 "Can't invoke kext resource callback; ");
14204 goto finish;
14205 }
14206
14207 (void)callback(requestTag->unsigned32BitValue(),
14208 (OSReturn)requestResult->unsigned32BitValue(),
14209 dataPtr, dataLength, context);
14210
14211 result = kOSReturnSuccess;
14212
14213 finish:
14214 return result;
14215 }
14216
14217 /*********************************************************************
14218 * Assumes sKextLock is held.
14219 *********************************************************************/
14220 /* static */
14221 OSReturn
14222 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14223 {
14224 OSSharedPtr<OSDictionary> missingIDs;
14225 OSArray *bundleIDList = NULL; // do not release
14226
14227 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14228 requestDict, kKextRequestArgumentMissingBundleIDs));
14229 if (!bundleIDList) {
14230 return kOSKextReturnInvalidArgument;
14231 }
14232
14233 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
14234 if (!missingIDs) {
14235 return kOSKextReturnNoMemory;
14236 }
14237
14238 uint32_t count, i;
14239 count = bundleIDList->getCount();
14240 for (i = 0; i < count; i++) {
14241 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14242 if (thisID) {
14243 missingIDs->setObject(thisID, kOSBooleanFalse);
14244 }
14245 }
14246
14247 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
14248
14249 return kOSReturnSuccess;
14250 }
14251
14252 /*********************************************************************
14253 * Assumes sKextLock is held.
14254 *********************************************************************/
14255 /* static */
14256 OSReturn
14257 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14258 {
14259 bool loadable = true;
14260 if (!kextIdentifier) {
14261 return kOSKextReturnInvalidArgument;
14262 }
14263
14264 if (requestDict) {
14265 OSBoolean *loadableArg;
14266 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14267 requestDict, kKextRequestArgumentBundleAvailability));
14268 /* If we find the "Bundle Available" arg, and it's false, then
14269 * mark the bundle ID as _not_ loadable
14270 */
14271 if (loadableArg && !loadableArg->getValue()) {
14272 loadable = false;
14273 }
14274 }
14275
14276 if (!sNonLoadableKextsByID) {
14277 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
14278 }
14279
14280 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
14281
14282 OSKextLog(/* kext */ NULL,
14283 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14284 "KextLog: AuxKC bundle %s marked as %s",
14285 kextIdentifier->getCStringNoCopy(),
14286 (loadable ? "loadable" : "NOT loadable"));
14287
14288 return kOSReturnSuccess;
14289 }
14290
14291 /*********************************************************************
14292 *********************************************************************/
14293 /* static */
14294 void
14295 OSKext::invokeRequestCallback(
14296 OSDictionary * callbackRecord,
14297 OSReturn callbackResult)
14298 {
14299 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
14300 OSSharedPtr<OSNumber> resultNum;
14301
14302 if (!predicate) {
14303 goto finish;
14304 }
14305
14306 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
14307 8 * sizeof(callbackResult));
14308 if (!resultNum) {
14309 goto finish;
14310 }
14311
14312 /* Insert the result into the callback record and dispatch it as if it
14313 * were the reply coming down from user space.
14314 */
14315 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
14316 resultNum.get());
14317
14318 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14319 /* This removes the pending callback record.
14320 */
14321 OSKext::dispatchResource(callbackRecord);
14322 }
14323
14324 finish:
14325 return;
14326 }
14327
14328 /*********************************************************************
14329 * Assumes sKextLock is held.
14330 *********************************************************************/
14331 /* static */
14332 OSReturn
14333 OSKext::cancelRequest(
14334 OSKextRequestTag requestTag,
14335 void ** contextOut)
14336 {
14337 OSReturn result = kOSKextReturnNoMemory;
14338 OSSharedPtr<OSDictionary> callbackRecord;
14339 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14340
14341 IORecursiveLockLock(sKextLock);
14342 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14343 callbackRecord);
14344 IORecursiveLockUnlock(sKextLock);
14345
14346 if (result == kOSReturnSuccess && contextOut) {
14347 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14348 _OSKextGetRequestArgument(callbackRecord.get(),
14349 kKextRequestArgumentContextKey));
14350 *contextOut = _OSKextExtractPointer(contextWrapper);
14351 }
14352
14353 return result;
14354 }
14355
14356 /*********************************************************************
14357 * Assumes sKextLock is held.
14358 *********************************************************************/
14359 void
14360 OSKext::invokeOrCancelRequestCallbacks(
14361 OSReturn callbackResult,
14362 bool invokeFlag)
14363 {
14364 unsigned int count, i;
14365
14366 count = sRequestCallbackRecords->getCount();
14367 if (!count) {
14368 goto finish;
14369 }
14370
14371 i = count - 1;
14372 do {
14373 OSDictionary * request = OSDynamicCast(OSDictionary,
14374 sRequestCallbackRecords->getObject(i));
14375
14376 if (!request) {
14377 continue;
14378 }
14379 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14380 _OSKextGetRequestArgument(request,
14381 kKextRequestArgumentCallbackKey));
14382
14383 if (!callbackWrapper) {
14384 sRequestCallbackRecords->removeObject(i);
14385 continue;
14386 }
14387
14388 vm_address_t callbackAddress = (vm_address_t)
14389 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14390
14391 if ((kmod_info->address <= callbackAddress) &&
14392 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14393 if (invokeFlag) {
14394 /* This removes the callback record.
14395 */
14396 invokeRequestCallback(request, callbackResult);
14397 } else {
14398 sRequestCallbackRecords->removeObject(i);
14399 }
14400 }
14401 } while (i--);
14402
14403 finish:
14404 return;
14405 }
14406
14407 /*********************************************************************
14408 * Assumes sKextLock is held.
14409 *********************************************************************/
14410 uint32_t
14411 OSKext::countRequestCallbacks(void)
14412 {
14413 uint32_t result = 0;
14414 unsigned int count, i;
14415
14416 count = sRequestCallbackRecords->getCount();
14417 if (!count) {
14418 goto finish;
14419 }
14420
14421 i = count - 1;
14422 do {
14423 OSDictionary * request = OSDynamicCast(OSDictionary,
14424 sRequestCallbackRecords->getObject(i));
14425
14426 if (!request) {
14427 continue;
14428 }
14429 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14430 _OSKextGetRequestArgument(request,
14431 kKextRequestArgumentCallbackKey));
14432
14433 if (!callbackWrapper) {
14434 continue;
14435 }
14436
14437 vm_address_t callbackAddress = (vm_address_t)
14438 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14439
14440 if ((kmod_info->address <= callbackAddress) &&
14441 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14442 result++;
14443 }
14444 } while (i--);
14445
14446 finish:
14447 return result;
14448 }
14449
14450 /*********************************************************************
14451 *********************************************************************/
14452 static OSReturn
14453 _OSKextCreateRequest(
14454 const char * predicate,
14455 OSSharedPtr<OSDictionary> & requestR)
14456 {
14457 OSReturn result = kOSKextReturnNoMemory;
14458 OSSharedPtr<OSDictionary> request;
14459
14460 request = OSDictionary::withCapacity(2);
14461 if (!request) {
14462 goto finish;
14463 }
14464 result = _OSDictionarySetCStringValue(request.get(),
14465 kKextRequestPredicateKey, predicate);
14466 if (result != kOSReturnSuccess) {
14467 goto finish;
14468 }
14469 result = kOSReturnSuccess;
14470
14471 finish:
14472 if (result == kOSReturnSuccess) {
14473 requestR = os::move(request);
14474 }
14475
14476 return result;
14477 }
14478
14479 /*********************************************************************
14480 *********************************************************************/
14481 static OSString *
14482 _OSKextGetRequestPredicate(OSDictionary * requestDict)
14483 {
14484 return OSDynamicCast(OSString,
14485 requestDict->getObject(kKextRequestPredicateKey));
14486 }
14487
14488 /*********************************************************************
14489 *********************************************************************/
14490 static OSObject *
14491 _OSKextGetRequestArgument(
14492 OSDictionary * requestDict,
14493 const char * argName)
14494 {
14495 OSDictionary * args = OSDynamicCast(OSDictionary,
14496 requestDict->getObject(kKextRequestArgumentsKey));
14497 if (args) {
14498 return args->getObject(argName);
14499 }
14500 return NULL;
14501 }
14502
14503 /*********************************************************************
14504 *********************************************************************/
14505 static bool
14506 _OSKextSetRequestArgument(
14507 OSDictionary * requestDict,
14508 const char * argName,
14509 OSMetaClassBase * value)
14510 {
14511 OSDictionary * args = OSDynamicCast(OSDictionary,
14512 requestDict->getObject(kKextRequestArgumentsKey));
14513 OSSharedPtr<OSDictionary> newArgs;
14514 if (!args) {
14515 newArgs = OSDictionary::withCapacity(2);
14516 args = newArgs.get();
14517 if (!args) {
14518 goto finish;
14519 }
14520 requestDict->setObject(kKextRequestArgumentsKey, args);
14521 }
14522 if (args) {
14523 return args->setObject(argName, value);
14524 }
14525 finish:
14526 return false;
14527 }
14528
14529 /*********************************************************************
14530 *********************************************************************/
14531 template <typename T>
14532 static T *
14533 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
14534 {
14535 if (!wrapper) {
14536 return nullptr;
14537 }
14538 return wrapper->getRef();
14539 }
14540
14541 /*********************************************************************
14542 *********************************************************************/
14543 static OSKextRequestResourceCallback
14544 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14545 {
14546 if (!wrapper) {
14547 return nullptr;
14548 }
14549 return wrapper->getRef();
14550 }
14551
14552
14553 /*********************************************************************
14554 *********************************************************************/
14555 static OSReturn
14556 _OSDictionarySetCStringValue(
14557 OSDictionary * dict,
14558 const char * cKey,
14559 const char * cValue)
14560 {
14561 OSReturn result = kOSKextReturnNoMemory;
14562 OSSharedPtr<const OSSymbol> key;
14563 OSSharedPtr<OSString> value;
14564
14565 key = OSSymbol::withCString(cKey);
14566 value = OSString::withCString(cValue);
14567 if (!key || !value) {
14568 goto finish;
14569 }
14570 if (dict->setObject(key.get(), value.get())) {
14571 result = kOSReturnSuccess;
14572 }
14573
14574 finish:
14575 return result;
14576 }
14577
14578 /*********************************************************************
14579 *********************************************************************/
14580 static bool
14581 _OSArrayContainsCString(
14582 OSArray * array,
14583 const char * cString)
14584 {
14585 bool result = false;
14586 OSSharedPtr<const OSSymbol> symbol;
14587 uint32_t count, i;
14588
14589 if (!array || !cString) {
14590 goto finish;
14591 }
14592
14593 symbol = OSSymbol::withCStringNoCopy(cString);
14594 if (!symbol) {
14595 goto finish;
14596 }
14597
14598 count = array->getCount();
14599 for (i = 0; i < count; i++) {
14600 OSObject * thisObject = array->getObject(i);
14601 if (symbol->isEqualTo(thisObject)) {
14602 result = true;
14603 goto finish;
14604 }
14605 }
14606
14607 finish:
14608 return result;
14609 }
14610
14611 #if CONFIG_KXLD
14612 /*********************************************************************
14613 * We really only care about boot / system start up related kexts.
14614 * We return true if we're less than REBUILD_MAX_TIME since start up,
14615 * otherwise return false.
14616 *********************************************************************/
14617 bool
14618 _OSKextInPrelinkRebuildWindow(void)
14619 {
14620 static bool outside_the_window = false;
14621 AbsoluteTime my_abstime;
14622 UInt64 my_ns;
14623 SInt32 my_secs;
14624
14625 if (outside_the_window) {
14626 return false;
14627 }
14628 clock_get_uptime(&my_abstime);
14629 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14630 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14631 if (my_secs > REBUILD_MAX_TIME) {
14632 outside_the_window = true;
14633 return false;
14634 }
14635 return true;
14636 }
14637 #endif /* CONFIG_KXLD */
14638
14639 /*********************************************************************
14640 *********************************************************************/
14641 bool
14642 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14643 {
14644 int unLoadedCount, i;
14645 bool result = false;
14646
14647 IORecursiveLockLock(sKextLock);
14648
14649 if (sUnloadedPrelinkedKexts == NULL) {
14650 goto finish;
14651 }
14652 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14653 if (unLoadedCount == 0) {
14654 goto finish;
14655 }
14656
14657 for (i = 0; i < unLoadedCount; i++) {
14658 const OSSymbol * myBundleID; // do not release
14659
14660 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14661 if (!myBundleID) {
14662 continue;
14663 }
14664 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
14665 result = true;
14666 break;
14667 }
14668 }
14669 finish:
14670 IORecursiveLockUnlock(sKextLock);
14671 return result;
14672 }
14673
14674 #if PRAGMA_MARK
14675 #pragma mark Personalities (IOKit Drivers)
14676 #endif
14677 /*********************************************************************
14678 *********************************************************************/
14679 /* static */
14680 OSSharedPtr<OSArray>
14681 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14682 {
14683 OSSharedPtr<OSArray> result;
14684 OSSharedPtr<OSCollectionIterator> kextIterator;
14685 OSSharedPtr<OSArray> personalities;
14686
14687 OSString * kextID = NULL; // do not release
14688 OSKext * theKext = NULL; // do not release
14689
14690 IORecursiveLockLock(sKextLock);
14691
14692 /* Let's conservatively guess that any given kext has around 3
14693 * personalities for now.
14694 */
14695 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
14696 if (!result) {
14697 goto finish;
14698 }
14699
14700 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
14701 if (!kextIterator) {
14702 goto finish;
14703 }
14704
14705 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14706 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14707 if (theKext->flags.requireExplicitLoad) {
14708 OSKextLog(theKext,
14709 kOSKextLogDebugLevel |
14710 kOSKextLogLoadFlag,
14711 "Kext %s requires an explicit kextload; "
14712 "omitting its personalities.",
14713 theKext->getIdentifierCString());
14714 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14715 personalities = theKext->copyPersonalitiesArray();
14716 if (!personalities) {
14717 continue;
14718 }
14719 result->merge(personalities.get());
14720 } else {
14721 // xxx - check for better place to put this log msg
14722 OSKextLog(theKext,
14723 kOSKextLogWarningLevel |
14724 kOSKextLogLoadFlag,
14725 "Kext %s is not loadable during safe boot; "
14726 "omitting its personalities.",
14727 theKext->getIdentifierCString());
14728 }
14729 }
14730
14731 finish:
14732 IORecursiveLockUnlock(sKextLock);
14733
14734 return result;
14735 }
14736
14737 /*********************************************************************
14738 *********************************************************************/
14739 /* static */
14740 void
14741 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14742 {
14743 int numPersonalities = 0;
14744
14745 OSKextLog(/* kext */ NULL,
14746 kOSKextLogStepLevel |
14747 kOSKextLogLoadFlag,
14748 "Sending all eligible registered kexts' personalities "
14749 "to the IOCatalogue %s.",
14750 startMatching ? "and starting matching" : "but not starting matching");
14751
14752 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14753 /* filterSafeBootFlag */ true);
14754
14755 if (personalities) {
14756 gIOCatalogue->addDrivers(personalities.get(), startMatching);
14757 numPersonalities = personalities->getCount();
14758 }
14759
14760 OSKextLog(/* kext */ NULL,
14761 kOSKextLogStepLevel |
14762 kOSKextLogLoadFlag,
14763 "%d kext personalit%s sent to the IOCatalogue; %s.",
14764 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14765 startMatching ? "matching started" : "matching not started");
14766 return;
14767 }
14768
14769 /*********************************************************************
14770 * Do not make a deep copy, just convert the IOKitPersonalities dict
14771 * to an array for sending to the IOCatalogue.
14772 *********************************************************************/
14773 OSSharedPtr<OSArray>
14774 OSKext::copyPersonalitiesArray(void)
14775 {
14776 OSSharedPtr<OSArray> result;
14777 OSDictionary * personalities = NULL; // do not release
14778 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14779
14780 OSString * personalityName = NULL; // do not release
14781 OSString * personalityBundleIdentifier = NULL; // do not release
14782
14783 personalities = OSDynamicCast(OSDictionary,
14784 getPropertyForHostArch(kIOKitPersonalitiesKey));
14785 if (!personalities) {
14786 goto finish;
14787 }
14788
14789 result = OSArray::withCapacity(personalities->getCount());
14790 if (!result) {
14791 goto finish;
14792 }
14793
14794 personalitiesIterator =
14795 OSCollectionIterator::withCollection(personalities);
14796 if (!personalitiesIterator) {
14797 goto finish;
14798 }
14799 while ((personalityName = OSDynamicCast(OSString,
14800 personalitiesIterator->getNextObject()))) {
14801 OSDictionary * personality = OSDynamicCast(OSDictionary,
14802 personalities->getObject(personalityName));
14803
14804 if (personality) {
14805 /******
14806 * If the personality doesn't have a CFBundleIdentifier, or if it
14807 * differs from the kext's, insert the kext's ID so we can find it.
14808 * The publisher ID is used to remove personalities from bundles
14809 * correctly.
14810 */
14811 personalityBundleIdentifier = OSDynamicCast(OSString,
14812 personality->getObject(kCFBundleIdentifierKey));
14813
14814 if (!personalityBundleIdentifier) {
14815 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
14816 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
14817 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
14818 }
14819 }
14820
14821 result->setObject(personality);
14822 }
14823
14824 finish:
14825 return result;
14826 }
14827
14828 /*********************************************************************
14829 * Might want to change this to a bool return?
14830 *********************************************************************/
14831 OSReturn
14832 OSKext::sendPersonalitiesToCatalog(
14833 bool startMatching,
14834 OSArray * personalityNames)
14835 {
14836 OSReturn result = kOSReturnSuccess;
14837 OSSharedPtr<OSArray> personalitiesToSend;
14838 OSDictionary * kextPersonalities = NULL; // do not release
14839 int count, i;
14840
14841 if (!sLoadEnabled) {
14842 OSKextLog(this,
14843 kOSKextLogErrorLevel |
14844 kOSKextLogLoadFlag,
14845 "Kext loading is disabled (attempt to start matching for kext %s).",
14846 getIdentifierCString());
14847 result = kOSKextReturnDisabled;
14848 goto finish;
14849 }
14850
14851 if (sSafeBoot && !isLoadableInSafeBoot()) {
14852 OSKextLog(this,
14853 kOSKextLogErrorLevel |
14854 kOSKextLogLoadFlag,
14855 "Kext %s is not loadable during safe boot; "
14856 "not sending personalities to the IOCatalogue.",
14857 getIdentifierCString());
14858 result = kOSKextReturnNotLoadable;
14859 goto finish;
14860 }
14861
14862 if (!personalityNames || !personalityNames->getCount()) {
14863 personalitiesToSend = copyPersonalitiesArray();
14864 } else {
14865 kextPersonalities = OSDynamicCast(OSDictionary,
14866 getPropertyForHostArch(kIOKitPersonalitiesKey));
14867 if (!kextPersonalities || !kextPersonalities->getCount()) {
14868 // not an error
14869 goto finish;
14870 }
14871 personalitiesToSend = OSArray::withCapacity(0);
14872 if (!personalitiesToSend) {
14873 result = kOSKextReturnNoMemory;
14874 goto finish;
14875 }
14876 count = personalityNames->getCount();
14877 for (i = 0; i < count; i++) {
14878 OSString * name = OSDynamicCast(OSString,
14879 personalityNames->getObject(i));
14880 if (!name) {
14881 continue;
14882 }
14883 OSDictionary * personality = OSDynamicCast(OSDictionary,
14884 kextPersonalities->getObject(name));
14885 if (personality) {
14886 personalitiesToSend->setObject(personality);
14887 }
14888 }
14889 }
14890 if (personalitiesToSend) {
14891 unsigned numPersonalities = personalitiesToSend->getCount();
14892 OSKextLog(this,
14893 kOSKextLogStepLevel |
14894 kOSKextLogLoadFlag,
14895 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
14896 getIdentifierCString(),
14897 numPersonalities,
14898 numPersonalities > 1 ? "ies" : "y",
14899 startMatching ? " and starting matching" : " but not starting matching");
14900 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
14901 }
14902 finish:
14903 return result;
14904 }
14905
14906 /*********************************************************************
14907 * xxx - We should allow removing the kext's declared personalities,
14908 * xxx - even with other bundle identifiers.
14909 *********************************************************************/
14910 void
14911 OSKext::removePersonalitiesFromCatalog(void)
14912 {
14913 OSSharedPtr<OSDictionary> personality;
14914
14915 personality = OSDictionary::withCapacity(1);
14916 if (!personality) {
14917 goto finish;
14918 }
14919 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
14920
14921 OSKextLog(this,
14922 kOSKextLogStepLevel |
14923 kOSKextLogLoadFlag,
14924 "Kext %s removing all personalities naming it from the IOCatalogue.",
14925 getIdentifierCString());
14926
14927 /* Have the IOCatalog remove all personalities matching this kext's
14928 * bundle ID and trigger matching anew.
14929 */
14930 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
14931
14932 finish:
14933 return;
14934 }
14935
14936 void
14937 OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
14938 {
14939 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
14940 return;
14941 }
14942
14943 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(1);
14944 if (!personalityToRemove) {
14945 return;
14946 }
14947
14948 /*
14949 * Create a personality dictionary with just the bundleID.
14950 * We will remove any personality that has a matching bundleID,
14951 * irrespective of which other keys are present on the dictionary.
14952 */
14953 personalityToRemove->setObject(kCFBundleIdentifierKey, getIdentifier());
14954 gIOCatalogue->exchangeDrivers(personalityToRemove.get(), upgradedPersonalities, true);
14955 }
14956
14957 #if PRAGMA_MARK
14958 #pragma mark Logging
14959 #endif
14960 /*********************************************************************
14961 * Do not call any function that takes sKextLock here!
14962 *********************************************************************/
14963 /* static */
14964 OSKextLogSpec
14965 OSKext::setUserSpaceLogFilter(
14966 OSKextLogSpec newUserLogFilter,
14967 bool captureFlag)
14968 {
14969 OSKextLogSpec result;
14970 bool allocError = false;
14971
14972 /* Do not call any function that takes sKextLoggingLock during
14973 * this critical block. That means do logging after.
14974 */
14975 IOLockLock(sKextLoggingLock);
14976
14977 result = sUserSpaceKextLogFilter;
14978 sUserSpaceKextLogFilter = newUserLogFilter;
14979
14980 if (newUserLogFilter && captureFlag &&
14981 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
14982 // xxx - do some measurements for a good initial capacity?
14983 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
14984 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
14985
14986 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
14987 allocError = true;
14988 }
14989 }
14990
14991 IOLockUnlock(sKextLoggingLock);
14992
14993 /* If the config flag itself is changing, log the state change
14994 * going both ways, before setting up the user-space log arrays,
14995 * so that this is only logged in the kernel.
14996 */
14997 if (result != newUserLogFilter) {
14998 OSKextLog(/* kext */ NULL,
14999 kOSKextLogDebugLevel |
15000 kOSKextLogGeneralFlag,
15001 "User-space log flags changed from 0x%x to 0x%x.",
15002 result, newUserLogFilter);
15003 }
15004 if (allocError) {
15005 OSKextLog(/* kext */ NULL,
15006 kOSKextLogErrorLevel |
15007 kOSKextLogGeneralFlag,
15008 "Failed to allocate user-space log message arrays.");
15009 }
15010
15011 return result;
15012 }
15013
15014 /*********************************************************************
15015 * Do not call any function that takes sKextLock here!
15016 *********************************************************************/
15017 /* static */
15018 OSSharedPtr<OSArray>
15019 OSKext::clearUserSpaceLogFilter(void)
15020 {
15021 OSSharedPtr<OSArray> result;
15022 OSKextLogSpec oldLogFilter;
15023 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
15024
15025 /* Do not call any function that takes sKextLoggingLock during
15026 * this critical block. That means do logging after.
15027 */
15028 IOLockLock(sKextLoggingLock);
15029
15030 result = OSArray::withCapacity(2);
15031 if (result) {
15032 result->setObject(sUserSpaceLogSpecArray.get());
15033 result->setObject(sUserSpaceLogMessageArray.get());
15034 }
15035 sUserSpaceLogSpecArray.reset();
15036 sUserSpaceLogMessageArray.reset();
15037
15038 oldLogFilter = sUserSpaceKextLogFilter;
15039 sUserSpaceKextLogFilter = newLogFilter;
15040
15041 IOLockUnlock(sKextLoggingLock);
15042
15043 /* If the config flag itself is changing, log the state change
15044 * going both ways, after tearing down the user-space log
15045 * arrays, so this is only logged within the kernel.
15046 */
15047 if (oldLogFilter != newLogFilter) {
15048 OSKextLog(/* kext */ NULL,
15049 kOSKextLogDebugLevel |
15050 kOSKextLogGeneralFlag,
15051 "User-space log flags changed from 0x%x to 0x%x.",
15052 oldLogFilter, newLogFilter);
15053 }
15054
15055 return result;
15056 }
15057
15058
15059 /*********************************************************************
15060 * Do not call any function that takes sKextLock here!
15061 *********************************************************************/
15062 /* static */
15063 OSKextLogSpec
15064 OSKext::getUserSpaceLogFilter(void)
15065 {
15066 OSKextLogSpec result;
15067
15068 IOLockLock(sKextLoggingLock);
15069 result = sUserSpaceKextLogFilter;
15070 IOLockUnlock(sKextLoggingLock);
15071
15072 return result;
15073 }
15074
15075 /*********************************************************************
15076 * This function is called by OSMetaClass during kernel C++ setup.
15077 * Be careful what you access here; assume only OSKext::initialize()
15078 * has been called.
15079 *
15080 * Do not call any function that takes sKextLock here!
15081 *********************************************************************/
15082 #define VTRESET "\033[0m"
15083
15084 #define VTBOLD "\033[1m"
15085 #define VTUNDER "\033[4m"
15086
15087 #define VTRED "\033[31m"
15088 #define VTGREEN "\033[32m"
15089 #define VTYELLOW "\033[33m"
15090 #define VTBLUE "\033[34m"
15091 #define VTMAGENTA "\033[35m"
15092 #define VTCYAN "\033[36m"
15093
15094 inline const char *
15095 colorForFlags(OSKextLogSpec flags)
15096 {
15097 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
15098
15099 switch (logLevel) {
15100 case kOSKextLogErrorLevel:
15101 return VTRED VTBOLD;
15102 case kOSKextLogWarningLevel:
15103 return VTRED;
15104 case kOSKextLogBasicLevel:
15105 return VTYELLOW VTUNDER;
15106 case kOSKextLogProgressLevel:
15107 return VTYELLOW;
15108 case kOSKextLogStepLevel:
15109 return VTGREEN;
15110 case kOSKextLogDetailLevel:
15111 return VTCYAN;
15112 case kOSKextLogDebugLevel:
15113 return VTMAGENTA;
15114 default:
15115 return ""; // white
15116 }
15117 }
15118
15119 inline bool
15120 logSpecMatch(
15121 OSKextLogSpec msgLogSpec,
15122 OSKextLogSpec logFilter)
15123 {
15124 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15125 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15126 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15127
15128 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15129 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15130 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15131
15132 /* Explicit messages always get logged.
15133 */
15134 if (msgLevel == kOSKextLogExplicitLevel) {
15135 return true;
15136 }
15137
15138 /* Warnings and errors are logged regardless of the flags.
15139 */
15140 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15141 return true;
15142 }
15143
15144 /* A verbose message that isn't for a logging-enabled kext and isn't global
15145 * does *not* get logged.
15146 */
15147 if (!msgKextGlobal && !filterKextGlobal) {
15148 return false;
15149 }
15150
15151 /* Warnings and errors are logged regardless of the flags.
15152 * All other messages must fit the flags and
15153 * have a level at or below the filter.
15154 *
15155 */
15156 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15157 return true;
15158 }
15159 return false;
15160 }
15161
15162 extern "C" {
15163 void
15164 OSKextLog(
15165 OSKext * aKext,
15166 OSKextLogSpec msgLogSpec,
15167 const char * format, ...)
15168 {
15169 va_list argList;
15170
15171 va_start(argList, format);
15172 OSKextVLog(aKext, msgLogSpec, format, argList);
15173 va_end(argList);
15174 }
15175
15176 void
15177 OSKextVLog(
15178 OSKext * aKext,
15179 OSKextLogSpec msgLogSpec,
15180 const char * format,
15181 va_list srcArgList)
15182 {
15183 bool logForKernel = false;
15184 bool logForUser = false;
15185 va_list argList;
15186 char stackBuffer[120];
15187 uint32_t length = 0;
15188 char * allocBuffer = NULL; // must kfree
15189 OSSharedPtr<OSNumber> logSpecNum;
15190 OSSharedPtr<OSString> logString;
15191 char * buffer = stackBuffer; // do not free
15192
15193 IOLockLock(sKextLoggingLock);
15194
15195 /* Set the kext/global bit in the message spec if we have no
15196 * kext or if the kext requests logging.
15197 */
15198 if (!aKext || aKext->flags.loggingEnabled) {
15199 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15200 }
15201
15202 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
15203 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15204 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
15205 }
15206
15207 if (!(logForKernel || logForUser)) {
15208 goto finish;
15209 }
15210
15211 /* No goto from here until past va_end()!
15212 */
15213 va_copy(argList, srcArgList);
15214 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15215 va_end(argList);
15216
15217 if (length + 1 >= sizeof(stackBuffer)) {
15218 allocBuffer = (char *)kalloc_data_tag(length + 1,
15219 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15220 if (!allocBuffer) {
15221 goto finish;
15222 }
15223
15224 /* No goto from here until past va_end()!
15225 */
15226 va_copy(argList, srcArgList);
15227 vsnprintf(allocBuffer, length + 1, format, argList);
15228 va_end(argList);
15229
15230 buffer = allocBuffer;
15231 }
15232
15233 /* If user space wants the log message, queue it up.
15234 */
15235 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15236 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
15237 logString = OSString::withCString(buffer);
15238 if (logSpecNum && logString) {
15239 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15240 sUserSpaceLogMessageArray->setObject(logString.get());
15241 }
15242 }
15243
15244 /* Always log messages from the kernel according to the kernel's
15245 * log flags.
15246 */
15247 if (logForKernel) {
15248 /* If we are in console mode and have a custom log filter,
15249 * colorize the log message.
15250 */
15251 if (sBootArgLogFilterFound) {
15252 const char * color = ""; // do not free
15253 color = colorForFlags(msgLogSpec);
15254 printf("%s%s%s\n", colorForFlags(msgLogSpec),
15255 buffer, color[0] ? VTRESET : "");
15256 } else {
15257 printf("%s\n", buffer);
15258 }
15259 }
15260
15261 finish:
15262 IOLockUnlock(sKextLoggingLock);
15263
15264 if (allocBuffer) {
15265 kfree_data(allocBuffer, length + 1);
15266 }
15267 return;
15268 }
15269
15270 #if KASLR_IOREG_DEBUG
15271
15272 #define IOLOG_INDENT( the_indention ) \
15273 { \
15274 int i; \
15275 for ( i = 0; i < (the_indention); i++ ) { \
15276 IOLog(" "); \
15277 } \
15278 }
15279
15280 extern vm_offset_t vm_kernel_stext;
15281 extern vm_offset_t vm_kernel_etext;
15282 extern mach_vm_offset_t kext_alloc_base;
15283 extern mach_vm_offset_t kext_alloc_max;
15284
15285 bool ScanForAddrInObject(OSObject * theObject,
15286 int indent );
15287
15288 bool
15289 ScanForAddrInObject(OSObject * theObject,
15290 int indent)
15291 {
15292 const OSMetaClass * myTypeID;
15293 OSSharedPtr<OSCollectionIterator> myIter;
15294 OSSymbol * myKey;
15295 OSObject * myValue;
15296 bool myResult = false;
15297
15298 if (theObject == NULL) {
15299 IOLog("%s: theObject is NULL \n",
15300 __FUNCTION__);
15301 return myResult;
15302 }
15303
15304 myTypeID = OSTypeIDInst(theObject);
15305
15306 if (myTypeID == OSTypeID(OSDictionary)) {
15307 OSDictionary * myDictionary;
15308
15309 myDictionary = OSDynamicCast(OSDictionary, theObject);
15310 myIter = OSCollectionIterator::withCollection( myDictionary );
15311 if (myIter == NULL) {
15312 return myResult;
15313 }
15314
15315 // !! reset the iterator
15316 myIter->reset();
15317
15318 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15319 bool myTempResult;
15320
15321 myValue = myDictionary->getObject(myKey);
15322 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15323 if (myTempResult) {
15324 // if we ever get a true result return true
15325 myResult = true;
15326 IOLOG_INDENT(indent);
15327 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15328 }
15329 }
15330
15331 // !! release the iterator
15332 myIter.reset();
15333 } else if (myTypeID == OSTypeID(OSArray)) {
15334 OSArray * myArray;
15335
15336 myArray = OSDynamicCast(OSArray, theObject);
15337 myIter = OSCollectionIterator::withCollection(myArray);
15338 if (myIter == NULL) {
15339 return myResult;
15340 }
15341 // !! reset the iterator
15342 myIter->reset();
15343
15344 while ((myValue = myIter->getNextObject())) {
15345 bool myTempResult;
15346 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15347 if (myTempResult) {
15348 // if we ever get a true result return true
15349 myResult = true;
15350 IOLOG_INDENT(indent);
15351 IOLog("OSArray: \n");
15352 }
15353 }
15354 // !! release the iterator
15355 myIter.reset();
15356 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15357 // should we look for addresses in strings?
15358 } else if (myTypeID == OSTypeID(OSData)) {
15359 void * * myPtrPtr;
15360 unsigned int myLen;
15361 OSData * myDataObj;
15362
15363 myDataObj = OSDynamicCast(OSData, theObject);
15364 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15365 myLen = myDataObj->getLength();
15366
15367 if (myPtrPtr && myLen && myLen > 7) {
15368 int i;
15369 int myPtrCount = (myLen / sizeof(void *));
15370
15371 for (i = 0; i < myPtrCount; i++) {
15372 UInt64 numberValue = (UInt64) * (myPtrPtr);
15373
15374 if (kext_alloc_max != 0 &&
15375 numberValue >= kext_alloc_base &&
15376 numberValue < kext_alloc_max) {
15377 OSSharedPtr<OSKext> myKext;
15378 // IOLog("found OSData %p in kext map %p to %p \n",
15379 // *(myPtrPtr),
15380 // (void *) kext_alloc_base,
15381 // (void *) kext_alloc_max);
15382
15383 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15384 if (myKext) {
15385 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15386 *(myPtrPtr),
15387 myKext->getIdentifierCString());
15388 }
15389 myResult = true;
15390 }
15391 if (vm_kernel_etext != 0 &&
15392 numberValue >= vm_kernel_stext &&
15393 numberValue < vm_kernel_etext) {
15394 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15395 *(myPtrPtr),
15396 (void *) vm_kernel_stext,
15397 (void *) vm_kernel_etext);
15398 myResult = true;
15399 }
15400 myPtrPtr++;
15401 }
15402 }
15403 } else if (myTypeID == OSTypeID(OSBoolean)) {
15404 // do nothing here...
15405 } else if (myTypeID == OSTypeID(OSNumber)) {
15406 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15407
15408 UInt64 numberValue = number->unsigned64BitValue();
15409
15410 if (kext_alloc_max != 0 &&
15411 numberValue >= kext_alloc_base &&
15412 numberValue < kext_alloc_max) {
15413 OSSharedPtr<OSKext> myKext;
15414 IOLog("found OSNumber in kext map %p to %p \n",
15415 (void *) kext_alloc_base,
15416 (void *) kext_alloc_max);
15417 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15418
15419 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15420 if (myKext) {
15421 IOLog("found in kext \"%s\" \n",
15422 myKext->getIdentifierCString());
15423 }
15424
15425 myResult = true;
15426 }
15427 if (vm_kernel_etext != 0 &&
15428 numberValue >= vm_kernel_stext &&
15429 numberValue < vm_kernel_etext) {
15430 IOLog("found OSNumber in kernel text segment %p to %p \n",
15431 (void *) vm_kernel_stext,
15432 (void *) vm_kernel_etext);
15433 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15434 myResult = true;
15435 }
15436 }
15437 #if 0
15438 else {
15439 const OSMetaClass* myMetaClass = NULL;
15440
15441 myMetaClass = theObject->getMetaClass();
15442 if (myMetaClass) {
15443 IOLog("class %s \n", myMetaClass->getClassName());
15444 } else {
15445 IOLog("Unknown object \n" );
15446 }
15447 }
15448 #endif
15449
15450 return myResult;
15451 }
15452 #endif // KASLR_KEXT_DEBUG
15453 }; /* extern "C" */
15454
15455 #if PRAGMA_MARK
15456 #pragma mark Backtrace Dump & kmod_get_info() support
15457 #endif
15458 /*********************************************************************
15459 * This function must be safe to call in panic context.
15460 *********************************************************************/
15461 /* static */
15462 void
15463 OSKext::printKextsInBacktrace(
15464 vm_offset_t * addr __unused,
15465 unsigned int cnt __unused,
15466 int (* printf_func)(const char *fmt, ...) __unused,
15467 uint32_t flags __unused)
15468 {
15469 addr64_t summary_page = 0;
15470 addr64_t last_summary_page = 0;
15471 bool found_kmod = false;
15472 u_int i = 0;
15473
15474 if (kPrintKextsLock & flags) {
15475 if (!sKextSummariesLock) {
15476 return;
15477 }
15478 IOLockLock(sKextSummariesLock);
15479 }
15480
15481 if (!gLoadedKextSummaries) {
15482 (*printf_func)(" can't perform kext scan: no kext summary");
15483 goto finish;
15484 }
15485
15486 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15487 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
15488 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15489 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
15490 (*printf_func)(" can't perform kext scan: "
15491 "missing kext summary page %p", summary_page);
15492 goto finish;
15493 }
15494 }
15495
15496 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15497 OSKextLoadedKextSummary * summary;
15498
15499 summary = gLoadedKextSummaries->summaries + i;
15500 if (!summary->address) {
15501 continue;
15502 }
15503
15504 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15505 continue;
15506 }
15507
15508 if (!found_kmod) {
15509 if (!(kPrintKextsTerse & flags)) {
15510 (*printf_func)(" Kernel Extensions in backtrace:\n");
15511 }
15512 found_kmod = true;
15513 }
15514
15515 printSummary(summary, printf_func, flags);
15516 }
15517
15518 finish:
15519 if (kPrintKextsLock & flags) {
15520 IOLockUnlock(sKextSummariesLock);
15521 }
15522
15523 return;
15524 }
15525
15526 /*********************************************************************
15527 * This function must be safe to call in panic context.
15528 *********************************************************************/
15529 /* static */
15530 boolean_t
15531 OSKext::summaryIsInBacktrace(
15532 OSKextLoadedKextSummary * summary,
15533 vm_offset_t * addr,
15534 unsigned int cnt)
15535 {
15536 u_int i = 0;
15537
15538 for (i = 0; i < cnt; i++) {
15539 vm_offset_t kscan_addr = addr[i];
15540 #if __has_feature(ptrauth_calls)
15541 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15542 #endif /* __has_feature(ptrauth_calls) */
15543 if ((kscan_addr >= summary->text_exec_address) &&
15544 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15545 return TRUE;
15546 }
15547 }
15548
15549 return FALSE;
15550 }
15551
15552 /*
15553 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15554 * sKextSummariesLock held.
15555 */
15556 OSKextLoadedKextSummary *
15557 OSKext::summaryForAddress(uintptr_t addr)
15558 {
15559 #if __has_feature(ptrauth_calls)
15560 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15561 #endif /* __has_feature(ptrauth_calls) */
15562 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15563 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15564 if (!summary->address) {
15565 continue;
15566 }
15567
15568 #if VM_MAPPED_KEXTS
15569 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15570 * support split kexts, but we also may unmap the kexts, which can
15571 * race with the above codepath (see OSKext::unload). As such,
15572 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15573 */
15574 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15575 return summary;
15576 }
15577 #else
15578 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15579 kernel_segment_command_t *seg;
15580
15581 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
15582 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15583 return summary;
15584 }
15585 }
15586 #endif
15587 }
15588
15589 /* addr did not map to any kext */
15590 return NULL;
15591 }
15592
15593 /* static */
15594 void *
15595 OSKext::kextForAddress(const void *address)
15596 {
15597 OSKextActiveAccount * active;
15598 OSKext * kext = NULL;
15599 uint32_t baseIdx;
15600 uint32_t lim;
15601 uintptr_t addr = (uintptr_t) address;
15602 size_t i;
15603
15604 if (!addr) {
15605 return NULL;
15606 }
15607 #if __has_feature(ptrauth_calls)
15608 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15609 #endif /* __has_feature(ptrauth_calls) */
15610
15611 if (sKextAccountsCount) {
15612 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
15613 // bsearch sKextAccounts list
15614 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15615 active = &sKextAccounts[baseIdx + (lim >> 1)];
15616 if ((addr >= active->address) && (addr < active->address_end)) {
15617 kext = active->account->kext;
15618 if (kext && kext->kmod_info) {
15619 lck_ticket_unlock(sKextAccountsLock);
15620 return (void *)kext->kmod_info->address;
15621 }
15622 break;
15623 } else if (addr > active->address) {
15624 // move right
15625 baseIdx += (lim >> 1) + 1;
15626 lim--;
15627 }
15628 // else move left
15629 }
15630 lck_ticket_unlock(sKextAccountsLock);
15631 }
15632 if (kernel_text_contains(addr)) {
15633 return (void *)&_mh_execute_header;
15634 }
15635 if (gLoadedKextSummaries) {
15636 IOLockLock(sKextSummariesLock);
15637 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15638 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15639 if (addr >= summary->address && addr < summary->address + summary->size) {
15640 void *kextAddress = (void *)summary->address;
15641 IOLockUnlock(sKextSummariesLock);
15642 return kextAddress;
15643 }
15644 }
15645 IOLockUnlock(sKextSummariesLock);
15646 }
15647
15648 return NULL;
15649 }
15650
15651 /* static */
15652 kern_return_t
15653 OSKext::summaryForAddressExt(
15654 const void * address,
15655 OSKextLoadedKextSummary * summary)
15656 {
15657 kern_return_t result = KERN_FAILURE;
15658 const OSKextLoadedKextSummary * foundSummary = NULL;
15659
15660 /*
15661 * This needs to be safe to call even before the lock has been initialized
15662 * in OSKext::initialize(), as we might get here from the ksancov runtime
15663 * when instrumenting XNU itself with sanitizer coverage.
15664 */
15665 if (!sKextSummariesLock) {
15666 return result;
15667 }
15668
15669 IOLockLock(sKextSummariesLock);
15670 if (gLoadedKextSummaries) {
15671 foundSummary = summaryForAddress((uintptr_t)address);
15672 if (foundSummary) {
15673 memcpy(summary, foundSummary, sizeof(*summary));
15674 result = KERN_SUCCESS;
15675 } else {
15676 result = KERN_NOT_FOUND;
15677 }
15678 }
15679 IOLockUnlock(sKextSummariesLock);
15680
15681 return result;
15682 }
15683
15684 /*
15685 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15686 * Safe to call in panic context.
15687 */
15688 static OSKextLoadedKextSummary *
15689 findSummary(uint32_t tagID)
15690 {
15691 OSKextLoadedKextSummary * summary;
15692 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15693 summary = gLoadedKextSummaries->summaries + i;
15694 if (summary->loadTag == tagID) {
15695 return summary;
15696 }
15697 }
15698 return NULL;
15699 }
15700
15701 /*********************************************************************
15702 * This function must be safe to call in panic context.
15703 *********************************************************************/
15704 void
15705 OSKext::printSummary(
15706 OSKextLoadedKextSummary * summary,
15707 int (* printf_func)(const char *fmt, ...),
15708 uint32_t flags)
15709 {
15710 kmod_reference_t * kmod_ref = NULL;
15711 uuid_string_t uuid;
15712 char version[kOSKextVersionMaxLength];
15713 uint64_t tmpAddr;
15714 uint64_t tmpSize;
15715 OSKextLoadedKextSummary *dependencySummary;
15716
15717 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
15718 strlcpy(version, "unknown version", sizeof(version));
15719 }
15720 (void) uuid_unparse(summary->uuid, uuid);
15721
15722 #if defined(__arm__) || defined(__arm64__)
15723 tmpAddr = summary->text_exec_address;
15724 tmpSize = summary->text_exec_size;
15725 #else
15726 tmpAddr = summary->address;
15727 tmpSize = summary->size;
15728 #endif
15729 if (kPrintKextsUnslide & flags) {
15730 tmpAddr = ml_static_unslide(tmpAddr);
15731 }
15732 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15733 (kPrintKextsTerse & flags) ? "" : " ",
15734 summary->name, version, uuid,
15735 tmpAddr, tmpAddr + tmpSize - 1);
15736
15737 if (kPrintKextsTerse & flags) {
15738 return;
15739 }
15740
15741 /* print dependency info */
15742 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15743 kmod_ref;
15744 kmod_ref = kmod_ref->next) {
15745 kmod_info_t * rinfo;
15746
15747 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15748 (*printf_func)(" kmod dependency scan stopped "
15749 "due to missing dependency page: %p\n",
15750 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
15751 break;
15752 }
15753 rinfo = kmod_ref->info;
15754
15755 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
15756 (*printf_func)(" kmod dependency scan stopped "
15757 "due to missing kmod page: %p\n",
15758 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
15759 break;
15760 }
15761
15762 if (!rinfo->address) {
15763 continue; // skip fake entries for built-ins
15764 }
15765
15766 dependencySummary = findSummary(rinfo->id);
15767 uuid[0] = 0x00;
15768 tmpAddr = rinfo->address;
15769 tmpSize = rinfo->size;
15770 if (dependencySummary) {
15771 (void) uuid_unparse(dependencySummary->uuid, uuid);
15772 #if defined(__arm__) || defined(__arm64__)
15773 tmpAddr = dependencySummary->text_exec_address;
15774 tmpSize = dependencySummary->text_exec_size;
15775 #endif
15776 }
15777
15778 if (kPrintKextsUnslide & flags) {
15779 tmpAddr = ml_static_unslide(tmpAddr);
15780 }
15781 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15782 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15783 }
15784 return;
15785 }
15786
15787
15788 #if !defined(__arm__) && !defined(__arm64__)
15789 /*******************************************************************************
15790 * substitute() looks at an input string (a pointer within a larger buffer)
15791 * for a match to a substring, and on match it writes the marker & substitution
15792 * character to an output string, updating the scan (from) and
15793 * output (to) indexes as appropriate.
15794 *******************************************************************************/
15795 static int substitute(
15796 const char * scan_string,
15797 char * string_out,
15798 uint32_t * to_index,
15799 uint32_t * from_index,
15800 const char * substring,
15801 char marker,
15802 char substitution);
15803
15804 /* string_out must be at least KMOD_MAX_NAME bytes.
15805 */
15806 static int
15807 substitute(
15808 const char * scan_string,
15809 char * string_out,
15810 uint32_t * to_index,
15811 uint32_t * from_index,
15812 const char * substring,
15813 char marker,
15814 char substitution)
15815 {
15816 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
15817
15818 /* On a substring match, append the marker (if there is one) and then
15819 * the substitution character, updating the output (to) index accordingly.
15820 * Then update the input (from) length by the length of the substring
15821 * that got replaced.
15822 */
15823 if (!strncmp(scan_string, substring, substring_length)) {
15824 if (marker) {
15825 string_out[(*to_index)++] = marker;
15826 }
15827 string_out[(*to_index)++] = substitution;
15828 (*from_index) += substring_length;
15829 return 1;
15830 }
15831 return 0;
15832 }
15833
15834 /*******************************************************************************
15835 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
15836 * KMOD_MAX_NAME characters and performs various substitutions of common
15837 * prefixes & substrings as defined by tables in kext_panic_report.h.
15838 *******************************************************************************/
15839 static void compactIdentifier(
15840 const char * identifier,
15841 char * identifier_out,
15842 char ** identifier_out_end);
15843
15844 static void
15845 compactIdentifier(
15846 const char * identifier,
15847 char * identifier_out,
15848 char ** identifier_out_end)
15849 {
15850 uint32_t from_index, to_index;
15851 uint32_t scan_from_index = 0;
15852 uint32_t scan_to_index = 0;
15853 subs_entry_t * subs_entry = NULL;
15854 int did_sub = 0;
15855
15856 from_index = to_index = 0;
15857 identifier_out[0] = '\0';
15858
15859 /* Replace certain identifier prefixes with shorter @+character sequences.
15860 * Check the return value of substitute() so we only replace the prefix.
15861 */
15862 for (subs_entry = &kext_identifier_prefix_subs[0];
15863 subs_entry->substring && !did_sub;
15864 subs_entry++) {
15865 did_sub = substitute(identifier, identifier_out,
15866 &scan_to_index, &scan_from_index,
15867 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
15868 }
15869 did_sub = 0;
15870
15871 /* Now scan through the identifier looking for the common substrings
15872 * and replacing them with shorter !+character sequences via substitute().
15873 */
15874 for (/* see above */;
15875 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
15876 /* see loop */) {
15877 const char * scan_string = &identifier[scan_from_index];
15878
15879 did_sub = 0;
15880
15881 if (scan_from_index) {
15882 for (subs_entry = &kext_identifier_substring_subs[0];
15883 subs_entry->substring && !did_sub;
15884 subs_entry++) {
15885 did_sub = substitute(scan_string, identifier_out,
15886 &scan_to_index, &scan_from_index,
15887 subs_entry->substring, '!', subs_entry->substitute);
15888 }
15889 }
15890
15891 /* If we didn't substitute, copy the input character to the output.
15892 */
15893 if (!did_sub) {
15894 identifier_out[scan_to_index++] = identifier[scan_from_index++];
15895 }
15896 }
15897
15898 identifier_out[scan_to_index] = '\0';
15899 if (identifier_out_end) {
15900 *identifier_out_end = &identifier_out[scan_to_index];
15901 }
15902
15903 return;
15904 }
15905 #endif /* !defined(__arm__) && !defined(__arm64__) */
15906
15907 /*******************************************************************************
15908 * assemble_identifier_and_version() adds to a string buffer a compacted
15909 * bundle identifier followed by a version string.
15910 *******************************************************************************/
15911
15912 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
15913 */
15914 static size_t assemble_identifier_and_version(
15915 kmod_info_t * kmod_info,
15916 char * identPlusVers,
15917 size_t bufSize);
15918
15919 static size_t
15920 assemble_identifier_and_version(
15921 kmod_info_t * kmod_info,
15922 char * identPlusVers,
15923 size_t bufSize)
15924 {
15925 size_t result = 0;
15926
15927 #if defined(__arm__) || defined(__arm64__)
15928 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
15929 #else
15930 compactIdentifier(kmod_info->name, identPlusVers, NULL);
15931 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
15932 #endif
15933 identPlusVers[result++] = '\t'; // increment for real char
15934 identPlusVers[result] = '\0'; // don't increment for nul char
15935 result = strlcat(identPlusVers, kmod_info->version, bufSize);
15936 if (result >= bufSize) {
15937 identPlusVers[bufSize - 1] = '\0';
15938 result = bufSize - 1;
15939 }
15940
15941 return result;
15942 }
15943
15944 /*******************************************************************************
15945 * Assumes sKextLock is held.
15946 *******************************************************************************/
15947 /* static */
15948 int
15949 OSKext::saveLoadedKextPanicListTyped(
15950 const char * prefix,
15951 int invertFlag,
15952 int libsFlag,
15953 char * paniclist,
15954 uint32_t list_size)
15955 {
15956 int result = -1;
15957 unsigned int count, i;
15958
15959 count = sLoadedKexts->getCount();
15960 if (!count) {
15961 goto finish;
15962 }
15963
15964 i = count - 1;
15965 do {
15966 OSObject * rawKext = sLoadedKexts->getObject(i);
15967 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
15968 int match;
15969 size_t identPlusVersLength;
15970 size_t tempLen;
15971 char identPlusVers[2 * KMOD_MAX_NAME];
15972
15973 if (!rawKext) {
15974 printf("OSKext::saveLoadedKextPanicListTyped - "
15975 "NULL kext in loaded kext list; continuing\n");
15976 continue;
15977 }
15978
15979 if (!theKext) {
15980 printf("OSKext::saveLoadedKextPanicListTyped - "
15981 "Kext type cast failed in loaded kext list; continuing\n");
15982 continue;
15983 }
15984
15985 /* Skip all built-in kexts.
15986 */
15987 if (theKext->isKernelComponent()) {
15988 continue;
15989 }
15990
15991 kmod_info_t * kmod_info = theKext->kmod_info;
15992
15993 /* Filter for kmod name (bundle identifier).
15994 */
15995 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
15996 if ((match && invertFlag) || (!match && !invertFlag)) {
15997 continue;
15998 }
15999
16000 /* Filter for libraries (kexts that have a compatible version).
16001 */
16002 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
16003 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
16004 continue;
16005 }
16006
16007 if (!kmod_info ||
16008 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
16009 printf("kext scan stopped due to missing kmod_info page: %p\n",
16010 kmod_info);
16011 goto finish;
16012 }
16013
16014 identPlusVersLength = assemble_identifier_and_version(kmod_info,
16015 identPlusVers,
16016 sizeof(identPlusVers));
16017 if (!identPlusVersLength) {
16018 printf("error saving loaded kext info\n");
16019 goto finish;
16020 }
16021
16022 /* make sure everything fits and we null terminate.
16023 */
16024 tempLen = strlcat(paniclist, identPlusVers, list_size);
16025 if (tempLen >= list_size) {
16026 // panic list is full, keep it and null terminate
16027 paniclist[list_size - 1] = 0x00;
16028 result = 0;
16029 goto finish;
16030 }
16031 tempLen = strlcat(paniclist, "\n", list_size);
16032 if (tempLen >= list_size) {
16033 // panic list is full, keep it and null terminate
16034 paniclist[list_size - 1] = 0x00;
16035 result = 0;
16036 goto finish;
16037 }
16038 } while (i--);
16039
16040 result = 0;
16041 finish:
16042
16043 return result;
16044 }
16045
16046 /*********************************************************************
16047 *********************************************************************/
16048 /* static */
16049 void
16050 OSKext::saveLoadedKextPanicList(void)
16051 {
16052 char * newlist = NULL;
16053 uint32_t newlist_size = 0;
16054
16055 newlist_size = KEXT_PANICLIST_SIZE;
16056 newlist = (char *)kalloc_data_tag(newlist_size,
16057 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
16058
16059 if (!newlist) {
16060 OSKextLog(/* kext */ NULL,
16061 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
16062 "Couldn't allocate kext panic log buffer.");
16063 goto finish;
16064 }
16065
16066 newlist[0] = '\0';
16067
16068 // non-"com.apple." kexts
16069 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
16070 /* libs? */ -1, newlist, newlist_size) != 0) {
16071 goto finish;
16072 }
16073 // "com.apple." nonlibrary kexts
16074 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16075 /* libs? */ 0, newlist, newlist_size) != 0) {
16076 goto finish;
16077 }
16078 // "com.apple." library kexts
16079 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16080 /* libs? */ 1, newlist, newlist_size) != 0) {
16081 goto finish;
16082 }
16083
16084 if (loaded_kext_paniclist) {
16085 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
16086 }
16087 loaded_kext_paniclist = newlist;
16088 newlist = NULL;
16089 loaded_kext_paniclist_size = newlist_size;
16090
16091 finish:
16092 if (newlist) {
16093 kfree_data(newlist, newlist_size);
16094 }
16095 return;
16096 }
16097
16098 /*********************************************************************
16099 * Assumes sKextLock is held.
16100 *********************************************************************/
16101 void
16102 OSKext::savePanicString(bool isLoading)
16103 {
16104 u_long len;
16105
16106 if (!kmod_info) {
16107 return; // do not goto finish here b/c of lock
16108 }
16109
16110 len = assemble_identifier_and_version( kmod_info,
16111 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
16112 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
16113 if (!len) {
16114 printf("error saving unloaded kext info\n");
16115 goto finish;
16116 }
16117
16118 if (isLoading) {
16119 last_loaded_strlen = len;
16120 last_loaded_address = (void *)kmod_info->address;
16121 last_loaded_size = kmod_info->size;
16122 clock_get_uptime(&last_loaded_timestamp);
16123 } else {
16124 last_unloaded_strlen = len;
16125 last_unloaded_address = (void *)kmod_info->address;
16126 last_unloaded_size = kmod_info->size;
16127 clock_get_uptime(&last_unloaded_timestamp);
16128 }
16129
16130 finish:
16131 return;
16132 }
16133
16134 /*********************************************************************
16135 *********************************************************************/
16136 /* static */
16137 void
16138 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
16139 {
16140 if (last_loaded_strlen) {
16141 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
16142 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16143 last_loaded_strlen, last_loaded_str_buf,
16144 last_loaded_address, last_loaded_size);
16145 }
16146
16147 if (last_unloaded_strlen) {
16148 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16149 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16150 last_unloaded_strlen, last_unloaded_str_buf,
16151 last_unloaded_address, last_unloaded_size);
16152 }
16153
16154 printf_func("loaded kexts:\n");
16155 if (loaded_kext_paniclist &&
16156 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16157 loaded_kext_paniclist[0]) {
16158 printf_func("%.*s",
16159 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
16160 loaded_kext_paniclist);
16161 } else {
16162 printf_func("(none)\n");
16163 }
16164 return;
16165 }
16166
16167 /*********************************************************************
16168 * Assumes sKextLock is held.
16169 *********************************************************************/
16170 /* static */
16171 void
16172 OSKext::updateLoadedKextSummaries(void)
16173 {
16174 kern_return_t result = KERN_FAILURE;
16175 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16176 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16177 OSKext *aKext;
16178 vm_map_offset_t start, end;
16179 size_t summarySize = 0;
16180 size_t size;
16181 u_int count;
16182 u_int maxKexts;
16183 u_int i, j;
16184 OSKextActiveAccount * accountingList;
16185 OSKextActiveAccount * prevAccountingList;
16186 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16187
16188 prevAccountingList = NULL;
16189 prevAccountingListCount = 0;
16190
16191 #if DEVELOPMENT || DEBUG
16192 if (IORecursiveLockHaveLock(sKextLock) == false) {
16193 panic("sKextLock must be held");
16194 }
16195 #endif
16196
16197 IOLockLock(sKextSummariesLock);
16198
16199 count = sLoadedKexts->getCount();
16200 for (i = 0, maxKexts = 0; i < count; ++i) {
16201 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16202 maxKexts += (aKext && (aKext->isExecutable() || aKext->isSpecialKernelBinary()));
16203 }
16204
16205 if (!maxKexts) {
16206 goto finish;
16207 }
16208 if (maxKexts < kOSKextTypicalLoadCount) {
16209 maxKexts = kOSKextTypicalLoadCount;
16210 }
16211
16212 /* Calculate the size needed for the new summary headers.
16213 */
16214
16215 size = sizeof(*gLoadedKextSummaries);
16216 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16217 size = round_page(size);
16218
16219 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16220 if (gLoadedKextSummaries) {
16221 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
16222 gLoadedKextSummaries = NULL;
16223 gLoadedKextSummariesTimestamp = mach_absolute_time();
16224 sLoadedKextSummariesAllocSize = 0;
16225 }
16226 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
16227 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
16228 if (result != KERN_SUCCESS) {
16229 goto finish;
16230 }
16231 summaryHeader = summaryHeaderAlloc;
16232 summarySize = size;
16233 } else {
16234 summaryHeader = gLoadedKextSummaries;
16235 summarySize = sLoadedKextSummariesAllocSize;
16236
16237 start = (vm_map_offset_t) summaryHeader;
16238 end = start + summarySize;
16239 result = vm_map_protect(kernel_map,
16240 start,
16241 end,
16242 VM_PROT_DEFAULT,
16243 FALSE);
16244 if (result != KERN_SUCCESS) {
16245 goto finish;
16246 }
16247 }
16248
16249 /* Populate the summary header.
16250 */
16251
16252 bzero(summaryHeader, summarySize);
16253 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16254 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16255
16256 /* Populate each kext summary.
16257 */
16258
16259 count = sLoadedKexts->getCount();
16260 accountingListAlloc = 0;
16261 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16262 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16263 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16264 continue;
16265 }
16266
16267 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
16268 summaryHeader->numSummaries++;
16269 accountingListAlloc++;
16270 }
16271
16272 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16273 accountingListCount = 0;
16274 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16275 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16276 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16277 continue;
16278 }
16279
16280 OSKextActiveAccount activeAccount;
16281 aKext->updateActiveAccount(&activeAccount);
16282 // order by address
16283 for (idx = 0; idx < accountingListCount; idx++) {
16284 if (activeAccount.address < accountingList[idx].address) {
16285 break;
16286 }
16287 }
16288 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
16289 accountingList[idx] = activeAccount;
16290 accountingListCount++;
16291 }
16292 assert(accountingListCount == accountingListAlloc);
16293 /* Write protect the buffer and move it into place.
16294 */
16295
16296 start = (vm_map_offset_t) summaryHeader;
16297 end = start + summarySize;
16298
16299 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
16300 if (result != KERN_SUCCESS) {
16301 goto finish;
16302 }
16303
16304 gLoadedKextSummaries = summaryHeader;
16305 gLoadedKextSummariesTimestamp = mach_absolute_time();
16306 sLoadedKextSummariesAllocSize = summarySize;
16307 summaryHeaderAlloc = NULL;
16308
16309 /* Call the magic breakpoint function through a static function pointer so
16310 * the compiler can't optimize the function away.
16311 */
16312 if (sLoadedKextSummariesUpdated) {
16313 (*sLoadedKextSummariesUpdated)();
16314 }
16315
16316 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16317 prevAccountingList = sKextAccounts;
16318 prevAccountingListCount = sKextAccountsCount;
16319 sKextAccounts = accountingList;
16320 sKextAccountsCount = accountingListCount;
16321 lck_ticket_unlock(sKextAccountsLock);
16322
16323 finish:
16324 IOLockUnlock(sKextSummariesLock);
16325
16326 /* If we had to allocate a new buffer but failed to generate the summaries,
16327 * free that now.
16328 */
16329 if (summaryHeaderAlloc) {
16330 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
16331 }
16332 if (prevAccountingList) {
16333 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16334 }
16335
16336 return;
16337 }
16338
16339 /*********************************************************************
16340 *********************************************************************/
16341 void
16342 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16343 {
16344 OSSharedPtr<OSData> uuid;
16345
16346 strlcpy(summary->name, getIdentifierCString(),
16347 sizeof(summary->name));
16348
16349 uuid = copyUUID();
16350 if (uuid) {
16351 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
16352 }
16353
16354 if (flags.builtin) {
16355 // this value will stop lldb from parsing the mach-o header
16356 // summary->address = UINT64_MAX;
16357 // summary->size = 0;
16358 summary->address = kmod_info->address;
16359 summary->size = kmod_info->size;
16360 } else {
16361 summary->address = kmod_info->address;
16362 summary->size = kmod_info->size;
16363 }
16364 summary->version = getVersion();
16365 summary->loadTag = kmod_info->id;
16366 summary->flags = 0;
16367 summary->reference_list = (uint64_t) kmod_info->reference_list;
16368
16369 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16370 if (summary->text_exec_address == 0) {
16371 // Fallback to __TEXT
16372 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16373 }
16374
16375 /**
16376 * If the addresses within the Mach-O are unslid, then manually slide any
16377 * addresses coming from the Mach-O as higher layer software using these
16378 * summaries expects a slid address here.
16379 */
16380 if (flags.unslidMachO) {
16381 summary->text_exec_address = (uint64_t) ml_static_slide((vm_offset_t) summary->text_exec_address);
16382 }
16383
16384 return;
16385 }
16386
16387 /*********************************************************************
16388 *********************************************************************/
16389
16390 void
16391 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16392 {
16393 kernel_mach_header_t *hdr = NULL;
16394 kernel_segment_command_t *seg = NULL;
16395
16396 bzero(accountp, sizeof(*accountp));
16397
16398 hdr = (kernel_mach_header_t *)kmod_info->address;
16399 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16400 /*
16401 * If this kext supports split segments (or is in a new
16402 * MH_FILESET kext collection), use the first
16403 * executable segment as the range for instructions
16404 * (and thus for backtracing.
16405 */
16406 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
16407 if (seg->initprot & VM_PROT_EXECUTE) {
16408 break;
16409 }
16410 }
16411 }
16412 if (seg) {
16413 accountp->address = seg->vmaddr;
16414 if (accountp->address) {
16415 accountp->address_end = seg->vmaddr + seg->vmsize;
16416 }
16417 } else {
16418 /* For non-split kexts and for kexts without executable
16419 * segments, just use the kmod_info range (as the kext
16420 * is either all in one range or should not show up in
16421 * instruction backtraces).
16422 */
16423 accountp->address = kmod_info->address;
16424 if (accountp->address) {
16425 accountp->address_end = kmod_info->address + kmod_info->size;
16426 }
16427 }
16428
16429 accountp->account = this->account;
16430 }
16431
16432 bool
16433 OSKext::isDriverKit(void)
16434 {
16435 OSString *bundleType;
16436
16437 if (infoDict) {
16438 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16439 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16440 return TRUE;
16441 }
16442 }
16443 return FALSE;
16444 }
16445
16446 bool
16447 OSKext::isInFileset(void)
16448 {
16449 if (!kmod_info) {
16450 goto check_prelinked;
16451 }
16452
16453 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16454 return true;
16455 }
16456
16457 check_prelinked:
16458 if (isPrelinked()) {
16459 /*
16460 * If we haven't setup kmod_info yet, but we know
16461 * we're loading a prelinked kext in an MH_FILESET KC,
16462 * then return true
16463 */
16464 kc_format_t kc_format;
16465 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
16466 return true;
16467 }
16468 }
16469 return false;
16470 }
16471
16472 OSSharedPtr<OSDextStatistics>
16473 OSKext::copyDextStatistics(void)
16474 {
16475 return dextStatistics;
16476 }
16477
16478 bool
16479 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16480 {
16481 kern_return_t result;
16482 if (!super::init()) {
16483 return false;
16484 }
16485 if (seg == nullptr) {
16486 return false;
16487 }
16488 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
16489 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16490 if (result != KERN_SUCCESS) {
16491 return false;
16492 }
16493 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
16494 savedSegment = seg;
16495 vmsize = seg->vmsize;
16496 vmaddr = seg->vmaddr;
16497 return true;
16498 }
16499
16500 OSSharedPtr<OSKextSavedMutableSegment>
16501 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16502 {
16503 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16504 if (me && !me->initWithSegment(seg)) {
16505 return nullptr;
16506 }
16507 return me;
16508 }
16509
16510 void
16511 OSKextSavedMutableSegment::free(void)
16512 {
16513 if (data) {
16514 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
16515 }
16516 }
16517
16518 vm_offset_t
16519 OSKextSavedMutableSegment::getVMAddr() const
16520 {
16521 return vmaddr;
16522 }
16523
16524 vm_offset_t
16525 OSKextSavedMutableSegment::getVMSize() const
16526 {
16527 return vmsize;
16528 }
16529
16530 OSReturn
16531 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16532 {
16533 if (seg != savedSegment) {
16534 return kOSKextReturnInvalidArgument;
16535 }
16536 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16537 return kOSKextReturnInvalidArgument;
16538 }
16539 memcpy((void *)seg->vmaddr, data, vmsize);
16540 return kOSReturnSuccess;
16541 }
16542
16543 extern "C" kern_return_t
16544 OSKextSetReceiptQueried(void)
16545 {
16546 OSKextLog(/* kext */ NULL,
16547 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16548 "Setting kext receipt as queried");
16549
16550 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
16551 return KERN_SUCCESS;
16552 }
16553
16554 extern "C" const vm_allocation_site_t *
16555 OSKextGetAllocationSiteForCaller(uintptr_t address)
16556 {
16557 OSKextActiveAccount * active;
16558 vm_allocation_site_t * site;
16559 vm_allocation_site_t * releasesite;
16560
16561 uint32_t baseIdx;
16562 uint32_t lim;
16563 #if __has_feature(ptrauth_calls)
16564 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16565 #endif /* __has_feature(ptrauth_calls) */
16566
16567 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16568 site = releasesite = NULL;
16569
16570 // bsearch sKextAccounts list
16571 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16572 active = &sKextAccounts[baseIdx + (lim >> 1)];
16573 if ((address >= active->address) && (address < active->address_end)) {
16574 site = &active->account->site;
16575 if (!site->tag) {
16576 vm_tag_alloc_locked(site, &releasesite);
16577 }
16578 break;
16579 } else if (address > active->address) {
16580 // move right
16581 baseIdx += (lim >> 1) + 1;
16582 lim--;
16583 }
16584 // else move left
16585 }
16586 lck_ticket_unlock(sKextAccountsLock);
16587 if (releasesite) {
16588 kern_allocation_name_release(releasesite);
16589 }
16590
16591 return site;
16592 }
16593
16594 #if DEVELOPMENT || DEBUG
16595 extern "C" void
16596 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16597 {
16598 OSKextActiveAccount * active;
16599
16600 uint32_t baseIdx;
16601 uint32_t lim;
16602 #if __has_feature(ptrauth_calls)
16603 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16604 #endif /* __has_feature(ptrauth_calls) */
16605
16606 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16607
16608 // bsearch sKextAccounts list
16609 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16610 active = &sKextAccounts[baseIdx + (lim >> 1)];
16611 if ((address >= active->address) && (address < active->address_end)) {
16612 cb(&active->account->task_refgrp);
16613 break;
16614 } else if (address > active->address) {
16615 // move right
16616 baseIdx += (lim >> 1) + 1;
16617 lim--;
16618 }
16619 // else move left
16620 }
16621 lck_ticket_unlock(sKextAccountsLock);
16622 }
16623 #endif /* DEVELOPMENT || DEBUG */
16624
16625 extern "C" uint32_t
16626 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16627 {
16628 OSKextAccount * account = (typeof(account))site;
16629 const char * kname;
16630
16631 if (name) {
16632 if (account->kext) {
16633 kname = account->kext->getIdentifierCString();
16634 } else {
16635 kname = "<>";
16636 }
16637 strlcpy(name, kname, namelen);
16638 }
16639
16640 return account->loadTag;
16641 }
16642
16643 extern "C" void
16644 OSKextFreeSite(vm_allocation_site_t * site)
16645 {
16646 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16647 IOFreeType(freeAccount, OSKextAccount);
16648 }
16649
16650 /*********************************************************************
16651 *********************************************************************/
16652
16653 #if CONFIG_IMAGEBOOT
16654 int
16655 OSKextGetUUIDForName(const char *name, uuid_t uuid)
16656 {
16657 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
16658 if (!kext) {
16659 return 1;
16660 }
16661
16662 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16663 if (uuid_data) {
16664 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
16665 return 0;
16666 }
16667
16668 return 1;
16669 }
16670 #endif
16671
16672
16673
16674 class OSDextCrash : public OSObject {
16675 OSDeclareDefaultStructors(OSDextCrash);
16676 public:
16677 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16678 uint64_t getTimestamp();
16679
16680 private:
16681 virtual bool initWithTimestamp(uint64_t timestamp);
16682 uint64_t fTimestamp;
16683 };
16684
16685 OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16686
16687 OSSharedPtr<OSDextCrash>
16688 OSDextCrash::withTimestamp(uint64_t timestamp)
16689 {
16690 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16691 if (!result->initWithTimestamp(timestamp)) {
16692 return NULL;
16693 }
16694 return result;
16695 }
16696
16697 bool
16698 OSDextCrash::initWithTimestamp(uint64_t timestamp)
16699 {
16700 if (!OSObject::init()) {
16701 return false;
16702 }
16703 fTimestamp = timestamp;
16704 return true;
16705 }
16706
16707 uint64_t
16708 OSDextCrash::getTimestamp()
16709 {
16710 return fTimestamp;
16711 }
16712
16713 OSSharedPtr<OSDextStatistics>
16714 OSDextStatistics::create()
16715 {
16716 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16717 if (!result->init()) {
16718 return NULL;
16719 }
16720 return result;
16721 }
16722
16723 bool
16724 OSDextStatistics::init()
16725 {
16726 if (!OSObject::init()) {
16727 return false;
16728 }
16729
16730 lock = IOLockAlloc();
16731 crashes = OSArray::withCapacity(kMaxDextCrashesInOneDay);
16732 return true;
16733 }
16734
16735 void
16736 OSDextStatistics::free()
16737 {
16738 if (lock) {
16739 IOLockFree(lock);
16740 }
16741 crashes.reset();
16742 OSObject::free();
16743 }
16744
16745 OSDextCrashPolicy
16746 OSDextStatistics::recordCrash()
16747 {
16748 size_t i = 0;
16749 uint64_t timestamp = mach_continuous_time();
16750 uint64_t interval;
16751 nanoseconds_to_absolutetime(86400 * NSEC_PER_SEC /* 1 day */, &interval);
16752 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16753 OSDextCrashPolicy policy;
16754
16755 IOLockLock(lock);
16756 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16757 for (i = 0; i < crashes->getCount();) {
16758 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16759 assert(current != NULL);
16760 if (current->getTimestamp() < lastTimestamp) {
16761 crashes->removeObject(i);
16762 } else {
16763 i++;
16764 }
16765 }
16766
16767 crashes->setObject(crash);
16768
16769 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16770 policy = kOSDextCrashPolicyReboot;
16771 } else {
16772 policy = kOSDextCrashPolicyNone;
16773 }
16774
16775 IOLockUnlock(lock);
16776
16777 return policy;
16778 }
16779
16780 size_t
16781 OSDextStatistics::getCrashCount()
16782 {
16783 size_t result = 0;
16784 IOLockLock(lock);
16785 result = crashes->getCount();
16786 IOLockUnlock(lock);
16787 return result;
16788 }
16789
16790 static int
16791 sysctl_willuserspacereboot
16792 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
16793 {
16794 int new_value = 0, old_value = 0, changed = 0;
16795 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
16796 if (error) {
16797 return error;
16798 }
16799 if (changed) {
16800 OSKext::willUserspaceReboot();
16801 }
16802 return 0;
16803 }
16804
16805 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
16806 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
16807 NULL, 0, sysctl_willuserspacereboot, "I", "");
16808