1 /*
2 * Copyright (c) 2008-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #define IOKIT_ENABLE_SHARED_PTR
30
31 extern "C" {
32 #include <string.h>
33 #include <kern/clock.h>
34 #include <kern/host.h>
35 #include <kern/kext_alloc.h>
36 #include <firehose/tracepoint_private.h>
37 #include <firehose/chunk_private.h>
38 #include <os/firehose_buffer_private.h>
39 #include <vm/vm_map.h>
40 #include <kextd/kextd_mach.h>
41 #include <libkern/kernel_mach_header.h>
42 #include <libkern/kext_panic_report.h>
43 #include <libkern/kext_request_keys.h>
44 #include <libkern/mkext.h>
45 #include <libkern/prelink.h>
46 #include <libkern/version.h>
47 #include <libkern/zlib.h>
48 #include <mach/host_special_ports.h>
49 #include <mach/mach_vm.h>
50 #include <mach/mach_time.h>
51 #include <uuid/uuid.h>
52 #include <sys/random.h>
53 #include <pexpert/pexpert.h>
54
55 #include <sys/pgo.h>
56
57 #if CONFIG_CSR
58 #include <sys/csr.h>
59 #include <sys/stat.h>
60 #include <sys/vnode.h>
61 #endif /* CONFIG_CSR */
62 };
63
64 #if CONFIG_MACF
65 #include <sys/kauth.h>
66 #include <security/mac_framework.h>
67 #endif
68
69 #include <vm/vm_kern.h>
70 #include <sys/sysctl.h>
71 #include <kern/task.h>
72 #include <os/cpp_util.h>
73
74 #include <libkern/OSKextLibPrivate.h>
75 #include <libkern/c++/OSKext.h>
76 #include <libkern/c++/OSLib.h>
77
78 #include <IOKit/IOLib.h>
79 #include <IOKit/IOCatalogue.h>
80 #include <IOKit/IORegistryEntry.h>
81 #include <IOKit/IOService.h>
82 #include <IOKit/IOUserServer.h>
83
84 #include <IOKit/IOStatisticsPrivate.h>
85 #include <IOKit/IOBSD.h>
86 #include <IOKit/IOPlatformExpert.h>
87
88 #include <san/kasan.h>
89
90 #if PRAGMA_MARK
91 #pragma mark External & Internal Function Protos
92 #endif
93 /*********************************************************************
94 *********************************************************************/
95 extern "C" {
96 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
97 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
98
99 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
100 extern int dtrace_keep_kernel_symbols(void);
101
102 #if defined(__x86_64__) || defined(__i386__)
103 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
104 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
105 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
106 static void *allocate_kcfileset_map_entry_list(void);
107 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
108 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
109 int vnode_put(struct vnode *vp);
110 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
111 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
112 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
113 void * ubc_getobject(struct vnode *vp, __unused int flags);
114 #endif //(__x86_64__) || defined(__i386__)
115 }
116
117 extern unsigned long gVirtBase;
118 extern unsigned long gPhysBase;
119 extern vm_map_t g_kext_map;
120
121 bool pageableKCloaded = false;
122 bool auxKCloaded = false;
123 bool resetAuxKCSegmentOnUnload = false;
124
125 extern boolean_t pageablekc_uuid_valid;
126 extern uuid_t pageablekc_uuid;
127 extern uuid_string_t pageablekc_uuid_string;
128
129 extern boolean_t auxkc_uuid_valid;
130 extern uuid_t auxkc_uuid;
131 extern uuid_string_t auxkc_uuid_string;
132
133 static OSReturn _OSKextCreateRequest(
134 const char * predicate,
135 OSSharedPtr<OSDictionary> & requestP);
136 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
137 static OSObject * _OSKextGetRequestArgument(
138 OSDictionary * requestDict,
139 const char * argName);
140 static bool _OSKextSetRequestArgument(
141 OSDictionary * requestDict,
142 const char * argName,
143 OSMetaClassBase * value);
144 template <typename T>
145 static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
146 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
147 static OSReturn _OSDictionarySetCStringValue(
148 OSDictionary * dict,
149 const char * key,
150 const char * value);
151 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
152 #if CONFIG_KXLD
153 static bool _OSKextInPrelinkRebuildWindow(void);
154 #endif
155
156 // We really should add containsObject() & containsCString to OSCollection & subclasses.
157 // So few pad slots, though....
158 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
159 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
160
161 /* Prelinked arm kexts do not have VM entries because the method we use to
162 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
163 * not work on ARM. To get around that, we must free prelinked kext
164 * executables with ml_static_mfree() instead of kext_free().
165 */
166 #if __i386__ || __x86_64__
167 #define VM_MAPPED_KEXTS 1
168 #define KASLR_KEXT_DEBUG 0
169 #define KASLR_IOREG_DEBUG 0
170 #elif __arm__ || __arm64__
171 #define VM_MAPPED_KEXTS 0
172 #define KASLR_KEXT_DEBUG 0
173 #else
174 #error Unsupported architecture
175 #endif
176
177 #if PRAGMA_MARK
178 #pragma mark Constants & Macros
179 #endif
180 /*********************************************************************
181 * Constants & Macros
182 *********************************************************************/
183
184 /* Use this number to create containers.
185 */
186 #define kOSKextTypicalLoadCount (150)
187
188 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
189 * A loaded kext will no dependents or external retains will have 2 retains.
190 */
191 #define kOSKextMinRetainCount (1)
192 #define kOSKextMinLoadedRetainCount (2)
193
194 /**********
195 * Strings and substrings used in dependency resolution.
196 */
197 #define APPLE_KEXT_PREFIX "com.apple."
198 #define KERNEL_LIB "com.apple.kernel"
199
200 #define PRIVATE_KPI "com.apple.kpi.private"
201
202 /* Version for compatbility pseudokexts (com.apple.kernel.*),
203 * compatible back to v6.0.
204 */
205 #define KERNEL6_LIB "com.apple.kernel.6.0"
206 #define KERNEL6_VERSION "7.9.9"
207
208 #define KERNEL_LIB_PREFIX "com.apple.kernel."
209 #define KPI_LIB_PREFIX "com.apple.kpi."
210
211 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
212
213 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
214 #define MINIMUM_WAKEUP_SECONDS (30)
215
216 /*********************************************************************
217 * infoDict keys for internally-stored data. Saves on ivar slots for
218 * objects we don't keep around past boot time or during active load.
219 *********************************************************************/
220
221 /* A usable, uncompressed file is stored under this key.
222 */
223 #define _kOSKextExecutableKey "_OSKextExecutable"
224
225 /* An indirect reference to the executable file from an mkext
226 * is stored under this key.
227 */
228 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
229
230 /* If the file is contained in a larger buffer laid down by the booter or
231 * sent from user space, the OSKext stores that OSData under this key so that
232 * references are properly tracked. This is always an mkext, right now.
233 */
234 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
235
236 #define OS_LOG_HDR_VERSION 1
237 #define NUM_OS_LOG_SECTIONS 3
238
239 #define OS_LOG_SECT_IDX 0
240 #define CSTRING_SECT_IDX 1
241 #define ASAN_CSTRING_SECT_IDX 2
242
243 #if PRAGMA_MARK
244 #pragma mark Typedefs
245 #endif
246 /*********************************************************************
247 * Typedefs
248 *********************************************************************/
249
250 /*********************************************************************
251 * osLogDataHeaderRef describes the header information of an OSData
252 * object that is returned when querying for kOSBundleLogStringsKey.
253 * We currently return information regarding 2 sections - os_log and
254 * cstring. In the case that the os_log section doesn't exist, we just
255 * return an offset and length of 0 for that section.
256 *********************************************************************/
257 typedef struct osLogDataHeader {
258 uint32_t version;
259 uint32_t sect_count;
260 struct {
261 uint32_t sect_offset;
262 uint32_t sect_size;
263 } sections[0];
264 } osLogDataHeaderRef;
265
266 /*********************************************************************
267 * MkextEntryRef describes the contents of an OSData object
268 * referencing a file entry from an mkext so that we can uncompress
269 * (if necessary) and extract it on demand.
270 *
271 * It contains the mkextVersion in case we ever wind up supporting
272 * multiple mkext formats. Mkext format 1 is officially retired as of
273 * Snow Leopard.
274 *********************************************************************/
275 typedef struct MkextEntryRef {
276 mkext_basic_header * mkext; // beginning of whole mkext file
277 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
278 } MkextEntryRef;
279
280 #if PRAGMA_MARK
281 #pragma mark Global and static Module Variables
282 #endif
283 /*********************************************************************
284 * Global & static variables, used to keep track of kexts.
285 *********************************************************************/
286
287 static bool sPrelinkBoot = false;
288 static bool sSafeBoot = false;
289 static bool sKeepSymbols = false;
290 static bool sPanicOnKCMismatch = false;
291 static bool sOSKextWasResetAfterUserspaceReboot = false;
292
293 /*********************************************************************
294 * sKextLock is the principal lock for OSKext, and guards all static
295 * and global variables not owned by other locks (declared further
296 * below). It must be taken by any entry-point method or function,
297 * including internal functions called on scheduled threads.
298 *
299 * sKextLock and sKextInnerLock are recursive due to multiple functions
300 * that are called both externally and internally. The other locks are
301 * nonrecursive.
302 *
303 * Which locks are taken depends on what they protect, but if more than
304 * one must be taken, they must always be locked in this order
305 * (and unlocked in reverse order) to prevent deadlocks:
306 *
307 * 1. sKextLock
308 * 2. sKextInnerLock
309 * 3. sKextSummariesLock
310 * 4. sKextLoggingLock
311 */
312 static IORecursiveLock * sKextLock = NULL;
313
314 static OSSharedPtr<OSDictionary> sKextsByID;
315 static OSSharedPtr<OSDictionary> sExcludeListByID;
316 static OSKextVersion sExcludeListVersion = 0;
317 static OSSharedPtr<OSArray> sLoadedKexts;
318 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
319 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
320 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
321
322 // Requests to the IOKit daemon waiting to be picked up.
323 static OSSharedPtr<OSArray> sKernelRequests;
324 // Identifier of kext load requests in sKernelRequests
325 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
326 static OSSharedPtr<OSArray> sRequestCallbackRecords;
327
328 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
329 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
330 #if CONFIG_KXLD
331 static KXLDContext * sKxldContext = NULL;
332 #endif
333 static uint32_t sNextLoadTag = 0;
334 static uint32_t sNextRequestTag = 0;
335
336 static bool sUserLoadsActive = false;
337 static bool sIOKitDaemonActive = false;
338 static bool sDeferredLoadSucceeded = false;
339 static bool sConsiderUnloadsExecuted = false;
340
341 #if NO_KEXTD
342 static bool sKernelRequestsEnabled = false;
343 #else
344 static bool sKernelRequestsEnabled = true;
345 #endif
346 static bool sLoadEnabled = true;
347 static bool sUnloadEnabled = true;
348
349 /*********************************************************************
350 * Stuff for the OSKext representing the kernel itself.
351 **********/
352 static OSKext * sKernelKext = NULL;
353
354 /* Set up a fake kmod_info struct for the kernel.
355 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
356 * before OSKext is initialized; that call only needs the name
357 * and address to be set correctly.
358 *
359 * We don't do much else with the kerne's kmod_info; we never
360 * put it into the kmod list, never adjust the reference count,
361 * and never have kernel components reference it.
362 * For that matter, we don't do much with kmod_info structs
363 * at all anymore! We just keep them filled in for gdb and
364 * binary compability.
365 */
366 kmod_info_t g_kernel_kmod_info = {
367 .next = NULL,
368 .info_version = KMOD_INFO_VERSION,
369 .id = 0, // loadTag: kernel is always 0
370 .name = kOSKextKernelIdentifier,// bundle identifier
371 .version = "0", // filled in in OSKext::initialize()
372 .reference_count = -1, // never adjusted; kernel never unloads
373 .reference_list = NULL,
374 .address = 0,
375 .size = 0, // filled in in OSKext::initialize()
376 .hdr_size = 0,
377 .start = NULL,
378 .stop = NULL
379 };
380
381 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
382
383 kmod_info_t invalid_kmod_info = {
384 .next = NULL,
385 .info_version = KMOD_INFO_VERSION,
386 .id = UINT32_MAX,
387 .name = "invalid",
388 .version = "0",
389 .reference_count = -1,
390 .reference_list = NULL,
391 .address = 0,
392 .size = 0,
393 .hdr_size = 0,
394 .start = NULL,
395 .stop = NULL
396 };
397
398 extern "C" {
399 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
400 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
401 // misc_protos.h, db_low_trace.c, kgmacros
402 // 'kmod' is a holdover from the old kmod system, we can't rename it.
403 kmod_info_t * kmod = NULL;
404
405 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
406
407
408 static char * loaded_kext_paniclist = NULL;
409 static uint32_t loaded_kext_paniclist_size = 0;
410
411 AbsoluteTime last_loaded_timestamp;
412 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
413 static u_long last_loaded_strlen = 0;
414 static void * last_loaded_address = NULL;
415 static u_long last_loaded_size = 0;
416
417 AbsoluteTime last_unloaded_timestamp;
418 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
419 static u_long last_unloaded_strlen = 0;
420 static void * last_unloaded_address = NULL;
421 static u_long last_unloaded_size = 0;
422
423 // Statically linked kmods described by several mach-o sections:
424 //
425 // kPrelinkInfoSegment:kBuiltinInfoSection
426 // Array of pointers to kmod_info_t structs.
427 //
428 // kPrelinkInfoSegment:kBuiltinInfoSection
429 // Array of pointers to an embedded mach-o header.
430 //
431 // __DATA:kBuiltinInitSection, kBuiltinTermSection
432 // Structors for all kmods. Has to be filtered by proc address.
433 //
434
435 static uint32_t gBuiltinKmodsCount;
436 static kernel_section_t * gBuiltinKmodsSectionInfo;
437 static kernel_section_t * gBuiltinKmodsSectionStart;
438
439 const OSSymbol * gIOSurfaceIdentifier;
440 vm_tag_t gIOSurfaceTag;
441
442 /*********************************************************************
443 * sKextInnerLock protects against cross-calls with IOService and
444 * IOCatalogue, and owns the variables declared immediately below.
445 *
446 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
447 *
448 * When both sKextLock and sKextInnerLock need to be taken,
449 * always lock sKextLock first and unlock it second. Never take both
450 * locks in an entry point to OSKext; if you need to do so, you must
451 * spawn an independent thread to avoid potential deadlocks for threads
452 * calling into OSKext.
453 **********/
454 static IORecursiveLock * sKextInnerLock = NULL;
455
456 #if XNU_TARGET_OS_OSX
457 static bool sAutounloadEnabled = true;
458 #endif
459 static bool sConsiderUnloadsCalled = false;
460 static bool sConsiderUnloadsPending = false;
461
462 static unsigned int sConsiderUnloadDelay = 60; // seconds
463 static thread_call_t sUnloadCallout = NULL;
464 #if CONFIG_KXLD
465 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
466 #endif // CONFIG_KXLD
467 static bool sSystemSleep = false; // true when system going to sleep
468 static AbsoluteTime sLastWakeTime; // last time we woke up
469
470 /*********************************************************************
471 * Backtraces can be printed at various times so we need a tight lock
472 * on data used for that. sKextSummariesLock protects the variables
473 * declared immediately below.
474 *
475 * gLoadedKextSummaries is accessed by other modules, but only during
476 * a panic so the lock isn't needed then.
477 *
478 * gLoadedKextSummaries has the "used" attribute in order to ensure
479 * that it remains visible even when we are performing extremely
480 * aggressive optimizations, as it is needed to allow the debugger
481 * to automatically parse the list of loaded kexts.
482 **********/
483 static IOLock * sKextSummariesLock = NULL;
484 extern "C" lck_spin_t vm_allocation_sites_lock;
485 static IOSimpleLock * sKextAccountsLock = &vm_allocation_sites_lock;
486
487 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
488 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
489 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
490 static size_t sLoadedKextSummariesAllocSize = 0;
491
492 static OSKextActiveAccount * sKextAccounts;
493 static uint32_t sKextAccountsCount;
494 };
495
496 /*********************************************************************
497 * sKextLoggingLock protects the logging variables declared immediately below.
498 **********/
499 static IOLock * sKextLoggingLock = NULL;
500
501 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
502 kOSKextLogVerboseFlagsMask;
503 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
504 static bool sBootArgLogFilterFound = false;
505 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
506 0, "kernel kext logging");
507
508 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
509 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
510 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
511
512 /*********
513 * End scope for sKextInnerLock-protected variables.
514 *********************************************************************/
515
516
517 /*********************************************************************
518 * helper function used for collecting PGO data upon unload of a kext
519 */
520
521 static int OSKextGrabPgoDataLocked(OSKext *kext,
522 bool metadata,
523 uuid_t instance_uuid,
524 uint64_t *pSize,
525 char *pBuffer,
526 uint64_t bufferSize);
527
528 /**********************************************************************/
529
530
531
532 #if PRAGMA_MARK
533 #pragma mark OSData callbacks (need to move to OSData)
534 #endif
535 /*********************************************************************
536 * C functions used for callbacks.
537 *********************************************************************/
538 extern "C" {
539 void
osdata_kmem_free(void * ptr,unsigned int length)540 osdata_kmem_free(void * ptr, unsigned int length)
541 {
542 kmem_free(kernel_map, (vm_address_t)ptr, length);
543 return;
544 }
545
546 void
osdata_phys_free(void * ptr,unsigned int length)547 osdata_phys_free(void * ptr, unsigned int length)
548 {
549 ml_static_mfree((vm_offset_t)ptr, length);
550 return;
551 }
552
553 void
osdata_vm_deallocate(void * ptr,unsigned int length)554 osdata_vm_deallocate(void * ptr, unsigned int length)
555 {
556 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
557 return;
558 }
559
560 void
osdata_kext_free(void * ptr,unsigned int length)561 osdata_kext_free(void * ptr, unsigned int length)
562 {
563 (void)kext_free((vm_offset_t)ptr, length);
564 }
565 };
566
567 #if PRAGMA_MARK
568 #pragma mark KXLD Allocation Callback
569 #endif
570 #if CONFIG_KXLD
571 /*********************************************************************
572 * KXLD Allocation Callback
573 *********************************************************************/
574 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)575 kern_allocate(
576 u_long size,
577 KXLDAllocateFlags * flags,
578 void * user_data)
579 {
580 vm_address_t result = 0; // returned
581 kern_return_t mach_result = KERN_FAILURE;
582 bool success = false;
583 OSKext * theKext = (OSKext *)user_data;
584 unsigned int roundSize = 0;
585 OSSharedPtr<OSData> linkBuffer;
586
587 if (round_page(size) > UINT_MAX) {
588 OSKextLog(theKext,
589 kOSKextLogErrorLevel |
590 kOSKextLogGeneralFlag,
591 "%s: Requested memory size is greater than UINT_MAX.",
592 theKext->getIdentifierCString());
593 goto finish;
594 }
595
596 roundSize = (unsigned int)round_page(size);
597
598 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
599 if (mach_result != KERN_SUCCESS) {
600 OSKextLog(theKext,
601 kOSKextLogErrorLevel |
602 kOSKextLogGeneralFlag,
603 "Can't allocate kernel memory to link %s.",
604 theKext->getIdentifierCString());
605 goto finish;
606 }
607
608 /* Create an OSData wrapper for the allocated buffer.
609 */
610 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
611 if (!linkBuffer) {
612 OSKextLog(theKext,
613 kOSKextLogErrorLevel |
614 kOSKextLogGeneralFlag,
615 "Can't allocate linked executable wrapper for %s.",
616 theKext->getIdentifierCString());
617 goto finish;
618 }
619 linkBuffer->setDeallocFunction(osdata_kext_free);
620 OSKextLog(theKext,
621 kOSKextLogProgressLevel |
622 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
623 "Allocated link buffer for kext %s at %p (%lu bytes).",
624 theKext->getIdentifierCString(),
625 (void *)result, (unsigned long)roundSize);
626
627 theKext->setLinkedExecutable(linkBuffer.get());
628
629 *flags = kKxldAllocateWritable;
630 success = true;
631
632 finish:
633 if (!success && result) {
634 kext_free(result, roundSize);
635 result = 0;
636 }
637
638 return (kxld_addr_t)result;
639 }
640
641 /*********************************************************************
642 *********************************************************************/
643 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)644 kxld_log_callback(
645 KXLDLogSubsystem subsystem,
646 KXLDLogLevel level,
647 const char * format,
648 va_list argList,
649 void * user_data)
650 {
651 OSKext *theKext = (OSKext *) user_data;
652 OSKextLogSpec logSpec = 0;
653
654 switch (subsystem) {
655 case kKxldLogLinking:
656 logSpec |= kOSKextLogLinkFlag;
657 break;
658 case kKxldLogPatching:
659 logSpec |= kOSKextLogPatchFlag;
660 break;
661 }
662
663 switch (level) {
664 case kKxldLogExplicit:
665 logSpec |= kOSKextLogExplicitLevel;
666 break;
667 case kKxldLogErr:
668 logSpec |= kOSKextLogErrorLevel;
669 break;
670 case kKxldLogWarn:
671 logSpec |= kOSKextLogWarningLevel;
672 break;
673 case kKxldLogBasic:
674 logSpec |= kOSKextLogProgressLevel;
675 break;
676 case kKxldLogDetail:
677 logSpec |= kOSKextLogDetailLevel;
678 break;
679 case kKxldLogDebug:
680 logSpec |= kOSKextLogDebugLevel;
681 break;
682 }
683
684 OSKextVLog(theKext, logSpec, format, argList);
685 }
686 #endif // CONFIG_KXLD
687
688 #if PRAGMA_MARK
689 #pragma mark IOStatistics defines
690 #endif
691
692 #if IOKITSTATS
693
694 #define notifyKextLoadObservers(kext, kmod_info) \
695 do { \
696 IOStatistics::onKextLoad(kext, kmod_info); \
697 } while (0)
698
699 #define notifyKextUnloadObservers(kext) \
700 do { \
701 IOStatistics::onKextUnload(kext); \
702 } while (0)
703
704 #define notifyAddClassObservers(kext, addedClass, flags) \
705 do { \
706 IOStatistics::onClassAdded(kext, addedClass); \
707 } while (0)
708
709 #define notifyRemoveClassObservers(kext, removedClass, flags) \
710 do { \
711 IOStatistics::onClassRemoved(kext, removedClass); \
712 } while (0)
713
714 #else
715
716 #define notifyKextLoadObservers(kext, kmod_info)
717 #define notifyKextUnloadObservers(kext)
718 #define notifyAddClassObservers(kext, addedClass, flags)
719 #define notifyRemoveClassObservers(kext, removedClass, flags)
720
721 #endif /* IOKITSTATS */
722
723 #if PRAGMA_MARK
724 #pragma mark Module Config (Startup & Shutdown)
725 #endif
726 /*********************************************************************
727 * Module Config (Class Definition & Class Methods)
728 *********************************************************************/
729 #define super OSObject
730 OSDefineMetaClassAndStructors(OSKext, OSObject)
731
732 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
733
734 /*********************************************************************
735 *********************************************************************/
736 /* static */
737 void
initialize(void)738 OSKext::initialize(void)
739 {
740 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
741 u_char * kernelStart = NULL;// do not free
742 size_t kernelLength = 0;
743 IORegistryEntry * registryRoot = NULL;// do not release
744 OSSharedPtr<OSNumber> kernelCPUType;
745 OSSharedPtr<OSNumber> kernelCPUSubtype;
746 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
747 bool setResult = false;
748 uint64_t * timestamp = NULL;
749 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
750
751 /* This must be the first thing allocated. Everything else grabs this lock.
752 */
753 sKextLock = IORecursiveLockAlloc();
754 sKextInnerLock = IORecursiveLockAlloc();
755 sKextSummariesLock = IOLockAlloc();
756 sKextLoggingLock = IOLockAlloc();
757 assert(sKextLock);
758 assert(sKextInnerLock);
759 assert(sKextSummariesLock);
760 assert(sKextLoggingLock);
761
762 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
763 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
764 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
765 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
766 sKernelRequests = OSArray::withCapacity(0);
767 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
768 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
769 sRequestCallbackRecords = OSArray::withCapacity(0);
770 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
771 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
772 sRequestCallbackRecords && sUnloadedPrelinkedKexts);
773
774 /* Read the log flag boot-args and set the log flags.
775 */
776 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
777 sBootArgLogFilterFound = true;
778 sKernelLogFilter = bootLogFilter;
779 // log this if any flags are set
780 OSKextLog(/* kext */ NULL,
781 kOSKextLogBasicLevel |
782 kOSKextLogFlagsMask,
783 "Kernel kext log filter 0x%x per kextlog boot arg.",
784 (unsigned)sKernelLogFilter);
785 }
786
787 #if !defined(__arm__) && !defined(__arm64__)
788 /*
789 * On our ARM targets, the kernelcache/boot kernel collection contains
790 * the set of kexts required to boot, as specified by KCB. Safeboot is
791 * either unsupported, or is supported by the bootloader only loading
792 * the boot kernel collection; as a result OSKext has no role to play
793 * in safeboot policy on ARM.
794 */
795 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
796 sizeof(bootArgBuffer)) ? true : false;
797 #endif /* defined(__arm__) && defined(__arm64__) */
798
799 if (sSafeBoot) {
800 OSKextLog(/* kext */ NULL,
801 kOSKextLogWarningLevel |
802 kOSKextLogGeneralFlag,
803 "SAFE BOOT DETECTED - "
804 "only valid OSBundleRequired kexts will be loaded.");
805 }
806
807 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
808 #if CONFIG_DTRACE
809 if (dtrace_keep_kernel_symbols()) {
810 sKeepSymbols = true;
811 }
812 #endif /* CONFIG_DTRACE */
813 #if KASAN_DYNAMIC_BLACKLIST
814 /* needed for function lookup */
815 sKeepSymbols = true;
816 #endif
817
818 /*
819 * Should we panic when the SystemKC is not linked against the
820 * BootKC that was loaded by the booter? By default: yes, if the
821 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
822 * on mis-match and instead just print an error and continue.
823 */
824 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
825 sizeof(bootArgBuffer)) ? false : true;
826
827 /* Set up an OSKext instance to represent the kernel itself.
828 */
829 sKernelKext = new OSKext;
830 assert(sKernelKext);
831
832 kernelStart = (u_char *)&_mh_execute_header;
833 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
834 assert(kernelLength <= UINT_MAX);
835 kernelExecutable = OSData::withBytesNoCopy(
836 kernelStart, (unsigned int)kernelLength);
837 assert(kernelExecutable);
838
839 #if KASLR_KEXT_DEBUG
840 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %lu (0x%016lx) \n",
841 (unsigned long)kernelStart,
842 (unsigned long)getlastaddr(),
843 kernelLength,
844 (unsigned long)vm_kernel_slide,
845 (unsigned long)vm_kernel_slide);
846 #endif
847
848 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
849 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
850
851 sKernelKext->version = OSKextParseVersionString(osrelease);
852 sKernelKext->compatibleVersion = sKernelKext->version;
853 sKernelKext->linkedExecutable = os::move(kernelExecutable);
854 sKernelKext->interfaceUUID = sKernelKext->copyUUID();
855
856 sKernelKext->flags.hasAllDependencies = 1;
857 sKernelKext->flags.kernelComponent = 1;
858 sKernelKext->flags.prelinked = 0;
859 sKernelKext->flags.loaded = 1;
860 sKernelKext->flags.started = 1;
861 sKernelKext->flags.CPPInitialized = 0;
862 sKernelKext->flags.jettisonLinkeditSeg = 0;
863
864 sKernelKext->kmod_info = &g_kernel_kmod_info;
865 strlcpy(g_kernel_kmod_info.version, osrelease,
866 sizeof(g_kernel_kmod_info.version));
867 g_kernel_kmod_info.size = kernelLength;
868 g_kernel_kmod_info.id = sKernelKext->loadTag;
869
870 /* Cons up an info dict, so we don't have to have special-case
871 * checking all over.
872 */
873 sKernelKext->infoDict = OSDictionary::withCapacity(5);
874 assert(sKernelKext->infoDict);
875 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
876 sKernelKext->bundleID.get());
877 assert(setResult);
878 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
879 kOSBooleanTrue);
880 assert(setResult);
881
882 {
883 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
884 assert(scratchString);
885 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
886 scratchString.get());
887 assert(setResult);
888 }
889
890 {
891 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy("mach_kernel"));
892 assert(scratchString);
893 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
894 scratchString.get());
895 assert(setResult);
896 }
897
898 /* Add the kernel kext to the bookkeeping dictionaries. Note that
899 * the kernel kext doesn't have a kmod_info struct. copyInfo()
900 * gathers info from other places anyhow.
901 */
902 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
903 assert(setResult);
904 setResult = sLoadedKexts->setObject(sKernelKext);
905 assert(setResult);
906
907 // XXX: better way with OSSharedPtr?
908 // sKernelKext remains a valid pointer even after the decref
909 sKernelKext->release();
910
911 registryRoot = IORegistryEntry::getRegistryRoot();
912 kernelCPUType = OSNumber::withNumber(
913 (long long unsigned int)_mh_execute_header.cputype,
914 8 * sizeof(_mh_execute_header.cputype));
915 kernelCPUSubtype = OSNumber::withNumber(
916 (long long unsigned int)_mh_execute_header.cpusubtype,
917 8 * sizeof(_mh_execute_header.cpusubtype));
918 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
919
920 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
921 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
922
923 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
924 if (gBuiltinKmodsSectionInfo) {
925 uint32_t count;
926
927 assert(gBuiltinKmodsSectionInfo->addr);
928 assert(gBuiltinKmodsSectionInfo->size);
929 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
930 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
931
932 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
933 assert(gBuiltinKmodsSectionStart);
934 assert(gBuiltinKmodsSectionStart->addr);
935 assert(gBuiltinKmodsSectionStart->size);
936 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
937 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
938 // one extra pointer for the end of last kmod
939 assert(count == (gBuiltinKmodsCount + 1));
940
941 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
942 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
943 }
944
945 // Don't track this object -- it's never released
946 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
947
948 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
949 *timestamp = 0;
950 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
951 *timestamp = 0;
952 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
953 *timestamp = 0;
954
955 OSKextLog(/* kext */ NULL,
956 kOSKextLogProgressLevel |
957 kOSKextLogGeneralFlag,
958 "Kext system initialized.");
959
960 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
961
962 return;
963 }
964
965 /*********************************************************************
966 * This is expected to be called exactly once, from exactly one thread
967 * context, during kernel bootstrap.
968 *********************************************************************/
969 /* static */
970 OSReturn
removeKextBootstrap(void)971 OSKext::removeKextBootstrap(void)
972 {
973 OSReturn result = kOSReturnError;
974
975 const char * dt_kernel_header_name = "Kernel-__HEADER";
976 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
977 kernel_mach_header_t * dt_mach_header = NULL;
978 int dt_mach_header_size = 0;
979 struct symtab_command * dt_symtab = NULL;
980 int dt_symtab_size = 0;
981 int dt_result = 0;
982
983 kernel_segment_command_t * seg_kld = NULL;
984 kernel_segment_command_t * seg_klddata = NULL;
985 kernel_segment_command_t * seg_linkedit = NULL;
986
987 const char __unused * dt_segment_name = NULL;
988 void __unused * segment_paddress = NULL;
989 int __unused segment_size = 0;
990
991 OSKextLog(/* kext */ NULL,
992 kOSKextLogProgressLevel |
993 kOSKextLogGeneralFlag,
994 "Jettisoning kext bootstrap segments.");
995
996 /*
997 * keep the linkedit segment around when booted from a new MH_FILESET
998 * KC because all the kexts shared a linkedit segment.
999 */
1000 kc_format_t kc_format;
1001 if (!PE_get_primary_kc_format(&kc_format)) {
1002 OSKextLog(/* kext */ NULL,
1003 kOSKextLogErrorLevel |
1004 kOSKextLogGeneralFlag,
1005 "Unable to determine primary KC format");
1006 }
1007
1008 /*****
1009 * Dispose of unnecessary stuff that the booter didn't need to load.
1010 */
1011 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1012 (void **)&dt_mach_header, &dt_mach_header_size);
1013 if (dt_result == 0 && dt_mach_header) {
1014 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1015 round_page_32(dt_mach_header_size));
1016 }
1017 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1018 (void **)&dt_symtab, &dt_symtab_size);
1019 if (dt_result == 0 && dt_symtab) {
1020 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1021 round_page_32(dt_symtab_size));
1022 }
1023
1024 /*****
1025 * KLD & KLDDATA bootstrap segments.
1026 */
1027 // xxx - should rename KLD segment
1028 seg_kld = getsegbyname("__KLD");
1029 seg_klddata = getsegbyname("__KLDDATA");
1030 if (seg_klddata) {
1031 // __mod_term_func is part of __KLDDATA
1032 OSRuntimeUnloadCPPForSegment(seg_klddata);
1033 }
1034
1035 #if __arm__ || __arm64__
1036 /* Free the memory that was set up by iBoot.
1037 */
1038 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1039 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1040 * is covered by the contiguous rorgn.
1041 */
1042 dt_segment_name = "Kernel-__KLD";
1043 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1044 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1045 (int)segment_size); // calls ml_static_mfree
1046 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1047 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1048 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1049 seg_kld->vmsize);
1050 }
1051 #endif
1052 dt_segment_name = "Kernel-__KLDDATA";
1053 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1054 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1055 (int)segment_size); // calls ml_static_mfree
1056 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1057 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1058 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1059 seg_klddata->vmsize);
1060 }
1061 #elif __i386__ || __x86_64__
1062 /* On x86, use the mapping data from the segment load command to
1063 * unload KLD & KLDDATA directly.
1064 * This may invalidate any assumptions about "avail_start"
1065 * defining the lower bound for valid physical addresses.
1066 */
1067 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1068 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1069 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1070 }
1071 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1072 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1073 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1074 }
1075 #else
1076 #error arch
1077 #endif
1078
1079 /*****
1080 * Prelinked kernel's symtab (if there is one).
1081 */
1082 if (kc_format != KCFormatFileset) {
1083 kernel_section_t * sect;
1084 sect = getsectbyname("__PRELINK", "__symtab");
1085 if (sect && sect->addr && sect->size) {
1086 ml_static_mfree(sect->addr, sect->size);
1087 }
1088 }
1089
1090 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1091
1092 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1093 * pageable, unless keepsyms is set. To do that, we have to copy it from
1094 * its booter-allocated memory, free the booter memory, reallocate proper
1095 * managed memory, then copy the segment back in.
1096 *
1097 * NOTE: This optimization is not valid for fileset KCs because each
1098 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1099 * that points to one fileset-global LINKEDIT segment. This
1100 * optimization is also only valid for platforms that support vm
1101 * mapped kexts or mapped kext collections (pageable KCs)
1102 */
1103 #if VM_MAPPED_KEXTS
1104 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1105 kern_return_t mem_result;
1106 void *seg_copy = NULL;
1107 void *seg_data = NULL;
1108 vm_map_offset_t seg_offset = 0;
1109 vm_map_offset_t seg_copy_offset = 0;
1110 vm_map_size_t seg_length = 0;
1111
1112 seg_data = (void *) seg_linkedit->vmaddr;
1113 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1114 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1115
1116 /* Allocate space for the LINKEDIT copy.
1117 */
1118 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1119 seg_length, VM_KERN_MEMORY_KEXT);
1120 if (mem_result != KERN_SUCCESS) {
1121 OSKextLog(/* kext */ NULL,
1122 kOSKextLogErrorLevel |
1123 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1124 "Can't copy __LINKEDIT segment for VM reassign.");
1125 return result;
1126 }
1127 seg_copy_offset = (vm_map_offset_t) seg_copy;
1128
1129 /* Copy it out.
1130 */
1131 memcpy(seg_copy, seg_data, seg_length);
1132
1133 /* Dump the booter memory.
1134 */
1135 ml_static_mfree(seg_offset, seg_length);
1136
1137 /* Set up the VM region.
1138 */
1139 mem_result = vm_map_enter_mem_object(
1140 kernel_map,
1141 &seg_offset,
1142 seg_length, /* mask */ 0,
1143 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1144 VM_MAP_KERNEL_FLAGS_NONE,
1145 VM_KERN_MEMORY_NONE,
1146 (ipc_port_t)NULL,
1147 (vm_object_offset_t) 0,
1148 /* copy */ FALSE,
1149 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1150 /* max_protection */ VM_PROT_ALL,
1151 /* inheritance */ VM_INHERIT_DEFAULT);
1152 if ((mem_result != KERN_SUCCESS) ||
1153 (seg_offset != (vm_map_offset_t) seg_data)) {
1154 OSKextLog(/* kext */ NULL,
1155 kOSKextLogErrorLevel |
1156 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1157 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1158 seg_data, seg_length, mem_result);
1159 return result;
1160 }
1161
1162 /* And copy it back.
1163 */
1164 memcpy(seg_data, seg_copy, seg_length);
1165
1166 /* Free the copy.
1167 */
1168 kmem_free(kernel_map, seg_copy_offset, seg_length);
1169 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1170 /* Remove the linkedit segment of the Boot KC */
1171 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1172 OSKext::jettisonFileSetLinkeditSegment(mh);
1173 }
1174 #else // !VM_MAPPED_KEXTS
1175 /*****
1176 * Dump the LINKEDIT segment, unless keepsyms is set.
1177 */
1178 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1179 dt_segment_name = "Kernel-__LINKEDIT";
1180 if (0 == IODTGetLoaderInfo(dt_segment_name,
1181 &segment_paddress, &segment_size)) {
1182 #ifdef SECURE_KERNEL
1183 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1184 bzero((void*)vmaddr, segment_size);
1185 #endif
1186 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1187 (int)segment_size);
1188 }
1189 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1190 /* Remove the linkedit segment of the Boot KC */
1191 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1192 OSKext::jettisonFileSetLinkeditSegment(mh);
1193 } else {
1194 OSKextLog(/* kext */ NULL,
1195 kOSKextLogBasicLevel |
1196 kOSKextLogGeneralFlag,
1197 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1198 }
1199 #endif // VM_MAPPED_KEXTS
1200
1201 result = kOSReturnSuccess;
1202
1203 return result;
1204 }
1205
1206 #if CONFIG_KXLD
1207 /*********************************************************************
1208 *********************************************************************/
1209 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1210 OSKext::flushNonloadedKexts(
1211 Boolean flushPrelinkedKexts)
1212 {
1213 OSSharedPtr<OSSet> keepKexts;
1214
1215 /* TODO: make this more efficient with MH_FILESET kexts */
1216
1217 // Do not unload prelinked kexts on arm because the kernelcache is not
1218 // structured in a way that allows them to be unmapped
1219 #if !defined(__x86_64__)
1220 flushPrelinkedKexts = false;
1221 #endif /* defined(__x86_64__) */
1222
1223 IORecursiveLockLock(sKextLock);
1224
1225 OSKextLog(/* kext */ NULL,
1226 kOSKextLogProgressLevel |
1227 kOSKextLogKextBookkeepingFlag,
1228 "Flushing nonloaded kexts and other unused data.");
1229
1230 OSKext::considerDestroyingLinkContext();
1231
1232 /* If we aren't flushing unused prelinked kexts, we have to put them
1233 * aside while we flush everything else so make a container for them.
1234 */
1235 keepKexts = OSSet::withCapacity(16);
1236 if (!keepKexts) {
1237 goto finish;
1238 }
1239
1240 /* Set aside prelinked kexts (in-use or not) and break
1241 * any lingering inter-kext references for nonloaded kexts
1242 * so they have min. retain counts.
1243 */
1244 {
1245 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1246 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1247 if (!thisKext) {
1248 return false;
1249 }
1250 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1251 keepKexts->setObject(thisKext);
1252 } else if (!thisKext->declaresExecutable()) {
1253 /*
1254 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1255 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1256 * flushNonloadedKexts().
1257 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1258 */
1259 keepKexts->setObject(thisKext);
1260 } else if (thisKext->isInFileset()) {
1261 /* keep all kexts in the new MH_FILESET KC */
1262 keepKexts->setObject(thisKext);
1263 }
1264
1265 thisKext->flushDependencies(/* forceIfLoaded */ false);
1266 return false;
1267 });
1268 }
1269 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1270 */
1271 sKextsByID->flushCollection();
1272
1273 /* Now put the loaded kexts back into the ID dictionary.
1274 */
1275 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1276 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1277 if (!thisKext) {
1278 return false;
1279 }
1280 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1281 return false;
1282 });
1283
1284 /* Finally, put back the kept kexts if we saved any.
1285 */
1286 keepKexts->iterateObjects(^bool (OSObject * obj) {
1287 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1288 if (!thisKext) {
1289 return false;
1290 }
1291 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1292 return false;
1293 });
1294
1295 finish:
1296 IORecursiveLockUnlock(sKextLock);
1297 return;
1298 }
1299 #else /* !CONFIG_KXLD */
1300
1301 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1302 OSKext::flushNonloadedKexts(
1303 Boolean flushPrelinkedKexts __unused)
1304 {
1305 IORecursiveLockLock(sKextLock);
1306
1307 OSKextLog(/* kext */ NULL,
1308 kOSKextLogProgressLevel |
1309 kOSKextLogKextBookkeepingFlag,
1310 "Flushing dependency info for non-loaded kexts.");
1311
1312 /*
1313 * In a world where we don't dynamically link kexts, they all come
1314 * from a kext collection that's either in wired memory, or
1315 * wire-on-demand. We don't need to mess around with moving kexts in
1316 * and out of the sKextsByID array - they can all just stay there.
1317 * Here we just flush the dependency list for kexts that are not
1318 * loaded.
1319 */
1320 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1321 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1322 if (!thisKext) {
1323 return false;
1324 }
1325 thisKext->flushDependencies(/* forceIfLoaded */ false);
1326 return false;
1327 });
1328
1329 IORecursiveLockUnlock(sKextLock);
1330 return;
1331 }
1332
1333 #endif /* CONFIG_KXLD */
1334
1335 /*********************************************************************
1336 *********************************************************************/
1337 /* static */
1338 void
setIOKitDaemonActive(bool active)1339 OSKext::setIOKitDaemonActive(bool active)
1340 {
1341 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1342 IORecursiveLockLock(sKextLock);
1343 sIOKitDaemonActive = active;
1344 if (sKernelRequests->getCount()) {
1345 OSKext::pingIOKitDaemon();
1346 }
1347 IORecursiveLockUnlock(sKextLock);
1348
1349 return;
1350 }
1351
1352 /*********************************************************************
1353 * OSKextLib.cpp might need access to this someday but for now it's
1354 * private.
1355 *********************************************************************/
1356 extern "C" {
1357 extern void ipc_port_release_send(ipc_port_t);
1358 };
1359
1360 /* static */
1361 OSReturn
pingIOKitDaemon(void)1362 OSKext::pingIOKitDaemon(void)
1363 {
1364 OSReturn result = kOSReturnError;
1365 #if !NO_KEXTD
1366 mach_port_t kextd_port = IPC_PORT_NULL;
1367
1368 if (!sIOKitDaemonActive) {
1369 result = kOSKextReturnDisabled; // basically unavailable
1370 goto finish;
1371 }
1372
1373 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1374 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1375 OSKextLog(/* kext */ NULL,
1376 kOSKextLogErrorLevel |
1377 kOSKextLogIPCFlag,
1378 "Can't get " kIOKitDaemonName " port.");
1379 goto finish;
1380 }
1381
1382 result = kextd_ping(kextd_port);
1383 if (result != KERN_SUCCESS) {
1384 OSKextLog(/* kext */ NULL,
1385 kOSKextLogErrorLevel |
1386 kOSKextLogIPCFlag,
1387 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1388 goto finish;
1389 }
1390
1391 finish:
1392 if (IPC_PORT_VALID(kextd_port)) {
1393 ipc_port_release_send(kextd_port);
1394 }
1395 #endif
1396
1397 return result;
1398 }
1399
1400 /*********************************************************************
1401 *********************************************************************/
1402 /* static */
1403 void
setDeferredLoadSucceeded(Boolean succeeded)1404 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1405 {
1406 IORecursiveLockLock(sKextLock);
1407 sDeferredLoadSucceeded = succeeded;
1408 IORecursiveLockUnlock(sKextLock);
1409
1410 return;
1411 }
1412
1413 /*********************************************************************
1414 * Called from IOSystemShutdownNotification.
1415 *********************************************************************/
1416 /* static */
1417 void
willShutdown(void)1418 OSKext::willShutdown(void)
1419 {
1420 #if !NO_KEXTD
1421 OSReturn checkResult = kOSReturnError;
1422 #endif
1423 OSSharedPtr<OSDictionary> exitRequest;
1424
1425 IORecursiveLockLock(sKextLock);
1426
1427 OSKext::setLoadEnabled(false);
1428 OSKext::setUnloadEnabled(false);
1429 OSKext::setAutounloadsEnabled(false);
1430 OSKext::setKernelRequestsEnabled(false);
1431
1432 #if defined(__x86_64__) || defined(__i386__)
1433 if (IOPMRootDomainGetWillShutdown()) {
1434 OSKext::freeKCFileSetcontrol();
1435 }
1436 #endif // (__x86_64__) || defined(__i386__)
1437
1438 #if !NO_KEXTD
1439 OSKextLog(/* kext */ NULL,
1440 kOSKextLogProgressLevel |
1441 kOSKextLogGeneralFlag,
1442 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1443
1444 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1445 exitRequest);
1446 if (checkResult != kOSReturnSuccess) {
1447 goto finish;
1448 }
1449 if (!sKernelRequests->setObject(exitRequest.get())) {
1450 goto finish;
1451 }
1452
1453 OSKext::pingIOKitDaemon();
1454
1455 finish:
1456 #endif
1457
1458 IORecursiveLockUnlock(sKextLock);
1459 return;
1460 }
1461
1462 void
willUserspaceReboot(void)1463 OSKext::willUserspaceReboot(void)
1464 {
1465 OSKext::willShutdown();
1466 IOService::userSpaceWillReboot();
1467 gIOCatalogue->terminateDriversForUserspaceReboot();
1468 }
1469
1470 void
resetAfterUserspaceReboot(void)1471 OSKext::resetAfterUserspaceReboot(void)
1472 {
1473 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1474 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1475
1476 IORecursiveLockLock(sKextLock);
1477 gIOCatalogue->resetAfterUserspaceReboot();
1478 IOService::userSpaceDidReboot();
1479 OSKext::removeDaemonExitRequests();
1480 OSKext::setLoadEnabled(true);
1481 OSKext::setUnloadEnabled(true);
1482 OSKext::setAutounloadsEnabled(true);
1483 OSKext::setKernelRequestsEnabled(true);
1484 sOSKextWasResetAfterUserspaceReboot = true;
1485 IORecursiveLockUnlock(sKextLock);
1486 }
1487
1488 extern "C" void
OSKextResetAfterUserspaceReboot(void)1489 OSKextResetAfterUserspaceReboot(void)
1490 {
1491 OSKext::resetAfterUserspaceReboot();
1492 }
1493
1494 /*
1495 * Remove daemon exit requests from sKernelRequests
1496 *
1497 * If we sent a daemon exit request during a userspace reboot and launchd
1498 * killed the IOKit daemon before it was able to dequeue the exit request, the
1499 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1500 *
1501 * This removes exit requests so that this does not happen.
1502 */
1503 void
removeDaemonExitRequests(void)1504 OSKext::removeDaemonExitRequests(void)
1505 {
1506 OSDictionary * current = NULL;
1507 OSString * predicate = NULL;
1508 size_t index = 0;
1509 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1510
1511 while (index < sKernelRequests->getCount()) {
1512 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1513 if (current) {
1514 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1515 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1516 sKernelRequests->removeObject(index);
1517 continue;
1518 }
1519 }
1520 index++;
1521 }
1522 }
1523
1524 /*********************************************************************
1525 *********************************************************************/
1526 /* static */
1527 bool
getLoadEnabled(void)1528 OSKext::getLoadEnabled(void)
1529 {
1530 bool result;
1531
1532 IORecursiveLockLock(sKextLock);
1533 result = sLoadEnabled;
1534 IORecursiveLockUnlock(sKextLock);
1535 return result;
1536 }
1537
1538 /*********************************************************************
1539 *********************************************************************/
1540 /* static */
1541 bool
setLoadEnabled(bool flag)1542 OSKext::setLoadEnabled(bool flag)
1543 {
1544 bool result;
1545
1546 IORecursiveLockLock(sKextLock);
1547 result = sLoadEnabled;
1548 sLoadEnabled = (flag ? true : false);
1549
1550 if (sLoadEnabled != result) {
1551 OSKextLog(/* kext */ NULL,
1552 kOSKextLogBasicLevel |
1553 kOSKextLogLoadFlag,
1554 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1555 }
1556
1557 IORecursiveLockUnlock(sKextLock);
1558
1559 return result;
1560 }
1561
1562 /*********************************************************************
1563 *********************************************************************/
1564 /* static */
1565 bool
getUnloadEnabled(void)1566 OSKext::getUnloadEnabled(void)
1567 {
1568 bool result;
1569
1570 IORecursiveLockLock(sKextLock);
1571 result = sUnloadEnabled;
1572 IORecursiveLockUnlock(sKextLock);
1573 return result;
1574 }
1575
1576 /*********************************************************************
1577 *********************************************************************/
1578 /* static */
1579 bool
setUnloadEnabled(bool flag)1580 OSKext::setUnloadEnabled(bool flag)
1581 {
1582 bool result;
1583
1584 IORecursiveLockLock(sKextLock);
1585 result = sUnloadEnabled;
1586 sUnloadEnabled = (flag ? true : false);
1587 IORecursiveLockUnlock(sKextLock);
1588
1589 if (sUnloadEnabled != result) {
1590 OSKextLog(/* kext */ NULL,
1591 kOSKextLogBasicLevel |
1592 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1593 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1594 }
1595
1596 return result;
1597 }
1598
1599 /*********************************************************************
1600 * Do not call any function that takes sKextLock here!
1601 *********************************************************************/
1602 /* static */
1603 bool
getAutounloadEnabled(void)1604 OSKext::getAutounloadEnabled(void)
1605 {
1606 #if XNU_TARGET_OS_OSX
1607 bool result;
1608
1609 IORecursiveLockLock(sKextInnerLock);
1610 result = sAutounloadEnabled ? true : false;
1611 IORecursiveLockUnlock(sKextInnerLock);
1612 return result;
1613 #else
1614 return false;
1615 #endif /* XNU_TARGET_OS_OSX */
1616 }
1617
1618 /*********************************************************************
1619 * Do not call any function that takes sKextLock here!
1620 *********************************************************************/
1621 /* static */
1622 bool
setAutounloadsEnabled(bool flag)1623 OSKext::setAutounloadsEnabled(bool flag)
1624 {
1625 #if XNU_TARGET_OS_OSX
1626 bool result;
1627
1628 IORecursiveLockLock(sKextInnerLock);
1629
1630 result = sAutounloadEnabled;
1631 sAutounloadEnabled = (flag ? true : false);
1632 if (!sAutounloadEnabled && sUnloadCallout) {
1633 thread_call_cancel(sUnloadCallout);
1634 }
1635
1636 if (sAutounloadEnabled != result) {
1637 OSKextLog(/* kext */ NULL,
1638 kOSKextLogBasicLevel |
1639 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1640 "Kext autounloading now %sabled.",
1641 sAutounloadEnabled ? "en" : "dis");
1642 }
1643
1644 IORecursiveLockUnlock(sKextInnerLock);
1645
1646 return result;
1647 #else
1648 (void)flag;
1649 return false;
1650 #endif /* XNU_TARGET_OS_OSX */
1651 }
1652
1653 /*********************************************************************
1654 *********************************************************************/
1655 /* instance method operating on OSKext field */
1656 bool
setAutounloadEnabled(bool flag)1657 OSKext::setAutounloadEnabled(bool flag)
1658 {
1659 bool result = flags.autounloadEnabled ? true : false;
1660 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1661
1662 if (result != (flag ? true : false)) {
1663 OSKextLog(this,
1664 kOSKextLogProgressLevel |
1665 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1666 "Autounloading for kext %s now %sabled.",
1667 getIdentifierCString(),
1668 flags.autounloadEnabled ? "en" : "dis");
1669 }
1670 return result;
1671 }
1672
1673 /*********************************************************************
1674 *********************************************************************/
1675 /* static */
1676 bool
setKernelRequestsEnabled(bool flag)1677 OSKext::setKernelRequestsEnabled(bool flag)
1678 {
1679 bool result;
1680
1681 IORecursiveLockLock(sKextLock);
1682 result = sKernelRequestsEnabled;
1683 sKernelRequestsEnabled = flag ? true : false;
1684
1685 if (sKernelRequestsEnabled != result) {
1686 OSKextLog(/* kext */ NULL,
1687 kOSKextLogBasicLevel |
1688 kOSKextLogGeneralFlag,
1689 "Kernel requests now %sabled.",
1690 sKernelRequestsEnabled ? "en" : "dis");
1691 }
1692 IORecursiveLockUnlock(sKextLock);
1693 return result;
1694 }
1695
1696 /*********************************************************************
1697 *********************************************************************/
1698 /* static */
1699 bool
getKernelRequestsEnabled(void)1700 OSKext::getKernelRequestsEnabled(void)
1701 {
1702 bool result;
1703
1704 IORecursiveLockLock(sKextLock);
1705 result = sKernelRequestsEnabled;
1706 IORecursiveLockUnlock(sKextLock);
1707 return result;
1708 }
1709
1710 static bool
segmentIsMutable(kernel_segment_command_t * seg)1711 segmentIsMutable(kernel_segment_command_t *seg)
1712 {
1713 /* Mutable segments have to have VM_PROT_WRITE */
1714 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1715 return false;
1716 }
1717 /* Exclude the __DATA_CONST segment */
1718 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1719 return false;
1720 }
1721 /* Exclude __LINKEDIT */
1722 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1723 return false;
1724 }
1725 return true;
1726 }
1727
1728 #if PRAGMA_MARK
1729 #pragma mark Kext Life Cycle
1730 #endif
1731 /*********************************************************************
1732 *********************************************************************/
1733 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1734 OSKext::withPrelinkedInfoDict(
1735 OSDictionary * anInfoDict,
1736 bool doCoalescedSlides,
1737 kc_kind_t type)
1738 {
1739 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1740
1741 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1742 return NULL;
1743 }
1744
1745 return newKext;
1746 }
1747
1748 /*********************************************************************
1749 *********************************************************************/
1750 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1751 OSKext::initWithPrelinkedInfoDict(
1752 OSDictionary * anInfoDict,
1753 bool doCoalescedSlides,
1754 kc_kind_t type)
1755 {
1756 bool result = false;
1757 OSString * kextPath = NULL; // do not release
1758 OSNumber * addressNum = NULL; // reused; do not release
1759 OSNumber * lengthNum = NULL; // reused; do not release
1760 OSBoolean * scratchBool = NULL; // do not release
1761 void * data = NULL; // do not free
1762 void * srcData = NULL; // do not free
1763 OSSharedPtr<OSData> prelinkedExecutable;
1764 uint32_t length = 0; // reused
1765 uintptr_t kext_slide = PE_get_kc_slide(type);
1766 bool shouldSaveSegments = false;
1767
1768 if (!super::init()) {
1769 goto finish;
1770 }
1771
1772 /* Get the path. Don't look for an arch-specific path property.
1773 */
1774 kextPath = OSDynamicCast(OSString,
1775 anInfoDict->getObject(kPrelinkBundlePathKey));
1776
1777 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1778 goto finish;
1779 }
1780
1781 #if KASLR_KEXT_DEBUG
1782 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1783 #endif
1784
1785 /* Also get the executable's bundle-relative path if present.
1786 * Don't look for an arch-specific path property.
1787 */
1788 executableRelPath.reset(OSDynamicCast(OSString,
1789 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1790 userExecutableRelPath.reset(OSDynamicCast(OSString,
1791 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1792
1793 /* Don't need the paths to be in the info dictionary any more.
1794 */
1795 anInfoDict->removeObject(kPrelinkBundlePathKey);
1796 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1797
1798 scratchBool = OSDynamicCast(OSBoolean,
1799 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1800 if (scratchBool == kOSBooleanTrue) {
1801 flags.requireExplicitLoad = 1;
1802 }
1803
1804 /* Create an OSData wrapper around the linked executable.
1805 */
1806 addressNum = OSDynamicCast(OSNumber,
1807 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1808 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1809 lengthNum = OSDynamicCast(OSNumber,
1810 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1811 if (!lengthNum) {
1812 OSKextLog(this,
1813 kOSKextLogErrorLevel |
1814 kOSKextLogArchiveFlag,
1815 "Kext %s can't find prelinked kext executable size.",
1816 getIdentifierCString());
1817 return result;
1818 }
1819
1820 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1821 length = (uint32_t) (lengthNum->unsigned32BitValue());
1822
1823 #if KASLR_KEXT_DEBUG
1824 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1825 (unsigned long)ml_static_unslide((vm_offset_t)data),
1826 (unsigned long)data,
1827 length);
1828 #endif
1829
1830 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1831 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1832
1833 /* If the kext's load address differs from its source address, allocate
1834 * space in the kext map at the load address and copy the kext over.
1835 */
1836 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1837 if (addressNum) {
1838 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1839
1840 #if KASLR_KEXT_DEBUG
1841 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1842 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1843 (unsigned long)srcData);
1844 #endif
1845
1846 if (data != srcData) {
1847 #if __LP64__
1848 kern_return_t alloc_result;
1849
1850 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1851 if (alloc_result != KERN_SUCCESS) {
1852 OSKextLog(this,
1853 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1854 "Failed to allocate space for prelinked kext %s.",
1855 getIdentifierCString());
1856 goto finish;
1857 }
1858 memcpy(data, srcData, length);
1859 #else
1860 OSKextLog(this,
1861 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1862 "Error: prelinked kext %s - source and load addresses "
1863 "differ on ILP32 architecture.",
1864 getIdentifierCString());
1865 goto finish;
1866 #endif /* __LP64__ */
1867 }
1868
1869 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1870 }
1871
1872 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1873 if (!prelinkedExecutable) {
1874 OSKextLog(this,
1875 kOSKextLogErrorLevel |
1876 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1877 "Kext %s failed to create executable wrapper.",
1878 getIdentifierCString());
1879 goto finish;
1880 }
1881
1882 #if VM_MAPPED_KEXTS
1883 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1884 #else
1885 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1886 #endif
1887 setLinkedExecutable(prelinkedExecutable.get());
1888 addressNum = OSDynamicCast(OSNumber,
1889 anInfoDict->getObject(kPrelinkKmodInfoKey));
1890 if (!addressNum) {
1891 OSKextLog(this,
1892 kOSKextLogErrorLevel |
1893 kOSKextLogArchiveFlag,
1894 "Kext %s can't find prelinked kext kmod_info address.",
1895 getIdentifierCString());
1896 goto finish;
1897 }
1898
1899 if (addressNum->unsigned64BitValue() != 0) {
1900 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1901 if (kmod_info->address) {
1902 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
1903 } else {
1904 kmod_info->address = (uintptr_t)data;
1905 kmod_info->size = length;
1906 }
1907 #if KASLR_KEXT_DEBUG
1908 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1909 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
1910 (unsigned long)kmod_info);
1911 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1912 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
1913 (unsigned long)kmod_info->address);
1914 #endif
1915 }
1916
1917 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1918 }
1919
1920 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
1921 uintptr_t builtinTextStart;
1922 uintptr_t builtinTextEnd;
1923
1924 flags.builtin = true;
1925 builtinKmodIdx = addressNum->unsigned32BitValue();
1926 assert(builtinKmodIdx < gBuiltinKmodsCount);
1927
1928 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1929 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1930
1931 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1932 kmod_info->address = builtinTextStart;
1933 kmod_info->size = builtinTextEnd - builtinTextStart;
1934 }
1935
1936 /* If the plist has a UUID for an interface, save that off.
1937 */
1938 if (isInterface()) {
1939 interfaceUUID.reset(OSDynamicCast(OSData,
1940 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
1941 if (interfaceUUID) {
1942 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1943 }
1944 }
1945
1946 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
1947 if (!result) {
1948 goto finish;
1949 }
1950
1951 kc_type = type;
1952 /* Exclude builtin and codeless kexts */
1953 if (prelinkedExecutable && kmod_info) {
1954 switch (kc_type) {
1955 case KCKindPrimary:
1956 shouldSaveSegments = (
1957 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
1958 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
1959 if (shouldSaveSegments) {
1960 flags.resetSegmentsFromImmutableCopy = 1;
1961 } else {
1962 flags.unloadUnsupported = 1;
1963 }
1964 break;
1965 case KCKindPageable:
1966 flags.resetSegmentsFromVnode = 1;
1967 break;
1968 case KCKindAuxiliary:
1969 if (!pageableKCloaded) {
1970 flags.resetSegmentsFromImmutableCopy = 1;
1971 } else if (resetAuxKCSegmentOnUnload) {
1972 flags.resetSegmentsFromVnode = 1;
1973 } else {
1974 flags.unloadUnsupported = 1;
1975 }
1976 break;
1977 default:
1978 break;
1979 }
1980 }
1981
1982 if (flags.resetSegmentsFromImmutableCopy) {
1983 /* Save a pristine copy of the mutable segments */
1984 kernel_segment_command_t *seg = NULL;
1985 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
1986
1987 savedMutableSegments = OSArray::withCapacity(0);
1988
1989 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
1990 if (!segmentIsMutable(seg)) {
1991 continue;
1992 }
1993 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
1994 uint64_t vmsize = seg->vmsize;
1995 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1996 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1997 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
1998 if (!savedSegment) {
1999 OSKextLog(this,
2000 kOSKextLogErrorLevel |
2001 kOSKextLogGeneralFlag,
2002 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2003 result = kOSKextReturnInternalError;
2004 goto finish;
2005 }
2006 savedMutableSegments->setObject(savedSegment);
2007 }
2008 }
2009
2010 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2011 /*
2012 * set VM protections now, wire pages for the old style Aux KC now,
2013 * wire pages for the rest of the KC types at load time.
2014 */
2015 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2016 if (!result) {
2017 goto finish;
2018 }
2019 }
2020
2021 flags.prelinked = true;
2022
2023 /* If we created a kext from prelink info,
2024 * we must be booting from a prelinked kernel.
2025 */
2026 sPrelinkBoot = true;
2027
2028 result = registerIdentifier();
2029
2030 finish:
2031 return result;
2032 }
2033
2034 /*********************************************************************
2035 *********************************************************************/
2036 /* static */
2037 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict)2038 OSKext::withCodelessInfo(OSDictionary * anInfoDict)
2039 {
2040 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2041
2042 if (newKext && !newKext->initWithCodelessInfo(anInfoDict)) {
2043 return NULL;
2044 }
2045
2046 return newKext;
2047 }
2048
2049 /*********************************************************************
2050 *********************************************************************/
2051 bool
initWithCodelessInfo(OSDictionary * anInfoDict)2052 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2053 {
2054 bool result = false;
2055 OSString * kextPath = NULL; // do not release
2056 OSBoolean * scratchBool = NULL; // do not release
2057
2058 if (anInfoDict == NULL || !super::init()) {
2059 goto finish;
2060 }
2061
2062 /*
2063 * Get the path. Don't look for an arch-specific path property.
2064 */
2065 kextPath = OSDynamicCast(OSString,
2066 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2067 if (!kextPath) {
2068 OSKextLog(NULL,
2069 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2070 "Requested codeless kext dictionary does not contain the '%s' key",
2071 kKextRequestArgumentCodelessInfoBundlePathKey);
2072 goto finish;
2073 }
2074
2075 uniquePersonalityProperties(anInfoDict);
2076
2077 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2078 goto finish;
2079 }
2080
2081 /*
2082 * This path is meant to initialize codeless kexts only. Refuse
2083 * anything that looks like it has an executable and/or declares
2084 * itself as a kernel component.
2085 */
2086 if (declaresExecutable() || isKernelComponent()) {
2087 OSKextLog(NULL,
2088 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2089 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2090 getIdentifierCString());
2091 goto finish;
2092 }
2093
2094 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2095 boolean_t updated = updateExcludeList(infoDict.get());
2096 if (updated) {
2097 OSKextLog(this,
2098 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2099 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2100 }
2101 }
2102
2103 kc_type = KCKindNone;
2104
2105 scratchBool = OSDynamicCast(OSBoolean,
2106 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2107 if (scratchBool == kOSBooleanTrue) {
2108 flags.requireExplicitLoad = 1;
2109 }
2110
2111 /* Also get the executable's bundle-relative path if present.
2112 * Don't look for an arch-specific path property.
2113 */
2114 userExecutableRelPath.reset(OSDynamicCast(OSString,
2115 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2116
2117 /* remove unnecessary paths from the info dict */
2118 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2119
2120 result = registerIdentifier();
2121
2122 finish:
2123 return result;
2124 }
2125
2126 /*********************************************************************
2127 *********************************************************************/
2128 /* static */
2129 void
setAllVMAttributes(void)2130 OSKext::setAllVMAttributes(void)
2131 {
2132 OSSharedPtr<OSCollectionIterator> kextIterator;
2133 const OSSymbol * thisID = NULL; // do not release
2134
2135 IORecursiveLockLock(sKextLock);
2136
2137 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2138 if (!kextIterator) {
2139 goto finish;
2140 }
2141
2142 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2143 OSKext * thisKext; // do not release
2144
2145 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2146 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2147 continue;
2148 }
2149
2150 if (!thisKext->flags.resetSegmentsFromVnode) {
2151 /*
2152 * set VM protections now, wire pages for the old style Aux KC now,
2153 * wire pages for the rest of the KC types at load time.
2154 */
2155 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2156 }
2157 }
2158
2159 finish:
2160 IORecursiveLockUnlock(sKextLock);
2161
2162 return;
2163 }
2164
2165 /*********************************************************************
2166 *********************************************************************/
2167 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2168 OSKext::withBooterData(
2169 OSString * deviceTreeName,
2170 OSData * booterData)
2171 {
2172 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2173
2174 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2175 return NULL;
2176 }
2177
2178 return newKext;
2179 }
2180
2181 /*********************************************************************
2182 *********************************************************************/
2183 typedef struct _BooterKextFileInfo {
2184 uint32_t infoDictPhysAddr;
2185 uint32_t infoDictLength;
2186 uint32_t executablePhysAddr;
2187 uint32_t executableLength;
2188 uint32_t bundlePathPhysAddr;
2189 uint32_t bundlePathLength;
2190 } _BooterKextFileInfo;
2191
2192 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2193 OSKext::initWithBooterData(
2194 OSString * deviceTreeName,
2195 OSData * booterData)
2196 {
2197 bool result = false;
2198 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2199 char * infoDictAddr = NULL; // do not free
2200 void * executableAddr = NULL; // do not free
2201 char * bundlePathAddr = NULL; // do not free
2202
2203 OSDictionary * theInfoDict = NULL; // do not release
2204 OSSharedPtr<OSObject> parsedXML;
2205 OSSharedPtr<OSString> kextPath;
2206
2207 OSSharedPtr<OSString> errorString;
2208 OSSharedPtr<OSData> executable;
2209
2210 if (!super::init()) {
2211 goto finish;
2212 }
2213
2214 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2215 if (!kextFileInfo) {
2216 OSKextLog(this,
2217 kOSKextLogErrorLevel |
2218 kOSKextLogGeneralFlag,
2219 "No booter-provided data for kext device tree entry %s.",
2220 deviceTreeName->getCStringNoCopy());
2221 goto finish;
2222 }
2223
2224 /* The info plist must exist or we can't read the kext.
2225 */
2226 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2227 OSKextLog(this,
2228 kOSKextLogErrorLevel |
2229 kOSKextLogGeneralFlag,
2230 "No kext info dictionary for booter device tree entry %s.",
2231 deviceTreeName->getCStringNoCopy());
2232 goto finish;
2233 }
2234
2235 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2236 if (!infoDictAddr) {
2237 OSKextLog(this,
2238 kOSKextLogErrorLevel |
2239 kOSKextLogGeneralFlag,
2240 "Can't translate physical address 0x%x of kext info dictionary "
2241 "for device tree entry %s.",
2242 (int)kextFileInfo->infoDictPhysAddr,
2243 deviceTreeName->getCStringNoCopy());
2244 goto finish;
2245 }
2246
2247 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2248 if (parsedXML) {
2249 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2250 }
2251 if (!theInfoDict) {
2252 const char * errorCString = "(unknown error)";
2253
2254 if (errorString && errorString->getCStringNoCopy()) {
2255 errorCString = errorString->getCStringNoCopy();
2256 } else if (parsedXML) {
2257 errorCString = "not a dictionary";
2258 }
2259 OSKextLog(this,
2260 kOSKextLogErrorLevel |
2261 kOSKextLogGeneralFlag,
2262 "Error unserializing info dictionary for device tree entry %s: %s.",
2263 deviceTreeName->getCStringNoCopy(), errorCString);
2264 goto finish;
2265 }
2266
2267 /* A bundle path is not mandatory.
2268 */
2269 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2270 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2271 if (!bundlePathAddr) {
2272 OSKextLog(this,
2273 kOSKextLogErrorLevel |
2274 kOSKextLogGeneralFlag,
2275 "Can't translate physical address 0x%x of kext bundle path "
2276 "for device tree entry %s.",
2277 (int)kextFileInfo->bundlePathPhysAddr,
2278 deviceTreeName->getCStringNoCopy());
2279 goto finish;
2280 }
2281 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2282
2283 kextPath = OSString::withCString(bundlePathAddr);
2284 if (!kextPath) {
2285 OSKextLog(this,
2286 kOSKextLogErrorLevel |
2287 kOSKextLogGeneralFlag,
2288 "Failed to create wrapper for device tree entry %s kext path %s.",
2289 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2290 goto finish;
2291 }
2292 }
2293
2294 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2295 goto finish;
2296 }
2297
2298 /* An executable is not mandatory.
2299 */
2300 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2301 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2302 if (!executableAddr) {
2303 OSKextLog(this,
2304 kOSKextLogErrorLevel |
2305 kOSKextLogGeneralFlag,
2306 "Can't translate physical address 0x%x of kext executable "
2307 "for device tree entry %s.",
2308 (int)kextFileInfo->executablePhysAddr,
2309 deviceTreeName->getCStringNoCopy());
2310 goto finish;
2311 }
2312
2313 executable = OSData::withBytesNoCopy(executableAddr,
2314 kextFileInfo->executableLength);
2315 if (!executable) {
2316 OSKextLog(this,
2317 kOSKextLogErrorLevel |
2318 kOSKextLogGeneralFlag,
2319 "Failed to create executable wrapper for device tree entry %s.",
2320 deviceTreeName->getCStringNoCopy());
2321 goto finish;
2322 }
2323
2324 /* A kext with an executable needs to retain the whole booterData
2325 * object to keep the executable in memory.
2326 */
2327 if (!setExecutable(executable.get(), booterData)) {
2328 OSKextLog(this,
2329 kOSKextLogErrorLevel |
2330 kOSKextLogGeneralFlag,
2331 "Failed to set kext executable for device tree entry %s.",
2332 deviceTreeName->getCStringNoCopy());
2333 goto finish;
2334 }
2335 }
2336
2337 result = registerIdentifier();
2338
2339 finish:
2340 return result;
2341 }
2342
2343 /*********************************************************************
2344 *********************************************************************/
2345 bool
registerIdentifier(void)2346 OSKext::registerIdentifier(void)
2347 {
2348 bool result = false;
2349 OSKext * existingKext = NULL; // do not release
2350 bool existingIsLoaded = false;
2351 bool existingIsPrelinked = false;
2352 bool existingIsCodeless = false;
2353 bool existingIsDext = false;
2354 OSKextVersion newVersion = -1;
2355 OSKextVersion existingVersion = -1;
2356 char newVersionCString[kOSKextVersionMaxLength];
2357 char existingVersionCString[kOSKextVersionMaxLength];
2358 OSSharedPtr<OSData> newUUID;
2359 OSSharedPtr<OSData> existingUUID;
2360
2361 IORecursiveLockLock(sKextLock);
2362
2363 /* Get the new kext's version for checks & log messages.
2364 */
2365 newVersion = getVersion();
2366 OSKextVersionGetString(newVersion, newVersionCString,
2367 kOSKextVersionMaxLength);
2368
2369 /* If we don't have an existing kext with this identifier,
2370 * just record the new kext and we're done!
2371 */
2372 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2373 if (!existingKext) {
2374 sKextsByID->setObject(bundleID.get(), this);
2375 result = true;
2376 goto finish;
2377 }
2378
2379 /* Get the existing kext's version for checks & log messages.
2380 */
2381 existingVersion = existingKext->getVersion();
2382 OSKextVersionGetString(existingVersion,
2383 existingVersionCString, kOSKextVersionMaxLength);
2384
2385 existingIsLoaded = existingKext->isLoaded();
2386 existingIsPrelinked = existingKext->isPrelinked();
2387 existingIsDext = existingKext->isDriverKit();
2388 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2389
2390 /* If we have a non-codeless kext with this identifier that's already
2391 * loaded/prelinked, we can't use the new one, but let's be really
2392 * thorough and check how the two are related for a precise diagnostic
2393 * log message.
2394 *
2395 * This check is valid for kexts that declare an executable and for
2396 * dexts, but not for codeless kexts - we can just replace those.
2397 */
2398 if ((!existingIsCodeless || existingIsDext) &&
2399 (existingIsLoaded || existingIsPrelinked)) {
2400 bool sameVersion = (newVersion == existingVersion);
2401 bool sameExecutable = true; // assume true unless we have UUIDs
2402
2403 /* Only get the UUID if the existing kext is loaded. Doing so
2404 * might have to uncompress an mkext executable and we shouldn't
2405 * take that hit when neither kext is loaded.
2406 *
2407 * Note: there is no decompression that happens when all kexts
2408 * are loaded from kext collecitons.
2409 */
2410 newUUID = copyUUID();
2411 existingUUID = existingKext->copyUUID();
2412
2413 if (existingIsDext && !isDriverKit()) {
2414 OSKextLog(this,
2415 kOSKextLogWarningLevel |
2416 kOSKextLogKextBookkeepingFlag,
2417 "Notice - new kext %s, v%s matches a %s dext"
2418 "with the same bundle ID, v%s.",
2419 getIdentifierCString(), newVersionCString,
2420 (existingIsLoaded ? "loaded" : "prelinked"),
2421 existingVersionCString);
2422 goto finish;
2423 }
2424
2425 /* I'm entirely too paranoid about checking equivalence of executables,
2426 * but I remember nasty problems with it in the past.
2427 *
2428 * - If we have UUIDs for both kexts, compare them.
2429 * - If only one kext has a UUID, they're definitely different.
2430 */
2431 if (newUUID && existingUUID) {
2432 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2433 } else if (newUUID || existingUUID) {
2434 sameExecutable = false;
2435 }
2436
2437 if (!newUUID && !existingUUID) {
2438 /* If there are no UUIDs, we can't really tell that the executables
2439 * are *different* without a lot of work; the loaded kext's
2440 * unrelocated executable is no longer around (and we never had it
2441 * in-kernel for a prelinked kext). We certainly don't want to do
2442 * a whole fake link for the new kext just to compare, either.
2443 */
2444 OSKextLog(this,
2445 kOSKextLogWarningLevel |
2446 kOSKextLogKextBookkeepingFlag,
2447 "Notice - new kext %s, v%s matches %s kext "
2448 "but can't determine if executables are the same (no UUIDs).",
2449 getIdentifierCString(),
2450 newVersionCString,
2451 (existingIsLoaded ? "loaded" : "prelinked"));
2452 }
2453
2454 if (sameVersion && sameExecutable) {
2455 OSKextLog(this,
2456 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2457 kOSKextLogKextBookkeepingFlag,
2458 "Refusing new kext %s, v%s: a %s copy is already present "
2459 "(same version and executable).",
2460 getIdentifierCString(), newVersionCString,
2461 (existingIsLoaded ? "loaded" : "prelinked"));
2462 } else {
2463 if (!sameVersion) {
2464 /* This condition is significant so log it under warnings.
2465 */
2466 OSKextLog(this,
2467 kOSKextLogWarningLevel |
2468 kOSKextLogKextBookkeepingFlag,
2469 "Refusing new kext %s, v%s: already have %s v%s.",
2470 getIdentifierCString(),
2471 newVersionCString,
2472 (existingIsLoaded ? "loaded" : "prelinked"),
2473 existingVersionCString);
2474 } else {
2475 /* This condition is significant so log it under warnings.
2476 */
2477 OSKextLog(this,
2478 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2479 "Refusing new kext %s, v%s: a %s copy with a different "
2480 "executable UUID is already present.",
2481 getIdentifierCString(), newVersionCString,
2482 (existingIsLoaded ? "loaded" : "prelinked"));
2483 }
2484 }
2485 goto finish;
2486 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2487
2488 /* Refuse to allow an existing loaded codeless kext be replaced by a
2489 * normal kext with the same bundle ID.
2490 */
2491 if (existingIsCodeless && declaresExecutable()) {
2492 OSKextLog(this,
2493 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2494 "Refusing new kext %s, v%s: a codeless copy is already %s",
2495 getIdentifierCString(), newVersionCString,
2496 (existingIsLoaded ? "loaded" : "prelinked"));
2497 goto finish;
2498 }
2499
2500 /* Dexts packaged in the BootKC will be protected against replacement
2501 * by non-dexts by the logic above which checks if they are prelinked.
2502 * Dexts which are prelinked into the System KC will be registered
2503 * before any other kexts in the AuxKC are registered, and we never
2504 * put dexts in the AuxKC. Therefore, there is no need to check if an
2505 * existing object is a dext and is being replaced by a non-dext.
2506 * The scenario cannot happen by construction.
2507 *
2508 * See: OSKext::loadFileSetKexts()
2509 */
2510
2511 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2512 * user loads are happening or if we're still in early boot. User agents are
2513 * supposed to resolve dependencies topside and include only the exact
2514 * kexts needed; so we always accept the new kext (in fact we should never
2515 * see an older unloaded copy hanging around).
2516 */
2517 if (sUserLoadsActive) {
2518 sKextsByID->setObject(bundleID.get(), this);
2519 result = true;
2520
2521 OSKextLog(this,
2522 kOSKextLogStepLevel |
2523 kOSKextLogKextBookkeepingFlag,
2524 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2525 getIdentifierCString(),
2526 existingVersionCString,
2527 newVersionCString);
2528
2529 goto finish;
2530 }
2531
2532 /* During early boot, the kext with the highest version always wins out.
2533 * Prelinked kernels will never hit this, but mkexts and booter-read
2534 * kexts might have duplicates.
2535 */
2536 if (newVersion > existingVersion) {
2537 sKextsByID->setObject(bundleID.get(), this);
2538 result = true;
2539
2540 OSKextLog(this,
2541 kOSKextLogStepLevel |
2542 kOSKextLogKextBookkeepingFlag,
2543 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2544 existingVersionCString,
2545 getIdentifierCString(),
2546 newVersionCString);
2547 } else {
2548 OSKextLog(this,
2549 kOSKextLogStepLevel |
2550 kOSKextLogKextBookkeepingFlag,
2551 "Kext %s is already registered with a higher/same version (v%s); "
2552 "dropping newly-added (v%s).",
2553 getIdentifierCString(),
2554 existingVersionCString,
2555 newVersionCString);
2556 }
2557
2558 /* result has been set appropriately by now. */
2559
2560 finish:
2561
2562 IORecursiveLockUnlock(sKextLock);
2563
2564 if (result) {
2565 OSKextLog(this,
2566 kOSKextLogStepLevel |
2567 kOSKextLogKextBookkeepingFlag,
2568 "Kext %s, v%s registered and available for loading.",
2569 getIdentifierCString(), newVersionCString);
2570 }
2571
2572 return result;
2573 }
2574
2575 /*********************************************************************
2576 * Does the bare minimum validation to look up a kext.
2577 * All other validation is done on the spot as needed.
2578 **********************************************************************/
2579 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)2580 OSKext::setInfoDictionaryAndPath(
2581 OSDictionary * aDictionary,
2582 OSString * aPath)
2583 {
2584 bool result = false;
2585 OSString * bundleIDString = NULL; // do not release
2586 OSString * versionString = NULL; // do not release
2587 OSString * compatibleVersionString = NULL; // do not release
2588 const char * versionCString = NULL; // do not free
2589 const char * compatibleVersionCString = NULL; // do not free
2590 OSBoolean * scratchBool = NULL; // do not release
2591 OSDictionary * scratchDict = NULL; // do not release
2592
2593 if (infoDict) {
2594 panic("Attempt to set info dictionary on a kext "
2595 "that already has one (%s).",
2596 getIdentifierCString());
2597 }
2598
2599 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2600 goto finish;
2601 }
2602
2603 infoDict.reset(aDictionary, OSRetain);
2604
2605 /* Check right away if the info dictionary has any log flags.
2606 */
2607 scratchBool = OSDynamicCast(OSBoolean,
2608 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2609 if (scratchBool == kOSBooleanTrue) {
2610 flags.loggingEnabled = 1;
2611 }
2612
2613 /* The very next thing to get is the bundle identifier. Unlike
2614 * in user space, a kext with no bundle identifier gets axed
2615 * immediately.
2616 */
2617 bundleIDString = OSDynamicCast(OSString,
2618 getPropertyForHostArch(kCFBundleIdentifierKey));
2619 if (!bundleIDString) {
2620 OSKextLog(this,
2621 kOSKextLogErrorLevel |
2622 kOSKextLogValidationFlag,
2623 "CFBundleIdentifier missing/invalid type in kext %s.",
2624 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2625 goto finish;
2626 }
2627 bundleID = OSSymbol::withString(bundleIDString);
2628 if (!bundleID) {
2629 OSKextLog(this,
2630 kOSKextLogErrorLevel |
2631 kOSKextLogValidationFlag,
2632 "Can't copy bundle identifier as symbol for kext %s.",
2633 bundleIDString->getCStringNoCopy());
2634 goto finish;
2635 }
2636
2637 /* Save the path if we got one (it should always be available but it's
2638 * just something nice to have for bookkeeping).
2639 */
2640 if (aPath) {
2641 path.reset(aPath, OSRetain);
2642 }
2643
2644 /*****
2645 * Minimal validation to initialize. We'll do other validation on the spot.
2646 */
2647 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2648 OSKextLog(this,
2649 kOSKextLogErrorLevel |
2650 kOSKextLogValidationFlag,
2651 "Kext %s error - CFBundleIdentifier over max length %d.",
2652 getIdentifierCString(), KMOD_MAX_NAME - 1);
2653 goto finish;
2654 }
2655
2656 version = compatibleVersion = -1;
2657
2658 versionString = OSDynamicCast(OSString,
2659 getPropertyForHostArch(kCFBundleVersionKey));
2660 if (!versionString) {
2661 OSKextLog(this,
2662 kOSKextLogErrorLevel |
2663 kOSKextLogValidationFlag,
2664 "Kext %s error - CFBundleVersion missing/invalid type.",
2665 getIdentifierCString());
2666 goto finish;
2667 }
2668 versionCString = versionString->getCStringNoCopy();
2669 version = OSKextParseVersionString(versionCString);
2670 if (version < 0) {
2671 OSKextLog(this,
2672 kOSKextLogErrorLevel |
2673 kOSKextLogValidationFlag,
2674 "Kext %s error - CFBundleVersion bad value '%s'.",
2675 getIdentifierCString(), versionCString);
2676 goto finish;
2677 }
2678
2679 compatibleVersion = -1; // set to illegal value for kexts that don't have
2680
2681 compatibleVersionString = OSDynamicCast(OSString,
2682 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2683 if (compatibleVersionString) {
2684 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2685 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2686 if (compatibleVersion < 0) {
2687 OSKextLog(this,
2688 kOSKextLogErrorLevel |
2689 kOSKextLogValidationFlag,
2690 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2691 getIdentifierCString(), compatibleVersionCString);
2692 goto finish;
2693 }
2694
2695 if (compatibleVersion > version) {
2696 OSKextLog(this,
2697 kOSKextLogErrorLevel |
2698 kOSKextLogValidationFlag,
2699 "Kext %s error - %s %s > %s %s (must be <=).",
2700 getIdentifierCString(),
2701 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2702 kCFBundleVersionKey, versionCString);
2703 goto finish;
2704 }
2705 }
2706
2707 /* Check to see if this kext is in exclude list */
2708 if (isInExcludeList()) {
2709 OSKextLog(this,
2710 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2711 "Kext %s is in exclude list, not loadable",
2712 getIdentifierCString());
2713 goto finish;
2714 }
2715
2716 /* Set flags for later use if the infoDict gets flushed. We only
2717 * check for true values, not false ones(!)
2718 */
2719 scratchBool = OSDynamicCast(OSBoolean,
2720 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2721 if (scratchBool == kOSBooleanTrue) {
2722 flags.interface = 1;
2723 }
2724
2725 scratchBool = OSDynamicCast(OSBoolean,
2726 getPropertyForHostArch(kOSKernelResourceKey));
2727 if (scratchBool == kOSBooleanTrue) {
2728 flags.kernelComponent = 1;
2729 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2730 flags.started = 1;
2731
2732 /* A kernel component has one implicit dependency on the kernel.
2733 */
2734 flags.hasAllDependencies = 1;
2735 }
2736
2737 /* Make sure common string values in personalities are uniqued to OSSymbols.
2738 */
2739 scratchDict = OSDynamicCast(OSDictionary,
2740 getPropertyForHostArch(kIOKitPersonalitiesKey));
2741 if (scratchDict) {
2742 uniquePersonalityProperties(scratchDict);
2743 }
2744
2745 result = true;
2746
2747 finish:
2748
2749 return result;
2750 }
2751
2752 /*********************************************************************
2753 * Not used for prelinked kernel boot as there is no unrelocated
2754 * executable.
2755 *********************************************************************/
2756 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)2757 OSKext::setExecutable(
2758 OSData * anExecutable,
2759 OSData * externalData,
2760 bool externalDataIsMkext)
2761 {
2762 bool result = false;
2763 const char * executableKey = NULL; // do not free
2764
2765 if (!anExecutable) {
2766 infoDict->removeObject(_kOSKextExecutableKey);
2767 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2768 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2769 result = true;
2770 goto finish;
2771 }
2772
2773 if (infoDict->getObject(_kOSKextExecutableKey) ||
2774 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2775 panic("Attempt to set an executable on a kext "
2776 "that already has one (%s).",
2777 getIdentifierCString());
2778 goto finish;
2779 }
2780
2781 if (externalDataIsMkext) {
2782 executableKey = _kOSKextMkextExecutableReferenceKey;
2783 } else {
2784 executableKey = _kOSKextExecutableKey;
2785 }
2786
2787 if (anExecutable) {
2788 infoDict->setObject(executableKey, anExecutable);
2789 if (externalData) {
2790 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2791 }
2792 }
2793
2794 result = true;
2795
2796 finish:
2797 return result;
2798 }
2799
2800 /*********************************************************************
2801 *********************************************************************/
2802 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)2803 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2804 {
2805 OSObject * value = NULL; // do not release
2806 OSString * stringValue = NULL; // do not release
2807 OSSharedPtr<const OSSymbol> symbolValue;
2808
2809 value = dict->getObject(key);
2810 if (!value) {
2811 goto finish;
2812 }
2813 if (OSDynamicCast(OSSymbol, value)) {
2814 /* this is already an OSSymbol: we're good */
2815 goto finish;
2816 }
2817
2818 stringValue = OSDynamicCast(OSString, value);
2819 if (!stringValue) {
2820 goto finish;
2821 }
2822
2823 symbolValue = OSSymbol::withString(stringValue);
2824 if (!symbolValue) {
2825 goto finish;
2826 }
2827
2828 dict->setObject(key, symbolValue.get());
2829
2830 finish:
2831 return;
2832 }
2833
2834 /*********************************************************************
2835 *********************************************************************/
2836 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)2837 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2838 {
2839 OSObject * value = NULL; // do not release
2840 OSString * stringValue = NULL; // do not release
2841 OSSharedPtr<const OSSymbol> symbolValue;
2842
2843 value = dict->getObject(key);
2844 if (!value) {
2845 goto finish;
2846 }
2847 if (OSDynamicCast(OSSymbol, value)) {
2848 /* this is already an OSSymbol: we're good */
2849 goto finish;
2850 }
2851
2852 stringValue = OSDynamicCast(OSString, value);
2853 if (!stringValue) {
2854 goto finish;
2855 }
2856
2857 symbolValue = OSSymbol::withString(stringValue);
2858 if (!symbolValue) {
2859 goto finish;
2860 }
2861
2862 dict->setObject(key, symbolValue.get());
2863
2864 finish:
2865 return;
2866 }
2867
2868 void
uniquePersonalityProperties(OSDictionary * personalityDict)2869 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2870 {
2871 OSKext::uniquePersonalityProperties(personalityDict, true);
2872 }
2873
2874 /*********************************************************************
2875 * Replace common personality property values with uniqued instances
2876 * to save on wired memory.
2877 *********************************************************************/
2878 /* static */
2879 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)2880 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
2881 {
2882 /* Properties every personality has.
2883 */
2884 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2885 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2886 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
2887 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
2888 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
2889 } else if (defaultAddKernelBundleIdentifier) {
2890 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
2891 }
2892
2893 /* Other commonly used properties.
2894 */
2895 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2896 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2897 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2898
2899 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2900 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2901 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2902 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2903 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2904 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2905 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2906 uniqueStringPlistProperty(personalityDict, "Vendor");
2907 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2908 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2909 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2910 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2911 uniqueStringPlistProperty(personalityDict, "idProduct");
2912
2913 return;
2914 }
2915
2916 /*********************************************************************
2917 *********************************************************************/
2918 void
free(void)2919 OSKext::free(void)
2920 {
2921 if (isLoaded()) {
2922 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2923 }
2924
2925 infoDict.reset();
2926 bundleID.reset();
2927 path.reset();
2928 executableRelPath.reset();
2929 userExecutableRelPath.reset();
2930 dependencies.reset();
2931 linkedExecutable.reset();
2932 metaClasses.reset();
2933 interfaceUUID.reset();
2934 driverKitUUID.reset();
2935
2936 if (isInterface() && kmod_info) {
2937 kfree_type(kmod_info_t, kmod_info);
2938 }
2939
2940 super::free();
2941 return;
2942 }
2943
2944 #if PRAGMA_MARK
2945 #pragma mark Mkext files
2946 #endif
2947
2948 #if CONFIG_KXLD
2949 /*
2950 * mkext archives are really only relevant on kxld-enabled kernels.
2951 * Without a dynamic kernel linker, we don't need to support any mkexts.
2952 */
2953
2954 /*********************************************************************
2955 *********************************************************************/
2956 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)2957 OSKext::readMkextArchive(OSData * mkextData,
2958 uint32_t * checksumPtr)
2959 {
2960 OSReturn result = kOSKextReturnBadData;
2961 uint32_t mkextLength = 0;
2962 mkext_header * mkextHeader = NULL; // do not free
2963 uint32_t mkextVersion = 0;
2964
2965 /* Note default return of kOSKextReturnBadData above.
2966 */
2967 mkextLength = mkextData->getLength();
2968 if (mkextLength < sizeof(mkext_basic_header)) {
2969 OSKextLog(/* kext */ NULL,
2970 kOSKextLogErrorLevel |
2971 kOSKextLogArchiveFlag,
2972 "Mkext archive too small to be valid.");
2973 goto finish;
2974 }
2975
2976 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2977
2978 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2979 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2980 OSKextLog(/* kext */ NULL,
2981 kOSKextLogErrorLevel |
2982 kOSKextLogArchiveFlag,
2983 "Mkext archive has invalid magic or signature.");
2984 goto finish;
2985 }
2986
2987 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2988 OSKextLog(/* kext */ NULL,
2989 kOSKextLogErrorLevel |
2990 kOSKextLogArchiveFlag,
2991 "Mkext archive recorded length doesn't match actual file length.");
2992 goto finish;
2993 }
2994
2995 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2996
2997 if (mkextVersion == MKEXT_VERS_2) {
2998 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2999 } else {
3000 OSKextLog(/* kext */ NULL,
3001 kOSKextLogErrorLevel |
3002 kOSKextLogArchiveFlag,
3003 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3004 result = kOSKextReturnUnsupported;
3005 }
3006
3007 finish:
3008 return result;
3009 }
3010
3011 /*********************************************************************
3012 * Assumes magic, signature, version, length have been checked.
3013 * xxx - need to add further bounds checking for each file entry
3014 *
3015 * Should keep track of all kexts created so far, and if we hit a
3016 * fatal error halfway through, remove those kexts. If we've dropped
3017 * an older version that had already been read, whoops! Might want to
3018 * add a level of buffering?
3019 *********************************************************************/
3020 /* static */
3021 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3022 OSKext::readMkext2Archive(
3023 OSData * mkextData,
3024 OSDictionary ** mkextPlistOut,
3025 uint32_t * checksumPtr)
3026 {
3027 OSReturn result = kOSReturnError;
3028 uint32_t mkextLength;
3029 mkext2_header * mkextHeader = NULL; // do not free
3030 void * mkextEnd = NULL; // do not free
3031 uint32_t mkextVersion;
3032 uint8_t * crc_address = NULL;
3033 size_t crc_buffer_size = 0;
3034 uint32_t checksum;
3035 uint32_t mkextPlistOffset;
3036 uint32_t mkextPlistCompressedSize;
3037 char * mkextPlistEnd = NULL; // do not free
3038 uint32_t mkextPlistFullSize;
3039 OSSharedPtr<OSString> errorString;
3040 OSSharedPtr<OSData> mkextPlistUncompressedData;
3041 const char * mkextPlistDataBuffer = NULL; // do not free
3042 OSSharedPtr<OSObject> parsedXML;
3043 OSDictionary * mkextPlist = NULL; // do not release
3044 OSArray * mkextInfoDictArray = NULL; // do not release
3045 uint32_t count, i;
3046 kc_format_t kc_format;
3047
3048 if (!PE_get_primary_kc_format(&kc_format)) {
3049 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3050 "Unable to determine primary KC format");
3051 goto finish;
3052 }
3053
3054 mkextLength = mkextData->getLength();
3055 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3056 mkextEnd = (char *)mkextHeader + mkextLength;
3057 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3058
3059 crc_address = (u_int8_t *)&mkextHeader->version;
3060 crc_buffer_size = (uintptr_t)mkextHeader +
3061 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3062 if (crc_buffer_size > INT32_MAX) {
3063 OSKextLog(/* kext */ NULL,
3064 kOSKextLogErrorLevel |
3065 kOSKextLogArchiveFlag,
3066 "Mkext archive size is too large (%lu > INT32_MAX).",
3067 crc_buffer_size);
3068 result = kOSKextReturnBadData;
3069 goto finish;
3070 }
3071 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3072
3073 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3074 OSKextLog(/* kext */ NULL,
3075 kOSKextLogErrorLevel |
3076 kOSKextLogArchiveFlag,
3077 "Mkext archive has bad checksum.");
3078 result = kOSKextReturnBadData;
3079 goto finish;
3080 }
3081
3082 if (checksumPtr) {
3083 *checksumPtr = checksum;
3084 }
3085
3086 /* Check that the CPU type & subtype match that of the running kernel. */
3087 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3088 OSKextLog(/* kext */ NULL,
3089 kOSKextLogErrorLevel |
3090 kOSKextLogArchiveFlag,
3091 "Mkext archive must have a specific CPU type.");
3092 result = kOSKextReturnBadData;
3093 goto finish;
3094 } else {
3095 if ((UInt32)_mh_execute_header.cputype !=
3096 MKEXT_GET_CPUTYPE(mkextHeader)) {
3097 OSKextLog(/* kext */ NULL,
3098 kOSKextLogErrorLevel |
3099 kOSKextLogArchiveFlag,
3100 "Mkext archive does not match the running kernel's CPU type.");
3101 result = kOSKextReturnArchNotFound;
3102 goto finish;
3103 }
3104 }
3105
3106 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3107 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3108 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3109 mkextPlistCompressedSize;
3110 if (mkextPlistEnd > mkextEnd) {
3111 OSKextLog(/* kext */ NULL,
3112 kOSKextLogErrorLevel |
3113 kOSKextLogArchiveFlag,
3114 "Mkext archive file overrun.");
3115 result = kOSKextReturnBadData;
3116 }
3117
3118 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3119 if (mkextPlistCompressedSize) {
3120 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3121 (UInt8 *)mkextHeader + mkextPlistOffset,
3122 "plist",
3123 mkextPlistCompressedSize, mkextPlistFullSize);
3124 if (!mkextPlistUncompressedData) {
3125 goto finish;
3126 }
3127 mkextPlistDataBuffer = (const char *)
3128 mkextPlistUncompressedData->getBytesNoCopy();
3129 } else {
3130 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3131 }
3132
3133 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3134 */
3135 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3136 if (parsedXML) {
3137 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3138 }
3139 if (!mkextPlist) {
3140 const char * errorCString = "(unknown error)";
3141
3142 if (errorString && errorString->getCStringNoCopy()) {
3143 errorCString = errorString->getCStringNoCopy();
3144 } else if (parsedXML) {
3145 errorCString = "not a dictionary";
3146 }
3147 OSKextLog(/* kext */ NULL,
3148 kOSKextLogErrorLevel |
3149 kOSKextLogArchiveFlag,
3150 "Error unserializing mkext plist: %s.", errorCString);
3151 goto finish;
3152 }
3153
3154 mkextInfoDictArray = OSDynamicCast(OSArray,
3155 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3156 if (!mkextInfoDictArray) {
3157 OSKextLog(/* kext */ NULL,
3158 kOSKextLogErrorLevel |
3159 kOSKextLogArchiveFlag,
3160 "Mkext archive contains no kext info dictionaries.");
3161 goto finish;
3162 }
3163
3164 count = mkextInfoDictArray->getCount();
3165 for (i = 0; i < count; i++) {
3166 OSDictionary * infoDict;
3167
3168
3169 infoDict = OSDynamicCast(OSDictionary,
3170 mkextInfoDictArray->getObject(i));
3171
3172 /* Create the kext for the entry, then release it, because the
3173 * kext system keeps them around until explicitly removed.
3174 * Any creation/registration failures are already logged for us.
3175 */
3176 if (infoDict) {
3177 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3178
3179 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3180 if (kc_format == KCFormatFileset &&
3181 newKext &&
3182 !(newKext->isPrelinked()) &&
3183 newKext->declaresExecutable()) {
3184 result = kOSReturnError;
3185 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3186 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3187
3188 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3189 "Dynamic loading of kext denied for kext %s\n",
3190 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3191 goto finish;
3192 }
3193 }
3194 }
3195
3196 /* If the caller needs the plist, hand them back our copy
3197 */
3198 if (mkextPlistOut) {
3199 *mkextPlistOut = mkextPlist;
3200 parsedXML.detach();
3201 }
3202
3203 /* Even if we didn't keep any kexts from the mkext, we may have a load
3204 * request to process, so we are successful (no errors occurred).
3205 */
3206 result = kOSReturnSuccess;
3207
3208 finish:
3209 return result;
3210 }
3211
3212 /* static */
3213 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3214 OSKext::readMkext2Archive(
3215 OSData * mkextData,
3216 OSSharedPtr<OSDictionary> &mkextPlistOut,
3217 uint32_t * checksumPtr)
3218 {
3219 OSDictionary * mkextPlist = NULL;
3220 OSReturn ret;
3221
3222 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3223 &mkextPlist,
3224 checksumPtr))) {
3225 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3226 }
3227 return ret;
3228 }
3229
3230 /*********************************************************************
3231 *********************************************************************/
3232 /* static */
3233 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3234 OSKext::withMkext2Info(
3235 OSDictionary * anInfoDict,
3236 OSData * mkextData)
3237 {
3238 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3239
3240 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3241 return NULL;
3242 }
3243
3244 return newKext;
3245 }
3246
3247 /*********************************************************************
3248 *********************************************************************/
3249 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3250 OSKext::initWithMkext2Info(
3251 OSDictionary * anInfoDict,
3252 OSData * mkextData)
3253 {
3254 bool result = false;
3255 OSString * kextPath = NULL; // do not release
3256 OSNumber * executableOffsetNum = NULL; // do not release
3257 OSSharedPtr<OSData> executable;
3258
3259 if (anInfoDict == NULL || !super::init()) {
3260 goto finish;
3261 }
3262
3263 /* Get the path. Don't look for an arch-specific path property.
3264 */
3265 kextPath = OSDynamicCast(OSString,
3266 anInfoDict->getObject(kMKEXTBundlePathKey));
3267
3268 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3269 goto finish;
3270 }
3271
3272 /* If we have a path to the executable, save it.
3273 */
3274 executableRelPath.reset(OSDynamicCast(OSString,
3275 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3276
3277 /* Don't need the paths to be in the info dictionary any more.
3278 */
3279 anInfoDict->removeObject(kMKEXTBundlePathKey);
3280 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3281
3282 executableOffsetNum = OSDynamicCast(OSNumber,
3283 infoDict->getObject(kMKEXTExecutableKey));
3284 if (executableOffsetNum) {
3285 executable = createMkext2FileEntry(mkextData,
3286 executableOffsetNum, "executable");
3287 infoDict->removeObject(kMKEXTExecutableKey);
3288 if (!executable) {
3289 goto finish;
3290 }
3291 if (!setExecutable(executable.get(), mkextData, true)) {
3292 goto finish;
3293 }
3294 }
3295
3296 result = registerIdentifier();
3297
3298 finish:
3299 return result;
3300 }
3301
3302 /*********************************************************************
3303 *********************************************************************/
3304 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3305 OSKext::createMkext2FileEntry(
3306 OSData * mkextData,
3307 OSNumber * offsetNum,
3308 const char * name)
3309 {
3310 OSSharedPtr<OSData> result;
3311 MkextEntryRef entryRef;
3312 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3313 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3314
3315 result = OSData::withCapacity(sizeof(entryRef));
3316 if (!result) {
3317 goto finish;
3318 }
3319
3320 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3321 entryRef.fileinfo = mkextBuffer + entryOffset;
3322 if (!result->appendValue(entryRef)) {
3323 result.reset();
3324 goto finish;
3325 }
3326
3327 finish:
3328 if (!result) {
3329 OSKextLog(this,
3330 kOSKextLogErrorLevel |
3331 kOSKextLogArchiveFlag,
3332 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3333 name, getIdentifierCString());
3334 }
3335 return result;
3336 }
3337
3338 /*********************************************************************
3339 *********************************************************************/
3340 extern "C" {
3341 static void * z_alloc(void *, u_int items, u_int size);
3342 static void z_free(void *, void *ptr);
3343
3344 typedef struct z_mem {
3345 uint32_t alloc_size;
3346 uint8_t data[0];
3347 } z_mem;
3348
3349 /*
3350 * Space allocation and freeing routines for use by zlib routines.
3351 */
3352 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3353 z_alloc(void * notused __unused, u_int num_items, u_int size)
3354 {
3355 void * result = NULL;
3356 z_mem * zmem = NULL;
3357
3358 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3359 //Check for overflow due to multiplication
3360 if (total > UINT32_MAX) {
3361 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3362 notused, num_items, size, num_items, size);
3363 }
3364
3365 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3366 //Check for overflow due to addition
3367 if (allocSize64 > UINT32_MAX) {
3368 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3369 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3370 }
3371 uint32_t allocSize = (uint32_t)allocSize64;
3372
3373 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3374 VM_KERN_MEMORY_OSKEXT);
3375 if (!zmem) {
3376 goto finish;
3377 }
3378 zmem->alloc_size = allocSize;
3379 result = (void *)&(zmem->data);
3380 finish:
3381 return result;
3382 }
3383
3384 void
z_free(void * notused __unused,void * ptr)3385 z_free(void * notused __unused, void * ptr)
3386 {
3387 uint32_t * skipper = (uint32_t *)ptr - 1;
3388 z_mem * zmem = (z_mem *)skipper;
3389 kfree_data(zmem, zmem->alloc_size);
3390 }
3391 };
3392
3393 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3394 OSKext::extractMkext2FileData(
3395 UInt8 * data,
3396 const char * name,
3397 uint32_t compressedSize,
3398 uint32_t fullSize)
3399 {
3400 OSSharedPtr<OSData> result;
3401 OSSharedPtr<OSData> uncompressedData; // release on error
3402
3403 uint8_t * uncompressedDataBuffer = NULL; // do not free
3404 unsigned long uncompressedSize;
3405 z_stream zstream;
3406 bool zstream_inited = false;
3407 int zlib_result;
3408
3409 /* If the file isn't compressed, we want to make a copy
3410 * so that we don't have the tie to the larger mkext file buffer any more.
3411 */
3412 if (!compressedSize) {
3413 uncompressedData = OSData::withBytes(data, fullSize);
3414 // xxx - no check for failure?
3415 result = uncompressedData;
3416 goto finish;
3417 }
3418
3419 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3420 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
3421 /* How's this for cheesy? The kernel is only asked to extract
3422 * kext plists so we tailor the log messages.
3423 */
3424 if (isKernel()) {
3425 OSKextLog(this,
3426 kOSKextLogErrorLevel |
3427 kOSKextLogArchiveFlag,
3428 "Allocation failure extracting %s from mkext.", name);
3429 } else {
3430 OSKextLog(this,
3431 kOSKextLogErrorLevel |
3432 kOSKextLogArchiveFlag,
3433 "Allocation failure extracting %s from mkext for kext %s.",
3434 name, getIdentifierCString());
3435 }
3436
3437 goto finish;
3438 }
3439 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3440 if (!uncompressedData) {
3441 if (isKernel()) {
3442 OSKextLog(this,
3443 kOSKextLogErrorLevel |
3444 kOSKextLogArchiveFlag,
3445 "Allocation failure extracting %s from mkext.", name);
3446 } else {
3447 OSKextLog(this,
3448 kOSKextLogErrorLevel |
3449 kOSKextLogArchiveFlag,
3450 "Allocation failure extracting %s from mkext for kext %s.",
3451 name, getIdentifierCString());
3452 }
3453 goto finish;
3454 }
3455 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3456
3457 if (isKernel()) {
3458 OSKextLog(this,
3459 kOSKextLogDetailLevel |
3460 kOSKextLogArchiveFlag,
3461 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3462 name, compressedSize, fullSize);
3463 } else {
3464 OSKextLog(this,
3465 kOSKextLogDetailLevel |
3466 kOSKextLogArchiveFlag,
3467 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3468 getIdentifierCString(), name, compressedSize, fullSize);
3469 }
3470
3471 bzero(&zstream, sizeof(zstream));
3472 zstream.next_in = (UInt8 *)data;
3473 zstream.avail_in = compressedSize;
3474
3475 zstream.next_out = uncompressedDataBuffer;
3476 zstream.avail_out = fullSize;
3477
3478 zstream.zalloc = z_alloc;
3479 zstream.zfree = z_free;
3480
3481 zlib_result = inflateInit(&zstream);
3482 if (Z_OK != zlib_result) {
3483 if (isKernel()) {
3484 OSKextLog(this,
3485 kOSKextLogErrorLevel |
3486 kOSKextLogArchiveFlag,
3487 "Mkext error; zlib inflateInit failed (%d) for %s.",
3488 zlib_result, name);
3489 } else {
3490 OSKextLog(this,
3491 kOSKextLogErrorLevel |
3492 kOSKextLogArchiveFlag,
3493 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3494 getIdentifierCString(), zlib_result, name);
3495 }
3496 goto finish;
3497 } else {
3498 zstream_inited = true;
3499 }
3500
3501 zlib_result = inflate(&zstream, Z_FINISH);
3502
3503 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3504 uncompressedSize = zstream.total_out;
3505 } else {
3506 if (isKernel()) {
3507 OSKextLog(this,
3508 kOSKextLogErrorLevel |
3509 kOSKextLogArchiveFlag,
3510 "Mkext error; zlib inflate failed (%d) for %s.",
3511 zlib_result, name);
3512 } else {
3513 OSKextLog(this,
3514 kOSKextLogErrorLevel |
3515 kOSKextLogArchiveFlag,
3516 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3517 getIdentifierCString(), zlib_result, name);
3518 }
3519 if (zstream.msg) {
3520 OSKextLog(this,
3521 kOSKextLogErrorLevel |
3522 kOSKextLogArchiveFlag,
3523 "zlib error: %s.", zstream.msg);
3524 }
3525 goto finish;
3526 }
3527
3528 if (uncompressedSize != fullSize) {
3529 if (isKernel()) {
3530 OSKextLog(this,
3531 kOSKextLogErrorLevel |
3532 kOSKextLogArchiveFlag,
3533 "Mkext error; zlib inflate discrepancy for %s, "
3534 "uncompressed size != original size.", name);
3535 } else {
3536 OSKextLog(this,
3537 kOSKextLogErrorLevel |
3538 kOSKextLogArchiveFlag,
3539 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3540 "uncompressed size != original size.",
3541 getIdentifierCString(), name);
3542 }
3543 goto finish;
3544 }
3545
3546 result = os::move(uncompressedData);
3547
3548 finish:
3549 /* Don't bother checking return, nothing we can do on fail.
3550 */
3551 if (zstream_inited) {
3552 inflateEnd(&zstream);
3553 }
3554
3555 return result;
3556 }
3557
3558 /*********************************************************************
3559 *********************************************************************/
3560 /* static */
3561 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3562 OSKext::loadFromMkext(
3563 OSKextLogSpec clientLogFilter,
3564 char * mkextBuffer,
3565 uint32_t mkextBufferLength,
3566 char ** logInfoOut,
3567 uint32_t * logInfoLengthOut)
3568 {
3569 OSReturn result = kOSReturnError;
3570 OSReturn tempResult = kOSReturnError;
3571
3572 OSSharedPtr<OSData> mkextData;
3573 OSSharedPtr<OSDictionary> mkextPlist;
3574
3575 OSSharedPtr<OSArray> logInfoArray;
3576 OSSharedPtr<OSSerialize> serializer;
3577
3578 OSString * predicate = NULL; // do not release
3579 OSDictionary * requestArgs = NULL; // do not release
3580
3581 OSString * kextIdentifier = NULL; // do not release
3582 OSNumber * startKextExcludeNum = NULL; // do not release
3583 OSNumber * startMatchingExcludeNum = NULL; // do not release
3584 OSBoolean * delayAutounloadBool = NULL; // do not release
3585 OSArray * personalityNames = NULL; // do not release
3586
3587 /* Default values for these two options: regular autounload behavior,
3588 * load all kexts, send no personalities.
3589 */
3590 Boolean delayAutounload = false;
3591 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3592 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3593
3594 IORecursiveLockLock(sKextLock);
3595
3596 if (logInfoOut) {
3597 *logInfoOut = NULL;
3598 *logInfoLengthOut = 0;
3599 }
3600
3601 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3602
3603 OSKextLog(/* kext */ NULL,
3604 kOSKextLogDebugLevel |
3605 kOSKextLogIPCFlag,
3606 "Received kext load request from user space.");
3607
3608 /* Regardless of processing, the fact that we have gotten here means some
3609 * user-space program is up and talking to us, so we'll switch our kext
3610 * registration to reflect that.
3611 */
3612 if (!sUserLoadsActive) {
3613 OSKextLog(/* kext */ NULL,
3614 kOSKextLogProgressLevel |
3615 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3616 "Switching to late startup (user-space) kext loading policy.");
3617
3618 sUserLoadsActive = true;
3619 }
3620
3621 if (!sLoadEnabled) {
3622 OSKextLog(/* kext */ NULL,
3623 kOSKextLogErrorLevel |
3624 kOSKextLogLoadFlag,
3625 "Kext loading is disabled.");
3626 result = kOSKextReturnDisabled;
3627 goto finish;
3628 }
3629
3630 /* Note that we do not set a dealloc function on this OSData
3631 * object! No references to it can remain after the loadFromMkext()
3632 * call since we are in a MIG function, and will vm_deallocate()
3633 * the buffer.
3634 */
3635 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3636 mkextBufferLength);
3637 if (!mkextData) {
3638 OSKextLog(/* kext */ NULL,
3639 kOSKextLogErrorLevel |
3640 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3641 "Failed to create wrapper for kext load request.");
3642 result = kOSKextReturnNoMemory;
3643 goto finish;
3644 }
3645
3646 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3647 if (result != kOSReturnSuccess) {
3648 OSKextLog(/* kext */ NULL,
3649 kOSKextLogErrorLevel |
3650 kOSKextLogLoadFlag,
3651 "Failed to read kext load request.");
3652 goto finish;
3653 }
3654
3655 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3656 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3657 OSKextLog(/* kext */ NULL,
3658 kOSKextLogErrorLevel |
3659 kOSKextLogLoadFlag,
3660 "Received kext load request with no predicate; skipping.");
3661 result = kOSKextReturnInvalidArgument;
3662 goto finish;
3663 }
3664
3665 requestArgs = OSDynamicCast(OSDictionary,
3666 mkextPlist->getObject(kKextRequestArgumentsKey));
3667 if (!requestArgs || !requestArgs->getCount()) {
3668 OSKextLog(/* kext */ NULL,
3669 kOSKextLogErrorLevel |
3670 kOSKextLogLoadFlag,
3671 "Received kext load request with no arguments.");
3672 result = kOSKextReturnInvalidArgument;
3673 goto finish;
3674 }
3675
3676 kextIdentifier = OSDynamicCast(OSString,
3677 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3678
3679 if (!kextIdentifier) {
3680 OSKextLog(/* kext */ NULL,
3681 kOSKextLogErrorLevel |
3682 kOSKextLogLoadFlag,
3683 "Received kext load request with no kext identifier.");
3684 result = kOSKextReturnInvalidArgument;
3685 goto finish;
3686 }
3687
3688 startKextExcludeNum = OSDynamicCast(OSNumber,
3689 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3690 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3691 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3692 delayAutounloadBool = OSDynamicCast(OSBoolean,
3693 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3694 personalityNames = OSDynamicCast(OSArray,
3695 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3696
3697 if (delayAutounloadBool) {
3698 delayAutounload = delayAutounloadBool->getValue();
3699 }
3700 if (startKextExcludeNum) {
3701 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3702 }
3703 if (startMatchingExcludeNum) {
3704 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3705 }
3706
3707 OSKextLog(/* kext */ NULL,
3708 kOSKextLogProgressLevel |
3709 kOSKextLogIPCFlag,
3710 "Received request from user space to load kext %s.",
3711 kextIdentifier->getCStringNoCopy());
3712
3713 /* Load the kext, with no deferral, since this is a load from outside
3714 * the kernel.
3715 * xxx - Would like a better way to handle the default values for the
3716 * xxx - start/match opt args.
3717 */
3718 result = OSKext::loadKextWithIdentifier(
3719 kextIdentifier,
3720 /* kextRef */ NULL,
3721 /* allowDefer */ false,
3722 delayAutounload,
3723 startKextExcludeLevel,
3724 startMatchingExcludeLevel,
3725 personalityNames);
3726 if (result != kOSReturnSuccess) {
3727 goto finish;
3728 }
3729 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3730 * for matching via a separate IOKit calldown.
3731 */
3732
3733 finish:
3734
3735 /* Gather up the collected log messages for user space. Any
3736 * error messages past this call will not make it up as log messages
3737 * but will be in the system log.
3738 */
3739 logInfoArray = OSKext::clearUserSpaceLogFilter();
3740
3741 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3742 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3743 logInfoOut, logInfoLengthOut);
3744 if (tempResult != kOSReturnSuccess) {
3745 result = tempResult;
3746 }
3747 }
3748
3749 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3750
3751 IORecursiveLockUnlock(sKextLock);
3752
3753 /* Note: mkextDataObject will have been retained by every kext w/an
3754 * executable in it. That should all have been flushed out at the
3755 * and of the load operation, but you never know....
3756 */
3757 if (mkextData && mkextData->getRetainCount() > 1) {
3758 OSKextLog(/* kext */ NULL,
3759 kOSKextLogErrorLevel |
3760 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3761 "Kext load request buffer from user space still retained by a kext; "
3762 "probable memory leak.");
3763 }
3764
3765 return result;
3766 }
3767
3768 #endif // CONFIG_KXLD
3769
3770 /*********************************************************************
3771 *********************************************************************/
3772 /* static */
3773 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)3774 OSKext::serializeLogInfo(
3775 OSArray * logInfoArray,
3776 char ** logInfoOut,
3777 uint32_t * logInfoLengthOut)
3778 {
3779 OSReturn result = kOSReturnError;
3780 char * buffer = NULL;
3781 kern_return_t kmem_result = KERN_FAILURE;
3782 OSSharedPtr<OSSerialize> serializer;
3783 char * logInfo = NULL; // returned by reference
3784 uint32_t logInfoLength = 0;
3785
3786 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3787 OSKextLog(/* kext */ NULL,
3788 kOSKextLogErrorLevel |
3789 kOSKextLogIPCFlag,
3790 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3791 /* Bad programmer. */
3792 result = kOSKextReturnInvalidArgument;
3793 goto finish;
3794 }
3795
3796 serializer = OSSerialize::withCapacity(0);
3797 if (!serializer) {
3798 OSKextLog(/* kext */ NULL,
3799 kOSKextLogErrorLevel |
3800 kOSKextLogIPCFlag,
3801 "Failed to create serializer on log info for request from user space.");
3802 /* Incidental error; we're going to (try to) allow the request
3803 * itself to succeed. */
3804 }
3805
3806 if (!logInfoArray->serialize(serializer.get())) {
3807 OSKextLog(/* kext */ NULL,
3808 kOSKextLogErrorLevel |
3809 kOSKextLogIPCFlag,
3810 "Failed to serialize log info for request from user space.");
3811 /* Incidental error; we're going to (try to) allow the request
3812 * itself to succeed. */
3813 } else {
3814 logInfo = serializer->text();
3815 logInfoLength = serializer->getLength();
3816
3817 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3818 if (kmem_result != KERN_SUCCESS) {
3819 OSKextLog(/* kext */ NULL,
3820 kOSKextLogErrorLevel |
3821 kOSKextLogIPCFlag,
3822 "Failed to copy log info for request from user space.");
3823 /* Incidental error; we're going to (try to) allow the request
3824 * to succeed. */
3825 } else {
3826 /* 11981737 - clear uninitialized data in last page */
3827 bzero((void *)(buffer + logInfoLength),
3828 (round_page(logInfoLength) - logInfoLength));
3829 memcpy(buffer, logInfo, logInfoLength);
3830 *logInfoOut = buffer;
3831 *logInfoLengthOut = logInfoLength;
3832 }
3833 }
3834
3835 result = kOSReturnSuccess;
3836 finish:
3837 return result;
3838 }
3839
3840 #if PRAGMA_MARK
3841 #pragma mark Instance Management Methods
3842 #endif
3843 /*********************************************************************
3844 *********************************************************************/
3845 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)3846 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3847 {
3848 OSSharedPtr<OSKext> foundKext;
3849
3850 IORecursiveLockLock(sKextLock);
3851 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
3852 IORecursiveLockUnlock(sKextLock);
3853
3854 return foundKext;
3855 }
3856
3857 /*********************************************************************
3858 *********************************************************************/
3859 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)3860 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3861 {
3862 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3863 }
3864
3865 /*********************************************************************
3866 *********************************************************************/
3867 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)3868 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3869 {
3870 OSSharedPtr<OSKext> foundKext; // returned
3871 uint32_t i, j;
3872 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3873 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3874
3875 IORecursiveLockLock(sKextLock);
3876
3877 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3878 for (i = 0; i < count[j]; i++) {
3879 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3880 if (thisKext->getLoadTag() == aTag) {
3881 foundKext.reset(thisKext, OSRetain);
3882 goto finish;
3883 }
3884 }
3885 }
3886
3887 finish:
3888 IORecursiveLockUnlock(sKextLock);
3889
3890 return foundKext;
3891 }
3892
3893 /*********************************************************************
3894 *********************************************************************/
3895 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)3896 OSKext::lookupKextWithAddress(vm_address_t address)
3897 {
3898 OSSharedPtr<OSKext> foundKext; // returned
3899 uint32_t count, i;
3900 kmod_info_t *kmod_info;
3901 vm_address_t originalAddress;
3902 #if defined(__arm64__)
3903 uint64_t textExecBase;
3904 size_t textExecSize;
3905 #endif /* defined(__arm64__) */
3906
3907 originalAddress = address;
3908 #if __has_feature(ptrauth_calls)
3909 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3910 #endif /* __has_feature(ptrauth_calls) */
3911
3912 IORecursiveLockLock(sKextLock);
3913
3914 count = sLoadedKexts->getCount();
3915 for (i = 0; i < count; i++) {
3916 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3917 if (thisKext == sKernelKext) {
3918 continue;
3919 }
3920 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3921 kmod_info = thisKext->kmod_info;
3922 vm_address_t kext_start = kmod_info->address;
3923 vm_address_t kext_end = kext_start + kmod_info->size;
3924 if ((kext_start <= address) && (address < kext_end)) {
3925 foundKext.reset(thisKext, OSRetain);
3926 goto finish;
3927 }
3928 #if defined(__arm64__)
3929 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3930 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3931 foundKext.reset(thisKext, OSRetain);
3932 goto finish;
3933 }
3934 #endif /* defined (__arm64__) */
3935 }
3936 }
3937 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3938 foundKext.reset(sKernelKext, OSRetain);
3939 goto finish;
3940 }
3941 /*
3942 * DriverKit userspace executables do not have a kernel linkedExecutable,
3943 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3944 * here, so use the original address passed to this method.
3945 *
3946 * This is supposed to be used for logging reasons only. When logd
3947 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3948 * remove it here before checking it against the LoadTag.
3949 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3950 */
3951
3952 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
3953 count = sLoadedDriverKitKexts->getCount();
3954 for (i = 0; i < count; i++) {
3955 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
3956 if (thisKext->getLoadTag() == address) {
3957 foundKext.reset(thisKext, OSRetain);
3958 }
3959 }
3960
3961 finish:
3962 IORecursiveLockUnlock(sKextLock);
3963
3964 return foundKext;
3965 }
3966
3967 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)3968 OSKext::copyKextUUIDForAddress(OSNumber *address)
3969 {
3970 OSSharedPtr<OSData> uuid;
3971 OSSharedPtr<OSKext> kext;
3972
3973 if (!address) {
3974 return NULL;
3975 }
3976
3977 #if CONFIG_MACF
3978 /* Is the calling process allowed to query kext info? */
3979 if (current_task() != kernel_task) {
3980 int macCheckResult = 0;
3981 kauth_cred_t cred = NULL;
3982
3983 cred = kauth_cred_get_with_ref();
3984 macCheckResult = mac_kext_check_query(cred);
3985 kauth_cred_unref(&cred);
3986
3987 if (macCheckResult != 0) {
3988 OSKextLog(/* kext */ NULL,
3989 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3990 "Failed to query kext UUID (MAC policy error 0x%x).",
3991 macCheckResult);
3992 return NULL;
3993 }
3994 }
3995 #endif
3996
3997 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3998 if (slidAddress != 0) {
3999 kext = lookupKextWithAddress(slidAddress);
4000 if (kext) {
4001 uuid = kext->copyTextUUID();
4002 }
4003 }
4004
4005 if (!uuid) {
4006 /*
4007 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4008 * a kext. This might have happened because the log message came from a dext.
4009 *
4010 * Try again with the original address.
4011 */
4012 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4013 if (kext && kext->isDriverKit()) {
4014 uuid = kext->copyTextUUID();
4015 }
4016 }
4017
4018 return uuid;
4019 }
4020
4021 /*********************************************************************
4022 *********************************************************************/
4023 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4024 OSKext::lookupKextWithUUID(uuid_t wanted)
4025 {
4026 OSSharedPtr<OSKext> foundKext; // returned
4027 uint32_t j, i;
4028 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4029 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4030
4031
4032 IORecursiveLockLock(sKextLock);
4033
4034 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4035 for (i = 0; i < count[j]; i++) {
4036 OSKext * thisKext = NULL;
4037
4038 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4039 if (!thisKext) {
4040 continue;
4041 }
4042
4043 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4044 if (!uuid_data) {
4045 continue;
4046 }
4047
4048 uuid_t uuid;
4049 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4050
4051 if (0 == uuid_compare(wanted, uuid)) {
4052 foundKext.reset(thisKext, OSRetain);
4053 goto finish;
4054 }
4055 }
4056 }
4057 finish:
4058 IORecursiveLockUnlock(sKextLock);
4059
4060 return foundKext;
4061 }
4062
4063
4064
4065
4066 /*********************************************************************
4067 *********************************************************************/
4068 /* static */
4069 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4070 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4071 {
4072 bool result = false;
4073 OSKext * foundKext = NULL; // returned
4074
4075 IORecursiveLockLock(sKextLock);
4076
4077 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4078 if (foundKext && foundKext->isLoaded()) {
4079 result = true;
4080 }
4081
4082 IORecursiveLockUnlock(sKextLock);
4083
4084 return result;
4085 }
4086
4087 /*********************************************************************
4088 * xxx - should spawn a separate thread so a kext can safely have
4089 * xxx - itself unloaded.
4090 *********************************************************************/
4091 /* static */
4092 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4093 OSKext::removeKext(
4094 OSKext * aKext,
4095 #if CONFIG_EMBEDDED
4096 __unused
4097 #endif
4098 bool terminateServicesAndRemovePersonalitiesFlag)
4099 {
4100 #if CONFIG_EMBEDDED
4101 OSKextLog(aKext,
4102 kOSKextLogErrorLevel |
4103 kOSKextLogKextBookkeepingFlag,
4104 "removeKext() called for %s, not supported on embedded",
4105 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4106
4107 return kOSReturnSuccess;
4108 #else /* CONFIG_EMBEDDED */
4109
4110 OSReturn result = kOSKextReturnInUse;
4111 OSKext * checkKext = NULL; // do not release
4112 #if CONFIG_MACF
4113 int macCheckResult = 0;
4114 kauth_cred_t cred = NULL;
4115 #endif
4116
4117 IORecursiveLockLock(sKextLock);
4118
4119 /* If the kext has no identifier, it failed to init
4120 * so isn't in sKextsByID and it isn't loaded.
4121 */
4122 if (!aKext->getIdentifier()) {
4123 result = kOSReturnSuccess;
4124 goto finish;
4125 }
4126
4127 checkKext = OSDynamicCast(OSKext,
4128 sKextsByID->getObject(aKext->getIdentifier()));
4129 if (checkKext != aKext) {
4130 result = kOSKextReturnNotFound;
4131 goto finish;
4132 }
4133
4134 if (aKext->isLoaded()) {
4135 #if CONFIG_MACF
4136 if (current_task() != kernel_task) {
4137 cred = kauth_cred_get_with_ref();
4138 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4139 kauth_cred_unref(&cred);
4140 }
4141
4142 if (macCheckResult != 0) {
4143 result = kOSReturnError;
4144 OSKextLog(aKext,
4145 kOSKextLogErrorLevel |
4146 kOSKextLogKextBookkeepingFlag,
4147 "Failed to remove kext %s (MAC policy error 0x%x).",
4148 aKext->getIdentifierCString(), macCheckResult);
4149 goto finish;
4150 }
4151 #endif
4152
4153 /* make sure there are no resource requests in flight - 17187548 */
4154 if (aKext->countRequestCallbacks()) {
4155 goto finish;
4156 }
4157 if (aKext->flags.unloadUnsupported) {
4158 result = kOSKextReturnInUse;
4159 OSKextLog(aKext,
4160 kOSKextLogErrorLevel |
4161 kOSKextLogKextBookkeepingFlag,
4162 "Can't remove kext %s; unsupported by cache.",
4163 aKext->getIdentifierCString());
4164 goto finish;
4165 }
4166
4167 /* If we are terminating, send the request to the IOCatalogue
4168 * (which will actually call us right back but that's ok we have
4169 * a recursive lock don't you know) but do not ask the IOCatalogue
4170 * to call back with an unload, we'll do that right here.
4171 */
4172 if (terminateServicesAndRemovePersonalitiesFlag) {
4173 result = gIOCatalogue->terminateDriversForModule(
4174 aKext->getIdentifierCString(), /* unload */ false);
4175 if (result != kOSReturnSuccess) {
4176 OSKextLog(aKext,
4177 kOSKextLogErrorLevel |
4178 kOSKextLogKextBookkeepingFlag,
4179 "Can't remove kext %s; services failed to terminate - 0x%x.",
4180 aKext->getIdentifierCString(), result);
4181 goto finish;
4182 }
4183 }
4184
4185 result = aKext->unload();
4186 if (result != kOSReturnSuccess) {
4187 goto finish;
4188 }
4189 }
4190
4191 /* Remove personalities as requested. This is a bit redundant for a loaded
4192 * kext as IOCatalogue::terminateDriversForModule() removes driver
4193 * personalities, but it doesn't restart matching, which we always want
4194 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4195 * that happens.
4196 */
4197 if (terminateServicesAndRemovePersonalitiesFlag) {
4198 aKext->removePersonalitiesFromCatalog();
4199 }
4200
4201 if (aKext->isInFileset()) {
4202 OSKextLog(aKext,
4203 kOSKextLogProgressLevel |
4204 kOSKextLogKextBookkeepingFlag,
4205 "Fileset kext %s unloaded.",
4206 aKext->getIdentifierCString());
4207 } else {
4208 OSKextLog(aKext,
4209 kOSKextLogProgressLevel |
4210 kOSKextLogKextBookkeepingFlag,
4211 "Removing kext %s.",
4212 aKext->getIdentifierCString());
4213
4214 sKextsByID->removeObject(aKext->getIdentifier());
4215 }
4216 result = kOSReturnSuccess;
4217
4218 finish:
4219 IORecursiveLockUnlock(sKextLock);
4220 return result;
4221 #endif /* CONFIG_EMBEDDED */
4222 }
4223
4224 /*********************************************************************
4225 *********************************************************************/
4226 /* static */
4227 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4228 OSKext::removeKextWithIdentifier(
4229 const char * kextIdentifier,
4230 bool terminateServicesAndRemovePersonalitiesFlag)
4231 {
4232 OSReturn result = kOSReturnError;
4233
4234 IORecursiveLockLock(sKextLock);
4235
4236 OSKext * aKext = OSDynamicCast(OSKext,
4237 sKextsByID->getObject(kextIdentifier));
4238 if (!aKext) {
4239 result = kOSKextReturnNotFound;
4240 OSKextLog(/* kext */ NULL,
4241 kOSKextLogErrorLevel |
4242 kOSKextLogKextBookkeepingFlag,
4243 "Can't remove kext %s - not found.",
4244 kextIdentifier);
4245 goto finish;
4246 }
4247
4248 result = OSKext::removeKext(aKext,
4249 terminateServicesAndRemovePersonalitiesFlag);
4250
4251 finish:
4252 IORecursiveLockUnlock(sKextLock);
4253
4254 return result;
4255 }
4256
4257 /*********************************************************************
4258 *********************************************************************/
4259 /* static */
4260 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4261 OSKext::removeKextWithLoadTag(
4262 OSKextLoadTag loadTag,
4263 bool terminateServicesAndRemovePersonalitiesFlag)
4264 {
4265 OSReturn result = kOSReturnError;
4266 OSKext * foundKext = NULL;
4267 uint32_t i, j;
4268 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4269 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4270
4271
4272 IORecursiveLockLock(sKextLock);
4273
4274 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4275 for (i = 0; i < count[j]; i++) {
4276 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4277 if (thisKext->loadTag == loadTag) {
4278 foundKext = thisKext;
4279 break;
4280 }
4281 }
4282 }
4283
4284 if (!foundKext) {
4285 result = kOSKextReturnNotFound;
4286 OSKextLog(/* kext */ NULL,
4287 kOSKextLogErrorLevel |
4288 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4289 "Can't remove kext with load tag %d - not found.",
4290 loadTag);
4291 goto finish;
4292 }
4293
4294 result = OSKext::removeKext(foundKext,
4295 terminateServicesAndRemovePersonalitiesFlag);
4296
4297 finish:
4298 IORecursiveLockUnlock(sKextLock);
4299
4300 return result;
4301 }
4302
4303 /*********************************************************************
4304 *********************************************************************/
4305 OSSharedPtr<OSDictionary>
copyKexts(void)4306 OSKext::copyKexts(void)
4307 {
4308 OSSharedPtr<OSDictionary> result;
4309
4310 IORecursiveLockLock(sKextLock);
4311 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4312 IORecursiveLockUnlock(sKextLock);
4313
4314 return result;
4315 }
4316
4317 /*********************************************************************
4318 *********************************************************************/
4319 #define BOOTER_KEXT_PREFIX "Driver-"
4320
4321 typedef struct _DeviceTreeBuffer {
4322 uint32_t paddr;
4323 uint32_t length;
4324 } _DeviceTreeBuffer;
4325
4326 /*********************************************************************
4327 * Create a dictionary of excluded kexts from the given booter data.
4328 *********************************************************************/
4329 /* static */
4330 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4331 OSKext::createExcludeListFromBooterData(
4332 OSDictionary * theDictionary,
4333 OSCollectionIterator * theIterator )
4334 {
4335 OSString * deviceTreeName = NULL; // do not release
4336 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4337 char * booterDataPtr = NULL; // do not release
4338 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4339 char * infoDictAddr = NULL; // do not release
4340 OSSharedPtr<OSObject> parsedXML;
4341 OSDictionary * theInfoDict = NULL; // do not release
4342
4343 theIterator->reset();
4344
4345 /* look for AppleKextExcludeList.kext */
4346 while ((deviceTreeName =
4347 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4348 const char * devTreeNameCString;
4349 OSData * deviceTreeEntry; // do not release
4350 OSString * myBundleID; // do not release
4351
4352 deviceTreeEntry =
4353 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4354 if (!deviceTreeEntry) {
4355 continue;
4356 }
4357
4358 /* Make sure it is a kext */
4359 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4360 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4361 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4362 OSKextLog(NULL,
4363 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4364 "\"%s\" not a kext",
4365 devTreeNameCString);
4366 continue;
4367 }
4368
4369 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4370 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4371 if (!deviceTreeBuffer) {
4372 continue;
4373 }
4374
4375 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4376 if (!booterDataPtr) {
4377 continue;
4378 }
4379
4380 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4381 if (!kextFileInfo->infoDictPhysAddr ||
4382 !kextFileInfo->infoDictLength) {
4383 continue;
4384 }
4385
4386 infoDictAddr = (char *)
4387 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4388 if (!infoDictAddr) {
4389 continue;
4390 }
4391
4392 parsedXML = OSUnserializeXML(infoDictAddr);
4393 if (!parsedXML) {
4394 continue;
4395 }
4396
4397 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4398 if (!theInfoDict) {
4399 continue;
4400 }
4401
4402 myBundleID =
4403 OSDynamicCast(OSString,
4404 theInfoDict->getObject(kCFBundleIdentifierKey));
4405 if (myBundleID &&
4406 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4407 boolean_t updated = updateExcludeList(theInfoDict);
4408 if (!updated) {
4409 /* 25322874 */
4410 panic("Missing OSKextExcludeList dictionary");
4411 }
4412 break;
4413 }
4414 } // while ( (deviceTreeName = ...) )
4415
4416 return;
4417 }
4418
4419 /*********************************************************************
4420 * Create a dictionary of excluded kexts from the given prelink
4421 * info (kernelcache).
4422 *********************************************************************/
4423 /* static */
4424 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4425 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4426 {
4427 OSDictionary * myInfoDict = NULL; // do not release
4428 OSString * myBundleID; // do not release
4429 u_int i;
4430
4431 /* Find the Apple Kext Exclude List. */
4432 for (i = 0; i < theInfoArray->getCount(); i++) {
4433 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4434 if (!myInfoDict) {
4435 continue;
4436 }
4437 myBundleID =
4438 OSDynamicCast(OSString,
4439 myInfoDict->getObject(kCFBundleIdentifierKey));
4440 if (myBundleID &&
4441 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4442 boolean_t updated = updateExcludeList(myInfoDict);
4443 if (!updated) {
4444 /* 25322874 */
4445 panic("Missing OSKextExcludeList dictionary");
4446 }
4447 break;
4448 }
4449 } // for (i = 0; i < theInfoArray->getCount()...
4450
4451 return;
4452 }
4453
4454 /* static */
4455 boolean_t
updateExcludeList(OSDictionary * infoDict)4456 OSKext::updateExcludeList(OSDictionary *infoDict)
4457 {
4458 OSDictionary *myTempDict = NULL; // do not free
4459 OSString *myTempString = NULL; // do not free
4460 OSKextVersion newVersion = 0;
4461 boolean_t updated = false;
4462
4463 if (!infoDict) {
4464 return false;
4465 }
4466
4467 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4468 if (!myTempDict) {
4469 return false;
4470 }
4471
4472 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4473 if (!myTempString) {
4474 return false;
4475 }
4476
4477 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4478 if (newVersion == 0) {
4479 return false;
4480 }
4481
4482 IORecursiveLockLock(sKextLock);
4483
4484 if (newVersion > sExcludeListVersion) {
4485 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4486 sExcludeListVersion = newVersion;
4487 updated = true;
4488 }
4489
4490 IORecursiveLockUnlock(sKextLock);
4491 return updated;
4492 }
4493
4494 #if PRAGMA_MARK
4495 #pragma mark Accessors
4496 #endif
4497 /*********************************************************************
4498 *********************************************************************/
4499 const OSSymbol *
getIdentifier(void)4500 OSKext::getIdentifier(void)
4501 {
4502 return bundleID.get();
4503 }
4504
4505 /*********************************************************************
4506 * A kext must have a bundle identifier to even survive initialization;
4507 * this is guaranteed to exist past then.
4508 *********************************************************************/
4509 const char *
getIdentifierCString(void)4510 OSKext::getIdentifierCString(void)
4511 {
4512 return bundleID->getCStringNoCopy();
4513 }
4514
4515 /*********************************************************************
4516 *********************************************************************/
4517 OSKextVersion
getVersion(void)4518 OSKext::getVersion(void)
4519 {
4520 return version;
4521 }
4522
4523 /*********************************************************************
4524 *********************************************************************/
4525 OSKextVersion
getCompatibleVersion(void)4526 OSKext::getCompatibleVersion(void)
4527 {
4528 return compatibleVersion;
4529 }
4530
4531 /*********************************************************************
4532 *********************************************************************/
4533 bool
isLibrary(void)4534 OSKext::isLibrary(void)
4535 {
4536 return getCompatibleVersion() > 0;
4537 }
4538
4539 /*********************************************************************
4540 *********************************************************************/
4541 bool
isCompatibleWithVersion(OSKextVersion aVersion)4542 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4543 {
4544 if ((compatibleVersion > -1 && version > -1) &&
4545 (compatibleVersion <= version && aVersion <= version)) {
4546 return true;
4547 }
4548 return false;
4549 }
4550
4551 /*********************************************************************
4552 *********************************************************************/
4553 bool
declaresExecutable(void)4554 OSKext::declaresExecutable(void)
4555 {
4556 if (isDriverKit()) {
4557 return false;
4558 }
4559 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4560 }
4561
4562 /*********************************************************************
4563 *********************************************************************/
4564 OSData *
getExecutable(void)4565 OSKext::getExecutable(void)
4566 {
4567 OSData * result = NULL;
4568 OSSharedPtr<OSData> extractedExecutable;
4569
4570 if (flags.builtin) {
4571 return sKernelKext->linkedExecutable.get();
4572 }
4573
4574 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4575 if (result) {
4576 return result;
4577 }
4578
4579 #if CONFIG_KXLD
4580 OSData * mkextExecutableRef = NULL; // do not release
4581 mkextExecutableRef = OSDynamicCast(OSData,
4582 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4583
4584 if (mkextExecutableRef) {
4585 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4586 mkextExecutableRef->getBytesNoCopy();
4587 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4588 if (mkextVersion == MKEXT_VERS_2) {
4589 mkext2_file_entry * fileinfo =
4590 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4591 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4592 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4593 extractedExecutable = extractMkext2FileData(
4594 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4595 compressedSize, fullSize);
4596 } else {
4597 OSKextLog(this, kOSKextLogErrorLevel |
4598 kOSKextLogArchiveFlag,
4599 "Kext %s - unknown mkext version 0x%x for executable.",
4600 getIdentifierCString(), mkextVersion);
4601 }
4602
4603 /* Regardless of success, remove the mkext executable,
4604 * and drop one reference on the mkext. (setExecutable() does not
4605 * replace, it removes, or panics if asked to replace.)
4606 */
4607 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4608 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4609
4610 if (extractedExecutable && extractedExecutable->getLength()) {
4611 if (!setExecutable(extractedExecutable.get())) {
4612 goto finish;
4613 }
4614 result = extractedExecutable.get();
4615 } else {
4616 goto finish;
4617 }
4618 }
4619
4620 finish:
4621 #endif // CONFIG_KXLD
4622 return result;
4623 }
4624
4625 /*********************************************************************
4626 *********************************************************************/
4627 bool
isInterface(void)4628 OSKext::isInterface(void)
4629 {
4630 return flags.interface;
4631 }
4632
4633 /*********************************************************************
4634 *********************************************************************/
4635 bool
isKernel(void)4636 OSKext::isKernel(void)
4637 {
4638 return this == sKernelKext;
4639 }
4640
4641 /*********************************************************************
4642 *********************************************************************/
4643 bool
isKernelComponent(void)4644 OSKext::isKernelComponent(void)
4645 {
4646 return flags.kernelComponent ? true : false;
4647 }
4648
4649 /*********************************************************************
4650 *********************************************************************/
4651 bool
isExecutable(void)4652 OSKext::isExecutable(void)
4653 {
4654 return !isKernel() && !isInterface() && declaresExecutable();
4655 }
4656
4657 /*********************************************************************
4658 * We might want to check this recursively for all dependencies,
4659 * since a subtree of dependencies could get loaded before we hit
4660 * a dependency that isn't safe-boot-loadable.
4661 *
4662 * xxx - Might want to return false if OSBundleEnableKextLogging or
4663 * OSBundleDebugLevel
4664 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4665 * the point except it's usually development drivers, which might
4666 * cause panics on startup, that have those properties). Heh; could
4667 * use a "kx" boot-arg!
4668 *********************************************************************/
4669 bool
isLoadableInSafeBoot(void)4670 OSKext::isLoadableInSafeBoot(void)
4671 {
4672 bool result = false;
4673 OSString * required = NULL; // do not release
4674
4675 if (isKernel()) {
4676 result = true;
4677 goto finish;
4678 }
4679
4680 if (isDriverKit()) {
4681 result = true;
4682 goto finish;
4683 }
4684
4685 required = OSDynamicCast(OSString,
4686 getPropertyForHostArch(kOSBundleRequiredKey));
4687 if (!required) {
4688 goto finish;
4689 }
4690 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4691 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4692 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4693 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4694 required->isEqualTo(kOSBundleRequiredConsole)) {
4695 result = true;
4696 }
4697
4698 finish:
4699 return result;
4700 }
4701
4702 /*********************************************************************
4703 *********************************************************************/
4704 bool
isPrelinked(void)4705 OSKext::isPrelinked(void)
4706 {
4707 return flags.prelinked ? true : false;
4708 }
4709
4710 /*********************************************************************
4711 *********************************************************************/
4712 bool
isLoaded(void)4713 OSKext::isLoaded(void)
4714 {
4715 return flags.loaded ? true : false;
4716 }
4717
4718 /*********************************************************************
4719 *********************************************************************/
4720 bool
isStarted(void)4721 OSKext::isStarted(void)
4722 {
4723 return flags.started ? true : false;
4724 }
4725
4726 /*********************************************************************
4727 *********************************************************************/
4728 bool
isCPPInitialized(void)4729 OSKext::isCPPInitialized(void)
4730 {
4731 return flags.CPPInitialized;
4732 }
4733
4734 /*********************************************************************
4735 *********************************************************************/
4736 void
setCPPInitialized(bool initialized)4737 OSKext::setCPPInitialized(bool initialized)
4738 {
4739 flags.CPPInitialized = initialized;
4740 }
4741
4742 /*********************************************************************
4743 *********************************************************************/
4744 uint32_t
getLoadTag(void)4745 OSKext::getLoadTag(void)
4746 {
4747 return loadTag;
4748 }
4749
4750 /*********************************************************************
4751 *********************************************************************/
4752 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)4753 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4754 {
4755 if (linkedExecutable) {
4756 *loadSize = linkedExecutable->getLength();
4757
4758 /* If we have a kmod_info struct, calculated the wired size
4759 * from that. Otherwise it's the full load size.
4760 */
4761 if (kmod_info) {
4762 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
4763 } else {
4764 *wiredSize = *loadSize;
4765 }
4766 } else {
4767 *wiredSize = 0;
4768 *loadSize = 0;
4769 }
4770 }
4771
4772 /*********************************************************************
4773 *********************************************************************/
4774 OSSharedPtr<OSData>
copyUUID(void)4775 OSKext::copyUUID(void)
4776 {
4777 OSSharedPtr<OSData> result;
4778 OSData * theExecutable = NULL; // do not release
4779 const kernel_mach_header_t * header;
4780
4781 /* An interface kext doesn't have a linked executable with an LC_UUID,
4782 * we create one when it's linked.
4783 */
4784 if (interfaceUUID) {
4785 result = interfaceUUID;
4786 goto finish;
4787 }
4788
4789 if (flags.builtin || isInterface()) {
4790 return sKernelKext->copyUUID();
4791 }
4792
4793 if (isDriverKit() && infoDict) {
4794 return driverKitUUID;
4795 }
4796
4797 /* For real kexts, try to get the UUID from the linked executable,
4798 * or if is hasn't been linked yet, the unrelocated executable.
4799 */
4800 theExecutable = linkedExecutable.get();
4801 if (!theExecutable) {
4802 theExecutable = getExecutable();
4803 }
4804
4805 if (!theExecutable) {
4806 goto finish;
4807 }
4808
4809 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4810 result = copyMachoUUID(header);
4811
4812 finish:
4813 return result;
4814 }
4815
4816 /*********************************************************************
4817 *********************************************************************/
4818 OSSharedPtr<OSData>
copyTextUUID(void)4819 OSKext::copyTextUUID(void)
4820 {
4821 if (flags.builtin) {
4822 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4823 }
4824 return copyUUID();
4825 }
4826
4827 /*********************************************************************
4828 *********************************************************************/
4829 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)4830 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4831 {
4832 OSSharedPtr<OSData> result;
4833 const struct load_command * load_cmd = NULL;
4834 const struct uuid_command * uuid_cmd = NULL;
4835 uint32_t i;
4836
4837 load_cmd = (const struct load_command *)&header[1];
4838
4839 if (header->magic != MH_MAGIC_KERNEL) {
4840 OSKextLog(NULL,
4841 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4842 "%s: bad header %p",
4843 __func__,
4844 header);
4845 goto finish;
4846 }
4847
4848 for (i = 0; i < header->ncmds; i++) {
4849 if (load_cmd->cmd == LC_UUID) {
4850 uuid_cmd = (struct uuid_command *)load_cmd;
4851 result = OSData::withValue(uuid_cmd->uuid);
4852 goto finish;
4853 }
4854 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4855 }
4856
4857 finish:
4858 return result;
4859 }
4860
4861 void
setDriverKitUUID(OSData * uuid)4862 OSKext::setDriverKitUUID(OSData *uuid)
4863 {
4864 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4865 OSSafeReleaseNULL(uuid);
4866 }
4867 }
4868
4869 /*********************************************************************
4870 *********************************************************************/
4871 #if defined (__arm__)
4872 #include <arm/arch.h>
4873 #endif
4874
4875 #if defined (__x86_64__)
4876 #define ARCHNAME "x86_64"
4877 #elif defined (__arm64__)
4878 #define ARCHNAME "arm64"
4879 #elif defined (__arm__)
4880
4881 #if defined (__ARM_ARCH_7S__)
4882 #define ARCHNAME "armv7s"
4883 #elif defined (__ARM_ARCH_7F__)
4884 #define ARCHNAME "armv7f"
4885 #elif defined (__ARM_ARCH_7K__)
4886 #define ARCHNAME "armv7k"
4887 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4888 #define ARCHNAME "armv7"
4889 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4890 #define ARCHNAME "armv6"
4891 #endif
4892
4893 #elif defined (__arm64__)
4894 #define ARCHNAME "arm64"
4895 #else
4896 #error architecture not supported
4897 #endif
4898
4899 #define ARCH_SEPARATOR_CHAR '_'
4900
4901 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)4902 makeHostArchKey(const char * key, size_t * keySizeOut)
4903 {
4904 char * result = NULL;
4905 size_t keyLength = strlen(key);
4906 size_t keySize;
4907
4908 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4909 */
4910 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4911 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4912
4913 if (!result) {
4914 goto finish;
4915 }
4916 strlcpy(result, key, keySize);
4917 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4918 result[keyLength] = '\0';
4919 strlcat(result, ARCHNAME, keySize);
4920 *keySizeOut = keySize;
4921
4922 finish:
4923 return result;
4924 }
4925
4926 /*********************************************************************
4927 *********************************************************************/
4928 OSObject *
getPropertyForHostArch(const char * key)4929 OSKext::getPropertyForHostArch(const char * key)
4930 {
4931 OSObject * result = NULL;// do not release
4932 size_t hostArchKeySize = 0;
4933 char * hostArchKey = NULL;// must kfree
4934
4935 if (!key || !infoDict) {
4936 goto finish;
4937 }
4938
4939 /* Some properties are not allowed to be arch-variant:
4940 * - Any CFBundle... property.
4941 * - OSBundleIsInterface.
4942 * - OSKernelResource.
4943 */
4944 if (STRING_HAS_PREFIX(key, "OS") ||
4945 STRING_HAS_PREFIX(key, "IO")) {
4946 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4947 if (!hostArchKey) {
4948 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4949 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4950 "Allocation failure.");
4951 goto finish;
4952 }
4953 result = infoDict->getObject(hostArchKey);
4954 }
4955
4956 if (!result) {
4957 result = infoDict->getObject(key);
4958 }
4959
4960 finish:
4961 if (hostArchKey) {
4962 kfree_data(hostArchKey, hostArchKeySize);
4963 }
4964 return result;
4965 }
4966
4967 #if PRAGMA_MARK
4968 #pragma mark Load/Start/Stop/Unload
4969 #endif
4970
4971 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4972
4973 /*********************************************************************
4974 * sExcludeListByID is a dictionary with keys / values of:
4975 * key = bundleID string of kext we will not allow to load
4976 * value = version string(s) of the kext that is to be denied loading.
4977 * The version strings can be comma delimited. For example if kext
4978 * com.foocompany.fookext has two versions that we want to deny
4979 * loading then the version strings might look like:
4980 * 1.0.0, 1.0.1
4981 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4982 * not load the kext.
4983 *
4984 * Value may also be in the form of "LE 2.0.0" (version numbers
4985 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4986 * number less than 2.0.0 will not load)
4987 *
4988 * NOTE - we cannot use the characters "<=" or "<" because we have code
4989 * that serializes plists and treats '<' as a special character.
4990 *********************************************************************/
4991 bool
isInExcludeList(void)4992 OSKext::isInExcludeList(void)
4993 {
4994 OSString * versionString = NULL; // do not release
4995 char * versionCString = NULL; // do not free
4996 size_t i;
4997 boolean_t wantLessThan = false;
4998 boolean_t wantLessThanEqualTo = false;
4999 boolean_t isInExcludeList = true;
5000 char myBuffer[32];
5001
5002 IORecursiveLockLock(sKextLock);
5003
5004 if (!sExcludeListByID) {
5005 isInExcludeList = false;
5006 } else {
5007 /* look up by bundleID in our exclude list and if found get version
5008 * string (or strings) that we will not allow to load
5009 */
5010 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5011 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5012 isInExcludeList = false;
5013 }
5014 }
5015
5016 IORecursiveLockUnlock(sKextLock);
5017
5018 if (!isInExcludeList) {
5019 return false;
5020 }
5021
5022 /* parse version strings */
5023 versionCString = (char *) versionString->getCStringNoCopy();
5024
5025 /* look for "LT" or "LE" form of version string, must be in first two
5026 * positions.
5027 */
5028 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5029 wantLessThan = true;
5030 versionCString += 2;
5031 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5032 wantLessThanEqualTo = true;
5033 versionCString += 2;
5034 }
5035
5036 for (i = 0; *versionCString != 0x00; versionCString++) {
5037 /* skip whitespace */
5038 if (isWhiteSpace(*versionCString)) {
5039 continue;
5040 }
5041
5042 /* peek ahead for version string separator or null terminator */
5043 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5044 /* OK, we have a version string */
5045 myBuffer[i++] = *versionCString;
5046 myBuffer[i] = 0x00;
5047
5048 OSKextVersion excludeVers;
5049 excludeVers = OSKextParseVersionString(myBuffer);
5050
5051 if (wantLessThanEqualTo) {
5052 if (version <= excludeVers) {
5053 return true;
5054 }
5055 } else if (wantLessThan) {
5056 if (version < excludeVers) {
5057 return true;
5058 }
5059 } else if (version == excludeVers) {
5060 return true;
5061 }
5062
5063 /* reset for the next (if any) version string */
5064 i = 0;
5065 wantLessThan = false;
5066 wantLessThanEqualTo = false;
5067 } else {
5068 /* save valid version character */
5069 myBuffer[i++] = *versionCString;
5070
5071 /* make sure bogus version string doesn't overrun local buffer */
5072 if (i >= sizeof(myBuffer)) {
5073 break;
5074 }
5075 }
5076 }
5077
5078 return false;
5079 }
5080
5081 /*********************************************************************
5082 * sNonLoadableKextsByID is a dictionary with keys / values of:
5083 * key = bundleID string of kext we will not allow to load
5084 * value = boolean (true == loadable, false == not loadable)
5085 *
5086 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5087 * i.e., the value for the kext's bundleID will be false. All kexts in
5088 * the primary and system KCs will always be marked as "loadable."
5089 *
5090 * This list ultimately comes from kexts which have been uninstalled
5091 * in user space by deleting the kext from disk, but which have not
5092 * yet been removed from the AuxKC. Because the user could choose to
5093 * re-install the exact same version of the kext, we need to keep
5094 * a dictionary of boolean values so that user space only needs to
5095 * keep a simple list of "uninstalled" or "missing" bundles. When
5096 * a bundle is re-installed, the iokit daemon can use the
5097 * AucKCBundleAvailable predicate to set the individual kext's
5098 * availability to true.
5099 *********************************************************************/
5100 bool
isLoadable(void)5101 OSKext::isLoadable(void)
5102 {
5103 bool isLoadable = true;
5104
5105 if (kc_type != KCKindAuxiliary) {
5106 /* this filtering only applies to kexts in the auxkc */
5107 return true;
5108 }
5109
5110 IORecursiveLockLock(sKextLock);
5111
5112 if (sNonLoadableKextsByID) {
5113 /* look up by bundleID in our exclude list and if found get version
5114 * string (or strings) that we will not allow to load
5115 */
5116 OSBoolean *loadableVal;
5117 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5118 if (loadableVal && !loadableVal->getValue()) {
5119 isLoadable = false;
5120 }
5121 }
5122 IORecursiveLockUnlock(sKextLock);
5123
5124 return isLoadable;
5125 }
5126
5127 /*********************************************************************
5128 *********************************************************************/
5129 /* static */
5130 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5131 OSKext::loadKextWithIdentifier(
5132 const char * kextIdentifierCString,
5133 Boolean allowDeferFlag,
5134 Boolean delayAutounloadFlag,
5135 OSKextExcludeLevel startOpt,
5136 OSKextExcludeLevel startMatchingOpt,
5137 OSArray * personalityNames)
5138 {
5139 OSReturn result = kOSReturnError;
5140 OSSharedPtr<OSString> kextIdentifier;
5141
5142 kextIdentifier = OSString::withCString(kextIdentifierCString);
5143 if (!kextIdentifier) {
5144 result = kOSKextReturnNoMemory;
5145 goto finish;
5146 }
5147 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5148 NULL /* kextRef */,
5149 allowDeferFlag, delayAutounloadFlag,
5150 startOpt, startMatchingOpt, personalityNames);
5151
5152 finish:
5153 return result;
5154 }
5155
5156 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5157 OSKext::loadKextWithIdentifier(
5158 OSString * kextIdentifier,
5159 OSSharedPtr<OSObject> &kextRef,
5160 Boolean allowDeferFlag,
5161 Boolean delayAutounloadFlag,
5162 OSKextExcludeLevel startOpt,
5163 OSKextExcludeLevel startMatchingOpt,
5164 OSArray * personalityNames)
5165 {
5166 OSObject * kextRefRaw = NULL;
5167 OSReturn result;
5168
5169 result = loadKextWithIdentifier(kextIdentifier,
5170 &kextRefRaw,
5171 allowDeferFlag,
5172 delayAutounloadFlag,
5173 startOpt,
5174 startMatchingOpt,
5175 personalityNames);
5176 if ((kOSReturnSuccess == result) && kextRefRaw) {
5177 kextRef.reset(kextRefRaw, OSNoRetain);
5178 }
5179 return result;
5180 }
5181
5182 /*********************************************************************
5183 *********************************************************************/
5184 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5185 OSKext::loadKextWithIdentifier(
5186 OSString * kextIdentifier,
5187 OSObject ** kextRef,
5188 Boolean allowDeferFlag,
5189 Boolean delayAutounloadFlag,
5190 OSKextExcludeLevel startOpt,
5191 OSKextExcludeLevel startMatchingOpt,
5192 OSArray * personalityNames)
5193 {
5194 OSReturn result = kOSReturnError;
5195 OSReturn pingResult = kOSReturnError;
5196 OSKext * theKext = NULL; // do not release
5197 OSSharedPtr<OSDictionary> loadRequest;
5198 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5199
5200 if (kextRef) {
5201 *kextRef = NULL;
5202 }
5203
5204 IORecursiveLockLock(sKextLock);
5205
5206 if (!kextIdentifier) {
5207 result = kOSKextReturnInvalidArgument;
5208 goto finish;
5209 }
5210
5211 OSKext::recordIdentifierRequest(kextIdentifier);
5212
5213 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5214 if (!theKext) {
5215 if (!allowDeferFlag) {
5216 OSKextLog(/* kext */ NULL,
5217 kOSKextLogErrorLevel |
5218 kOSKextLogLoadFlag,
5219 "Can't load kext %s - not found.",
5220 kextIdentifier->getCStringNoCopy());
5221 goto finish;
5222 }
5223
5224 if (!sKernelRequestsEnabled) {
5225 OSKextLog(theKext,
5226 kOSKextLogErrorLevel |
5227 kOSKextLogLoadFlag,
5228 "Can't load kext %s - requests to user space are disabled.",
5229 kextIdentifier->getCStringNoCopy());
5230 result = kOSKextReturnDisabled;
5231 goto finish;
5232 }
5233
5234 /* Create a new request unless one is already sitting
5235 * in sKernelRequests for this bundle identifier
5236 */
5237 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5238 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5239 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5240 loadRequest);
5241 if (result != kOSReturnSuccess) {
5242 goto finish;
5243 }
5244 if (!_OSKextSetRequestArgument(loadRequest.get(),
5245 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5246 result = kOSKextReturnNoMemory;
5247 goto finish;
5248 }
5249 if (!sKernelRequests->setObject(loadRequest.get())) {
5250 result = kOSKextReturnNoMemory;
5251 goto finish;
5252 }
5253
5254 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5255 result = kOSKextReturnNoMemory;
5256 goto finish;
5257 }
5258
5259 OSKextLog(theKext,
5260 kOSKextLogDebugLevel |
5261 kOSKextLogLoadFlag,
5262 "Kext %s not found; queued load request to user space.",
5263 kextIdentifier->getCStringNoCopy());
5264 }
5265
5266 pingResult = OSKext::pingIOKitDaemon();
5267 if (pingResult == kOSKextReturnDisabled) {
5268 OSKextLog(/* kext */ NULL,
5269 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5270 kOSKextLogLoadFlag,
5271 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5272 kextIdentifier->getCStringNoCopy());
5273 }
5274
5275 result = kOSKextReturnDeferred;
5276 goto finish;
5277 }
5278
5279 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5280
5281 if (result != kOSReturnSuccess) {
5282 OSKextLog(theKext,
5283 kOSKextLogErrorLevel |
5284 kOSKextLogLoadFlag,
5285 "Failed to load kext %s (error 0x%x).",
5286 kextIdentifier->getCStringNoCopy(), (int)result);
5287
5288 if (theKext->kc_type == KCKindUnknown) {
5289 OSKext::removeKext(theKext,
5290 /* terminateService/removePersonalities */ true);
5291 }
5292 goto finish;
5293 }
5294
5295 if (delayAutounloadFlag) {
5296 OSKextLog(theKext,
5297 kOSKextLogProgressLevel |
5298 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5299 "Setting delayed autounload for %s.",
5300 kextIdentifier->getCStringNoCopy());
5301 theKext->flags.delayAutounload = 1;
5302 }
5303
5304 finish:
5305 if ((kOSReturnSuccess == result) && kextRef) {
5306 *kextRef = theKext;
5307 theKext->matchingRefCount++;
5308 theKext->retain();
5309 }
5310
5311 IORecursiveLockUnlock(sKextLock);
5312
5313 return result;
5314 }
5315
5316 /*********************************************************************
5317 *********************************************************************/
5318 /* static */
5319 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)5320 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5321 {
5322 OSReturn result = kOSReturnError;
5323
5324 OSBoolean *delayAutounloadBool = NULL; // do not release
5325 OSNumber *startKextExcludeNum = NULL; // do not release
5326 OSNumber *startMatchingExcludeNum = NULL; // do not release
5327 OSArray *personalityNames = NULL; // do not release
5328
5329 /*
5330 * Default values for these options:
5331 * regular autounload behavior
5332 * start the kext
5333 * send all personalities to the catalog
5334 */
5335 Boolean delayAutounload = false;
5336 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5337 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5338
5339 IORecursiveLockLock(sKextLock);
5340
5341 OSKextLog(/* kext */ NULL,
5342 kOSKextLogDebugLevel |
5343 kOSKextLogIPCFlag,
5344 "Received kext KC load request from user space.");
5345
5346 /* Regardless of processing, the fact that we have gotten here means some
5347 * user-space program is up and talking to us, so we'll switch our kext
5348 * registration to reflect that.
5349 */
5350 if (!sUserLoadsActive) {
5351 OSKextLog(/* kext */ NULL,
5352 kOSKextLogProgressLevel |
5353 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5354 "Switching to late startup (user-space) kext loading policy.");
5355 sUserLoadsActive = true;
5356 }
5357
5358 delayAutounloadBool = OSDynamicCast(OSBoolean,
5359 _OSKextGetRequestArgument(requestDict,
5360 kKextRequestArgumentDelayAutounloadKey));
5361 startKextExcludeNum = OSDynamicCast(OSNumber,
5362 _OSKextGetRequestArgument(requestDict,
5363 kKextRequestArgumentStartExcludeKey));
5364 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5365 _OSKextGetRequestArgument(requestDict,
5366 kKextRequestArgumentStartMatchingExcludeKey));
5367 personalityNames = OSDynamicCast(OSArray,
5368 _OSKextGetRequestArgument(requestDict,
5369 kKextRequestArgumentPersonalityNamesKey));
5370
5371 if (delayAutounloadBool) {
5372 delayAutounload = delayAutounloadBool->getValue();
5373 }
5374 if (startKextExcludeNum) {
5375 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5376 }
5377 if (startMatchingExcludeNum) {
5378 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5379 }
5380
5381 OSKextLog(/* kext */ NULL,
5382 kOSKextLogProgressLevel |
5383 kOSKextLogIPCFlag,
5384 "Received request from user space to load KC kext %s.",
5385 theKext->getIdentifierCString());
5386
5387 /* this could be in the Auxiliary KC, so record the load request */
5388 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5389
5390 /*
5391 * Load the kext
5392 */
5393 result = theKext->load(startKextExcludeLevel,
5394 startMatchingExcludeLevel, personalityNames);
5395
5396 if (result != kOSReturnSuccess) {
5397 OSKextLog(theKext,
5398 kOSKextLogErrorLevel |
5399 kOSKextLogLoadFlag,
5400 "Failed to load kext %s (error 0x%x).",
5401 theKext->getIdentifierCString(), (int)result);
5402
5403 OSKext::removeKext(theKext,
5404 /* terminateService/removePersonalities */ true);
5405 goto finish;
5406 } else {
5407 OSKextLog(theKext,
5408 kOSKextLogProgressLevel |
5409 kOSKextLogLoadFlag,
5410 "Kext %s Loaded successfully from %s KC",
5411 theKext->getIdentifierCString(), theKext->getKCTypeString());
5412 }
5413
5414 if (delayAutounload) {
5415 OSKextLog(theKext,
5416 kOSKextLogProgressLevel |
5417 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5418 "Setting delayed autounload for %s.",
5419 theKext->getIdentifierCString());
5420 theKext->flags.delayAutounload = 1;
5421 }
5422
5423 finish:
5424 IORecursiveLockUnlock(sKextLock);
5425
5426 return result;
5427 }
5428
5429 /*********************************************************************
5430 *********************************************************************/
5431 /* static */
5432 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)5433 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5434 {
5435 OSReturn result = kOSReturnError;
5436 OSDictionary *anInfoDict = NULL; // do not release
5437
5438 anInfoDict = OSDynamicCast(OSDictionary,
5439 _OSKextGetRequestArgument(requestDict,
5440 kKextRequestArgumentCodelessInfoKey));
5441 if (anInfoDict == NULL) {
5442 OSKextLog(/* kext */ NULL,
5443 kOSKextLogErrorLevel |
5444 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5445 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5446 kextIdentifier->getCStringNoCopy());
5447 return kOSKextReturnInvalidArgument;
5448 }
5449
5450 IORecursiveLockLock(sKextLock);
5451
5452 OSKextLog(/* kext */ NULL,
5453 kOSKextLogProgressLevel |
5454 kOSKextLogIPCFlag,
5455 "Received request from user space to load codeless kext %s.",
5456 kextIdentifier->getCStringNoCopy());
5457
5458 {
5459 // instantiate a new kext, and don't hold a reference
5460 // (the kext subsystem will hold one implicitly)
5461 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5462 if (!newKext) {
5463 OSKextLog(/* kext */ NULL,
5464 kOSKextLogErrorLevel |
5465 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5466 "Could not instantiate codeless kext.");
5467 result = kOSKextReturnNotLoadable;
5468 goto finish;
5469 }
5470 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5471 OSKextLog(/* kext */ NULL,
5472 kOSKextLogErrorLevel |
5473 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5474 "Codeless kext identifiers don't match '%s' != '%s'",
5475 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5476
5477 OSKext::removeKext(newKext.get(), false);
5478 result = kOSKextReturnInvalidArgument;
5479 goto finish;
5480 }
5481
5482 /* Record the request for the codeless kext */
5483 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5484
5485 result = kOSReturnSuccess;
5486 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5487 result = newKext->sendPersonalitiesToCatalog(true, NULL);
5488 }
5489
5490 finish:
5491 IORecursiveLockUnlock(sKextLock);
5492
5493 return result;
5494 }
5495
5496 /*********************************************************************
5497 *********************************************************************/
5498 /* static */
5499 void
dropMatchingReferences(OSSet * kexts)5500 OSKext::dropMatchingReferences(
5501 OSSet * kexts)
5502 {
5503 IORecursiveLockLock(sKextLock);
5504 kexts->iterateObjects(^bool (OSObject * obj) {
5505 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5506 if (!thisKext) {
5507 return false;
5508 }
5509 thisKext->matchingRefCount--;
5510 return false;
5511 });
5512 IORecursiveLockUnlock(sKextLock);
5513 }
5514
5515 /*********************************************************************
5516 *********************************************************************/
5517 /* static */
5518 void
recordIdentifierRequest(OSString * kextIdentifier)5519 OSKext::recordIdentifierRequest(
5520 OSString * kextIdentifier)
5521 {
5522 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5523 bool fail = false;
5524
5525 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5526 goto finish;
5527 }
5528
5529 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5530 if (!kextIdentifierSymbol) {
5531 // xxx - this is really a basic alloc failure
5532 fail = true;
5533 goto finish;
5534 }
5535
5536 IORecursiveLockLock(sKextLock);
5537 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5538 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5539 fail = true;
5540 } else {
5541 // xxx - need to find a way to associate this whole func w/the kext
5542 OSKextLog(/* kext */ NULL,
5543 // xxx - check level
5544 kOSKextLogStepLevel |
5545 kOSKextLogArchiveFlag,
5546 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5547 kextIdentifier->getCStringNoCopy());
5548 }
5549 }
5550 IORecursiveLockUnlock(sKextLock);
5551
5552 finish:
5553
5554 if (fail) {
5555 OSKextLog(/* kext */ NULL,
5556 kOSKextLogErrorLevel |
5557 kOSKextLogArchiveFlag,
5558 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5559 kextIdentifier->getCStringNoCopy());
5560 }
5561 return;
5562 }
5563
5564 /*********************************************************************
5565 *********************************************************************/
5566 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5567 OSKext::load(
5568 OSKextExcludeLevel startOpt,
5569 OSKextExcludeLevel startMatchingOpt,
5570 OSArray * personalityNames)
5571 {
5572 OSReturn result = kOSReturnError;
5573 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5574 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5575 unsigned int i, count;
5576 Boolean alreadyLoaded = false;
5577 OSKext * lastLoadedKext = NULL; // do not release
5578
5579 if (isInExcludeList()) {
5580 OSKextLog(this,
5581 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5582 kOSKextLogLoadFlag,
5583 "Kext %s is in exclude list, not loadable",
5584 getIdentifierCString());
5585
5586 result = kOSKextReturnNotLoadable;
5587 goto finish;
5588 }
5589 if (!isLoadable()) {
5590 OSKextLog(this,
5591 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5592 kOSKextLogLoadFlag,
5593 "Kext %s is not loadable",
5594 getIdentifierCString());
5595
5596 result = kOSKextReturnNotLoadable;
5597 goto finish;
5598 }
5599
5600 if (isLoaded()) {
5601 alreadyLoaded = true;
5602 result = kOSReturnSuccess;
5603
5604 OSKextLog(this,
5605 kOSKextLogDebugLevel |
5606 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5607 "Kext %s is already loaded.",
5608 getIdentifierCString());
5609 goto loaded;
5610 }
5611
5612 #if CONFIG_MACF
5613 /*
5614 * On kxld and on embedded, only call into the MAC hook when on a
5615 * user thread, for access control over userspace kextloads.
5616 *
5617 * On non-kxld systems, additionally check the MAC hook for kexts in
5618 * the Pageable and Aux KCs, regardless of whether we are on a user
5619 * thread or not. This means on Apple silicon devices that the MAC
5620 * hook will only be useful to block 3rd party kexts loaded via
5621 * matching, and any kexts loaded from userspace kextloads.
5622 *
5623 * Note that this should _not_ be called on kexts loaded from the
5624 * kernel bootstrap thread as the kernel proc's cred struct is not
5625 * yet initialized! This won't happen on macOS because all the kexts
5626 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5627 */
5628 if (current_task() != kernel_task
5629 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
5630 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
5631 #endif
5632 ) {
5633 int macCheckResult = 0;
5634 kauth_cred_t cred = NULL;
5635
5636 cred = kauth_cred_get_with_ref();
5637 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5638 kauth_cred_unref(&cred);
5639
5640 if (macCheckResult != 0) {
5641 result = kOSReturnError;
5642 OSKextLog(this,
5643 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5644 "Failed to load kext %s (MAC policy error 0x%x).",
5645 getIdentifierCString(), macCheckResult);
5646 goto finish;
5647 }
5648 }
5649 #endif /* CONFIG_MACF */
5650
5651 if (!sLoadEnabled) {
5652 OSKextLog(this,
5653 kOSKextLogErrorLevel |
5654 kOSKextLogLoadFlag,
5655 "Kext loading is disabled (attempt to load kext %s).",
5656 getIdentifierCString());
5657 result = kOSKextReturnDisabled;
5658 goto finish;
5659 }
5660
5661 /* If we've pushed the next available load tag to the invalid value,
5662 * we can't load any more kexts.
5663 */
5664 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5665 OSKextLog(this,
5666 kOSKextLogErrorLevel |
5667 kOSKextLogLoadFlag,
5668 "Can't load kext %s - no more load tags to assign.",
5669 getIdentifierCString());
5670 result = kOSKextReturnNoResources;
5671 goto finish;
5672 }
5673
5674 /* This is a bit of a hack, because we shouldn't be handling
5675 * personalities within the load function.
5676 */
5677 if (!declaresExecutable()) {
5678 /* There is a special case where a non-executable kext can be loaded: the
5679 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5680 * load its metadata into the global data structures, if appropriate
5681 */
5682 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5683 boolean_t updated = updateExcludeList(infoDict.get());
5684 if (updated) {
5685 OSKextLog(this,
5686 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5687 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5688 }
5689 }
5690
5691 if (isDriverKit()) {
5692 if (loadTag == 0) {
5693 sLoadedDriverKitKexts->setObject(this);
5694 loadTag = sNextLoadTag++;
5695 }
5696 }
5697 result = kOSReturnSuccess;
5698 goto loaded;
5699 }
5700
5701 /* Are we in safe boot?
5702 */
5703 if (sSafeBoot && !isLoadableInSafeBoot()) {
5704 OSKextLog(this,
5705 kOSKextLogErrorLevel |
5706 kOSKextLogLoadFlag,
5707 "Can't load kext %s - not loadable during safe boot.",
5708 getIdentifierCString());
5709 result = kOSKextReturnBootLevel;
5710 goto finish;
5711 }
5712
5713 OSKextLog(this,
5714 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5715 "Loading kext %s.",
5716 getIdentifierCString());
5717
5718 #if !VM_MAPPED_KEXTS
5719 if (isPrelinked() == false) {
5720 OSKextLog(this,
5721 kOSKextLogErrorLevel |
5722 kOSKextLogLoadFlag,
5723 "Can't load kext %s - not in a kext collection.",
5724 getIdentifierCString());
5725 result = kOSKextReturnDisabled;
5726 goto finish;
5727 }
5728 #endif /* defined(__x86_64__) */
5729
5730 #if CONFIG_KXLD
5731 if (!sKxldContext) {
5732 kern_return_t kxldResult;
5733 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5734 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5735 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5736 if (kxldResult) {
5737 OSKextLog(this,
5738 kOSKextLogErrorLevel |
5739 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5740 "Can't load kext %s - failed to create link context.",
5741 getIdentifierCString());
5742 result = kOSKextReturnNoMemory;
5743 goto finish;
5744 }
5745 }
5746 #endif // CONFIG_KXLD
5747
5748 /* We only need to resolve dependencies once for the whole graph, but
5749 * resolveDependencies will just return if there's no work to do, so it's
5750 * safe to call it more than once.
5751 */
5752 if (!resolveDependencies()) {
5753 // xxx - check resolveDependencies() for log msg
5754 OSKextLog(this,
5755 kOSKextLogErrorLevel |
5756 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5757 "Can't load kext %s - failed to resolve library dependencies.",
5758 getIdentifierCString());
5759 result = kOSKextReturnDependencies;
5760 goto finish;
5761 }
5762
5763 /* If we are excluding just the kext being loaded now (and not its
5764 * dependencies), drop the exclusion level to none so dependencies
5765 * start and/or add their personalities.
5766 */
5767 if (dependenciesStartOpt == kOSKextExcludeKext) {
5768 dependenciesStartOpt = kOSKextExcludeNone;
5769 }
5770
5771 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5772 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5773 }
5774
5775 /* Load the dependencies, recursively.
5776 */
5777 count = getNumDependencies();
5778 for (i = 0; i < count; i++) {
5779 OSKext * dependency = OSDynamicCast(OSKext,
5780 dependencies->getObject(i));
5781 if (dependency == NULL) {
5782 OSKextLog(this,
5783 kOSKextLogErrorLevel |
5784 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5785 "Internal error loading kext %s; dependency disappeared.",
5786 getIdentifierCString());
5787 result = kOSKextReturnInternalError;
5788 goto finish;
5789 }
5790
5791 /* Dependencies must be started accorting to the opt,
5792 * but not given the personality names of the main kext.
5793 */
5794 result = dependency->load(dependenciesStartOpt,
5795 dependenciesStartMatchingOpt,
5796 /* personalityNames */ NULL);
5797 if (result != KERN_SUCCESS) {
5798 OSKextLog(this,
5799 kOSKextLogErrorLevel |
5800 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5801 "Dependency %s of kext %s failed to load.",
5802 dependency->getIdentifierCString(),
5803 getIdentifierCString());
5804
5805 OSKext::removeKext(dependency,
5806 /* terminateService/removePersonalities */ true);
5807 result = kOSKextReturnDependencyLoadError;
5808
5809 goto finish;
5810 }
5811 }
5812
5813 result = loadExecutable();
5814 if (result != KERN_SUCCESS) {
5815 goto finish;
5816 }
5817
5818 pendingPgoHead.next = &pendingPgoHead;
5819 pendingPgoHead.prev = &pendingPgoHead;
5820
5821 // The kernel PRNG is not initialized when the first kext is
5822 // loaded, so use early random
5823 uuid_generate_early_random(instance_uuid);
5824 account = IOMallocType(OSKextAccount);
5825
5826 account->loadTag = kmod_info->id;
5827 account->site.refcount = 0;
5828 account->site.flags = VM_TAG_KMOD;
5829
5830 #if DEVELOPMENT || DEBUG
5831 /* Setup the task reference group. */
5832 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
5833 "task_%s", getIdentifierCString());
5834 account->task_refgrp.grp_name = account->task_refgrp_name;
5835 account->task_refgrp.grp_parent = &task_external_refgrp;
5836 os_ref_log_init(&account->task_refgrp);
5837 #endif /* DEVELOPMENT || DEBUG */
5838
5839 account->kext = this;
5840 if (gIOSurfaceIdentifier == bundleID) {
5841 vm_tag_alloc(&account->site);
5842 gIOSurfaceTag = account->site.tag;
5843 }
5844
5845 flags.loaded = true;
5846
5847 /* Add the kext to the list of loaded kexts and update the kmod_info
5848 * struct to point to that of the last loaded kext (which is the way
5849 * it's always been done, though I'd rather do them in order now).
5850 */
5851 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5852 sLoadedKexts->setObject(this);
5853
5854 /* Keep the kernel itself out of the kmod list.
5855 */
5856 if (lastLoadedKext->isKernel()) {
5857 lastLoadedKext = NULL;
5858 }
5859
5860 if (lastLoadedKext) {
5861 kmod_info->next = lastLoadedKext->kmod_info;
5862 }
5863
5864 notifyKextLoadObservers(this, kmod_info);
5865
5866 /* Make the global kmod list point at the just-loaded kext. Note that the
5867 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5868 * although we do report it in kextstat these days by using the newer
5869 * OSArray of loaded kexts, which does contain it.
5870 *
5871 * (The OSKext object representing the kernel doesn't even have a kmod_info
5872 * struct, though I suppose we could stick a pointer to it from the
5873 * static struct in OSRuntime.cpp.)
5874 */
5875 kmod = kmod_info;
5876
5877 /* Save the list of loaded kexts in case we panic.
5878 */
5879 OSKext::saveLoadedKextPanicList();
5880
5881 if (isExecutable()) {
5882 OSKext::updateLoadedKextSummaries();
5883 savePanicString(/* isLoading */ true);
5884
5885 #if CONFIG_DTRACE
5886 registerWithDTrace();
5887 #else
5888 jettisonLinkeditSegment();
5889 #endif /* CONFIG_DTRACE */
5890
5891 #if !VM_MAPPED_KEXTS
5892 /* If there is a page (or more) worth of padding after the end
5893 * of the last data section but before the end of the data segment
5894 * then free it in the same manner the LinkeditSegment is freed
5895 */
5896 jettisonDATASegmentPadding();
5897 #endif
5898 }
5899
5900 loaded:
5901 if (isExecutable() && !flags.started) {
5902 if (startOpt == kOSKextExcludeNone) {
5903 result = start();
5904 if (result != kOSReturnSuccess) {
5905 OSKextLog(this,
5906 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5907 "Kext %s start failed (result 0x%x).",
5908 getIdentifierCString(), result);
5909 result = kOSKextReturnStartStopError;
5910 }
5911 }
5912 }
5913
5914 /* If not excluding matching, send the personalities to the kernel.
5915 * This never affects the result of the load operation.
5916 * This is a bit of a hack, because we shouldn't be handling
5917 * personalities within the load function.
5918 */
5919 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5920 result = sendPersonalitiesToCatalog(true, personalityNames);
5921 }
5922
5923 finish:
5924
5925 if (result != kOSReturnSuccess) {
5926 OSKextLog(this,
5927 kOSKextLogErrorLevel |
5928 kOSKextLogLoadFlag,
5929 "Kext %s failed to load (0x%x).",
5930 getIdentifierCString(), (int)result);
5931 } else if (!alreadyLoaded) {
5932 OSKextLog(this,
5933 kOSKextLogProgressLevel |
5934 kOSKextLogLoadFlag,
5935 "Kext %s loaded.",
5936 getIdentifierCString());
5937
5938 queueKextNotification(kKextRequestPredicateLoadNotification,
5939 OSDynamicCast(OSString, bundleID.get()));
5940 }
5941 return result;
5942 }
5943
5944 #if CONFIG_KXLD
5945 /*********************************************************************
5946 *
5947 *********************************************************************/
5948 static char *
strdup(const char * string)5949 strdup(const char * string)
5950 {
5951 char * result = NULL;
5952 size_t size;
5953
5954 if (!string) {
5955 goto finish;
5956 }
5957
5958 size = 1 + strlen(string);
5959 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5960 if (!result) {
5961 goto finish;
5962 }
5963
5964 memcpy(result, string, size);
5965
5966 finish:
5967 return result;
5968 }
5969 #endif // CONFIG_KXLD
5970
5971 /*********************************************************************
5972 *
5973 *********************************************************************/
5974
5975 kernel_section_t *
lookupSection(const char * segname,const char * secname)5976 OSKext::lookupSection(const char *segname, const char *secname)
5977 {
5978 kernel_section_t * found_section = NULL;
5979 kernel_mach_header_t * mh = NULL;
5980 kernel_segment_command_t * seg = NULL;
5981 kernel_section_t * sec = NULL;
5982
5983 if (!linkedExecutable) {
5984 return NULL;
5985 }
5986
5987 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5988
5989 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5990 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
5991 continue;
5992 }
5993
5994 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5995 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
5996 found_section = sec;
5997 goto out;
5998 }
5999 }
6000 }
6001
6002 out:
6003 return found_section;
6004 }
6005
6006 /*********************************************************************
6007 *
6008 *********************************************************************/
6009
6010 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6011 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6012 {
6013 OSReturn result = kOSKextReturnBadData;
6014 kernel_mach_header_t * mh = NULL;
6015 kernel_segment_command_t * seg = NULL;
6016 kernel_segment_command_t * linkeditSeg = NULL;
6017 kernel_section_t * sec = NULL;
6018 char * linkeditBase = NULL;
6019 bool haveLinkeditBase = false;
6020 char * relocBase = NULL;
6021 bool haveRelocBase = false;
6022 struct dysymtab_command * dysymtab = NULL;
6023 struct linkedit_data_command * segmentSplitInfo = NULL;
6024 struct symtab_command * symtab = NULL;
6025 kernel_nlist_t * sym = NULL;
6026 struct relocation_info * reloc = NULL;
6027 uint32_t i = 0;
6028 int reloc_size;
6029 vm_offset_t new_kextsize;
6030
6031 if (linkedExecutable == NULL || flags.builtin) {
6032 result = kOSReturnSuccess;
6033 goto finish;
6034 }
6035
6036 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6037 if (kernel_mach_header_is_in_fileset(mh)) {
6038 // kexts in filesets are slid as part of collection sliding
6039 result = kOSReturnSuccess;
6040 goto finish;
6041 }
6042
6043 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6044
6045 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6046 if (!seg->vmaddr) {
6047 continue;
6048 }
6049
6050 seg->vmaddr = ml_static_slide(seg->vmaddr);
6051
6052 #if KASLR_KEXT_DEBUG
6053 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6054 seg->segname,
6055 (unsigned long)ml_static_unslide(seg->vmaddr),
6056 (unsigned long)seg->vmaddr);
6057 #endif
6058
6059 if (!haveRelocBase) {
6060 relocBase = (char *) seg->vmaddr;
6061 haveRelocBase = true;
6062 }
6063 if (!strcmp(seg->segname, "__LINKEDIT")) {
6064 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6065 haveLinkeditBase = true;
6066 linkeditSeg = seg;
6067 }
6068 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6069 sec->addr = ml_static_slide(sec->addr);
6070
6071 #if KASLR_KEXT_DEBUG
6072 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6073 sec->sectname,
6074 (unsigned long)ml_static_unslide(sec->addr),
6075 (unsigned long)sec->addr);
6076 #endif
6077 }
6078 }
6079
6080 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6081
6082 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6083
6084 if (symtab != NULL && doCoalescedSlides == false) {
6085 /* Some pseudo-kexts have symbol tables without segments.
6086 * Ignore them. */
6087 if (symtab->nsyms > 0 && haveLinkeditBase) {
6088 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6089 for (i = 0; i < symtab->nsyms; i++) {
6090 if (sym[i].n_type & N_STAB) {
6091 continue;
6092 }
6093 sym[i].n_value = ml_static_slide(sym[i].n_value);
6094
6095 #if KASLR_KEXT_DEBUG
6096 #define MAX_SYMS_TO_LOG 5
6097 if (i < MAX_SYMS_TO_LOG) {
6098 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6099 (unsigned long)ml_static_unslide(sym[i].n_value),
6100 (unsigned long)sym[i].n_value);
6101 }
6102 #endif
6103 }
6104 }
6105 }
6106
6107 if (dysymtab != NULL && doCoalescedSlides == false) {
6108 if (dysymtab->nextrel > 0) {
6109 OSKextLog(this,
6110 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6111 kOSKextLogLinkFlag,
6112 "Sliding kext %s: External relocations found.",
6113 getIdentifierCString());
6114 goto finish;
6115 }
6116
6117 if (dysymtab->nlocrel > 0) {
6118 if (!haveLinkeditBase) {
6119 OSKextLog(this,
6120 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6121 kOSKextLogLinkFlag,
6122 "Sliding kext %s: No linkedit segment.",
6123 getIdentifierCString());
6124 goto finish;
6125 }
6126
6127 if (!haveRelocBase) {
6128 OSKextLog(this,
6129 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6130 kOSKextLogLinkFlag,
6131 #if __x86_64__
6132 "Sliding kext %s: No writable segments.",
6133 #else
6134 "Sliding kext %s: No segments.",
6135 #endif
6136 getIdentifierCString());
6137 goto finish;
6138 }
6139
6140 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6141 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6142
6143 for (i = 0; i < dysymtab->nlocrel; i++) {
6144 if (reloc[i].r_extern != 0
6145 || reloc[i].r_type != 0
6146 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6147 ) {
6148 OSKextLog(this,
6149 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6150 kOSKextLogLinkFlag,
6151 "Sliding kext %s: Unexpected relocation found.",
6152 getIdentifierCString());
6153 goto finish;
6154 }
6155 if (reloc[i].r_pcrel != 0) {
6156 continue;
6157 }
6158 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6159 *relocAddr = ml_static_slide(*relocAddr);
6160
6161 #if KASLR_KEXT_DEBUG
6162 #define MAX_DYSYMS_TO_LOG 5
6163 if (i < MAX_DYSYMS_TO_LOG) {
6164 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6165 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6166 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6167 }
6168 #endif
6169 }
6170
6171 /* We should free these relocations, not just delete the reference to them.
6172 * <rdar://problem/10535549> Free relocations from PIE kexts.
6173 *
6174 * For now, we do not free LINKEDIT for kexts with split segments.
6175 */
6176 new_kextsize = round_page(kmod_info->size - reloc_size);
6177 if (new_kextsize > UINT_MAX) {
6178 OSKextLog(this,
6179 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6180 kOSKextLogLinkFlag,
6181 "Kext %s: new kext size is too large.",
6182 getIdentifierCString());
6183 goto finish;
6184 }
6185 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6186 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6187 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6188 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6189 size_t bytes_remaining = endofkext - endofrelocInfo;
6190 OSSharedPtr<OSData> new_osdata;
6191
6192 /* fix up symbol offsets if they are after the dsymtab local relocs */
6193 if (symtab) {
6194 if (dysymtab->locreloff < symtab->symoff) {
6195 symtab->symoff -= reloc_size;
6196 }
6197 if (dysymtab->locreloff < symtab->stroff) {
6198 symtab->stroff -= reloc_size;
6199 }
6200 }
6201 if (dysymtab->locreloff < dysymtab->extreloff) {
6202 dysymtab->extreloff -= reloc_size;
6203 }
6204
6205 /* move data behind reloc info down to new offset */
6206 if (endofrelocInfo < endofkext) {
6207 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6208 }
6209
6210 /* Create a new OSData for the smaller kext object and reflect
6211 * new linkedit segment size.
6212 */
6213 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6214 linkeditSeg->filesize = linkeditSeg->vmsize;
6215
6216 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6217 if (new_osdata) {
6218 /* Fix up kmod info and linkedExecutable.
6219 */
6220 kmod_info->size = new_kextsize;
6221 #if VM_MAPPED_KEXTS
6222 new_osdata->setDeallocFunction(osdata_kext_free);
6223 #else
6224 new_osdata->setDeallocFunction(osdata_phys_free);
6225 #endif
6226 linkedExecutable->setDeallocFunction(NULL);
6227 linkedExecutable = os::move(new_osdata);
6228
6229 #if VM_MAPPED_KEXTS
6230 kext_free(new_endofkext, (endofkext - new_endofkext));
6231 #else
6232 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6233 #endif
6234 }
6235 }
6236 dysymtab->nlocrel = 0;
6237 dysymtab->locreloff = 0;
6238 }
6239 }
6240
6241 result = kOSReturnSuccess;
6242 finish:
6243 return result;
6244 }
6245
6246 /*********************************************************************
6247 * called only by load()
6248 *********************************************************************/
6249 OSReturn
loadExecutable()6250 OSKext::loadExecutable()
6251 {
6252 OSReturn result = kOSReturnError;
6253 OSSharedPtr<OSArray> linkDependencies;
6254 uint32_t num_kmod_refs = 0;
6255 OSData * theExecutable = NULL; // do not release
6256 OSString * versString = NULL; // do not release
6257 const char * versCString = NULL; // do not free
6258 const char * string = NULL; // do not free
6259
6260 #if CONFIG_KXLD
6261 unsigned int i;
6262 uint32_t numDirectDependencies = 0;
6263 kern_return_t kxldResult;
6264 KXLDDependency * kxlddeps = NULL; // must kfree
6265 uint32_t num_kxlddeps = 0;
6266 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6267 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6268 #endif // CONFIG_KXLD
6269
6270 /* We need the version string for a variety of bits below.
6271 */
6272 versString = OSDynamicCast(OSString,
6273 getPropertyForHostArch(kCFBundleVersionKey));
6274 if (!versString) {
6275 goto finish;
6276 }
6277 versCString = versString->getCStringNoCopy();
6278
6279 if (isKernelComponent()) {
6280 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6281 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6282 OSKextLog(this,
6283 kOSKextLogErrorLevel |
6284 kOSKextLogLoadFlag,
6285 "Kernel component %s has incorrect version %s; "
6286 "expected %s.",
6287 getIdentifierCString(),
6288 versCString, KERNEL6_VERSION);
6289 result = kOSKextReturnInternalError;
6290 goto finish;
6291 } else if (strcmp(versCString, osrelease)) {
6292 OSKextLog(this,
6293 kOSKextLogErrorLevel |
6294 kOSKextLogLoadFlag,
6295 "Kernel component %s has incorrect version %s; "
6296 "expected %s.",
6297 getIdentifierCString(),
6298 versCString, osrelease);
6299 result = kOSKextReturnInternalError;
6300 goto finish;
6301 }
6302 }
6303 }
6304
6305 #if defined(__x86_64__) || defined(__i386__)
6306 if (flags.resetSegmentsFromVnode) {
6307 /* Fixup the chains and slide the mach headers */
6308 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6309
6310 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6311 result = kOSKextReturnValidation;
6312 goto finish;
6313 }
6314 }
6315 #endif //(__x86_64__) || defined(__i386__)
6316
6317 if (isPrelinked()) {
6318 goto register_kmod;
6319 }
6320
6321 /* <rdar://problem/21444003> all callers must be entitled */
6322 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
6323 OSKextLog(this,
6324 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6325 "Not entitled to link kext '%s'",
6326 getIdentifierCString());
6327 result = kOSKextReturnNotPrivileged;
6328 goto finish;
6329 }
6330
6331 theExecutable = getExecutable();
6332 if (!theExecutable) {
6333 if (declaresExecutable()) {
6334 OSKextLog(this,
6335 kOSKextLogErrorLevel |
6336 kOSKextLogLoadFlag,
6337 "Can't load kext %s - executable is missing.",
6338 getIdentifierCString());
6339 result = kOSKextReturnValidation;
6340 goto finish;
6341 }
6342 goto register_kmod;
6343 }
6344
6345 if (isInterface()) {
6346 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6347 if (executableCopy) {
6348 setLinkedExecutable(executableCopy.get());
6349 }
6350 goto register_kmod;
6351 }
6352
6353 #if CONFIG_KXLD
6354 numDirectDependencies = getNumDependencies();
6355
6356 if (flags.hasBleedthrough) {
6357 linkDependencies = dependencies;
6358 } else {
6359 linkDependencies = OSArray::withArray(dependencies.get());
6360 if (!linkDependencies) {
6361 OSKextLog(this,
6362 kOSKextLogErrorLevel |
6363 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6364 "Can't allocate link dependencies to load kext %s.",
6365 getIdentifierCString());
6366 goto finish;
6367 }
6368
6369 for (i = 0; i < numDirectDependencies; ++i) {
6370 OSKext * dependencyKext = OSDynamicCast(OSKext,
6371 dependencies->getObject(i));
6372 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
6373 }
6374 }
6375
6376 num_kxlddeps = linkDependencies->getCount();
6377 if (!num_kxlddeps) {
6378 OSKextLog(this,
6379 kOSKextLogErrorLevel |
6380 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6381 "Can't load kext %s - it has no library dependencies.",
6382 getIdentifierCString());
6383 goto finish;
6384 }
6385
6386 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6387 if (!kxlddeps) {
6388 OSKextLog(this,
6389 kOSKextLogErrorLevel |
6390 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6391 "Can't allocate link context to load kext %s.",
6392 getIdentifierCString());
6393 goto finish;
6394 }
6395 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6396
6397 for (i = 0; i < num_kxlddeps; ++i) {
6398 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6399
6400 if (dependency->isInterface()) {
6401 OSKext *interfaceTargetKext = NULL; //do not release
6402 OSData * interfaceTarget = NULL; //do not release
6403
6404 if (dependency->isKernelComponent()) {
6405 interfaceTargetKext = sKernelKext;
6406 interfaceTarget = sKernelKext->linkedExecutable.get();
6407 } else {
6408 interfaceTargetKext = OSDynamicCast(OSKext,
6409 dependency->dependencies->getObject(0));
6410
6411 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
6412 }
6413
6414 if (!interfaceTarget) {
6415 // panic?
6416 goto finish;
6417 }
6418
6419 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6420 * it will be useful to have them in the debugger.
6421 * strdup() failing isn't critical right here so we don't check that.
6422 */
6423 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6424 kxlddeps[i].kext_size = interfaceTarget->getLength();
6425 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6426
6427 if (dependency->linkedExecutable != NULL) {
6428 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6429 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6430 } else {
6431 kxlddeps[i].interface = (u_char *) NULL;
6432 kxlddeps[i].interface_size = 0;
6433 }
6434 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6435 } else {
6436 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6437 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6438 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6439 }
6440
6441 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6442 }
6443
6444 kxldHeaderPtr = &kxld_header;
6445
6446 #if DEBUG
6447 OSKextLog(this,
6448 kOSKextLogExplicitLevel |
6449 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6450 "Kext %s - calling kxld_link_file:\n"
6451 " kxld_context: %p\n"
6452 " executable: %p executable_length: %d\n"
6453 " user_data: %p\n"
6454 " kxld_dependencies: %p num_dependencies: %d\n"
6455 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6456 getIdentifierCString(), sKxldContext,
6457 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6458 this, kxlddeps, num_kxlddeps,
6459 kxldHeaderPtr, &kmod_info);
6460 #endif
6461
6462 /* After this call, the linkedExecutable instance variable
6463 * should exist.
6464 */
6465 kxldResult = kxld_link_file(sKxldContext,
6466 (u_char *)theExecutable->getBytesNoCopy(),
6467 theExecutable->getLength(),
6468 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6469 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6470
6471 if (kxldResult != KERN_SUCCESS) {
6472 // xxx - add kxldResult here?
6473 OSKextLog(this,
6474 kOSKextLogErrorLevel |
6475 kOSKextLogLoadFlag,
6476 "Can't load kext %s - link failed.",
6477 getIdentifierCString());
6478 result = kOSKextReturnLinkError;
6479 goto finish;
6480 }
6481
6482 /* We've written data & instructions into kernel memory, so flush the data
6483 * cache and invalidate the instruction cache.
6484 * I/D caches are coherent on x86
6485 */
6486 #if !defined(__i386__) && !defined(__x86_64__)
6487 flush_dcache(kmod_info->address, kmod_info->size, false);
6488 invalidate_icache(kmod_info->address, kmod_info->size, false);
6489 #endif
6490
6491 #else // !CONFIG_KXLD
6492 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6493 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6494 result = kOSKextReturnLinkError;
6495 goto finish;
6496 #endif // CONFIG_KXLD
6497
6498 register_kmod:
6499
6500 if (isInterface()) {
6501 /* Whip up a fake kmod_info entry for the interface kext.
6502 */
6503 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
6504 if (!kmod_info) {
6505 result = KERN_MEMORY_ERROR;
6506 goto finish;
6507 }
6508
6509 /* A pseudokext has almost nothing in its kmod_info struct.
6510 */
6511 kmod_info->info_version = KMOD_INFO_VERSION;
6512
6513 /* An interface kext doesn't have a linkedExecutable, so save a
6514 * copy of the UUID out of the original executable via copyUUID()
6515 * while we still have the original executable.
6516 */
6517 interfaceUUID = copyUUID();
6518 }
6519
6520 kmod_info->id = loadTag = sNextLoadTag++;
6521 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
6522
6523 /* Stamp the bundle ID and version from the OSKext over anything
6524 * resident inside the kmod_info.
6525 */
6526 string = getIdentifierCString();
6527 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6528
6529 string = versCString;
6530 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6531
6532 /* Add the dependencies' kmod_info structs as kmod_references.
6533 */
6534 num_kmod_refs = getNumDependencies();
6535 if (num_kmod_refs) {
6536 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
6537 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
6538 if (!kmod_info->reference_list) {
6539 result = KERN_MEMORY_ERROR;
6540 goto finish;
6541 }
6542 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6543 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6544 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6545 ref->info = refKext->kmod_info;
6546 ref->info->reference_count++;
6547
6548 if (refIndex + 1 < num_kmod_refs) {
6549 ref->next = kmod_info->reference_list + refIndex + 1;
6550 }
6551 }
6552 }
6553
6554 if (kmod_info->hdr_size > UINT32_MAX) {
6555 OSKextLog(this,
6556 kOSKextLogErrorLevel |
6557 kOSKextLogLoadFlag,
6558 #if __LP64__
6559 "Kext %s header size is too large (%lu > UINT32_MAX).",
6560 #else
6561 "Kext %s header size is too large (%u > UINT32_MAX).",
6562 #endif
6563 kmod_info->name,
6564 kmod_info->hdr_size);
6565 result = KERN_FAILURE;
6566 goto finish;
6567 }
6568
6569 if (kmod_info->size > UINT32_MAX) {
6570 OSKextLog(this,
6571 kOSKextLogErrorLevel |
6572 kOSKextLogLoadFlag,
6573 #if __LP64__
6574 "Kext %s size is too large (%lu > UINT32_MAX).",
6575 #else
6576 "Kext %s size is too large (%u > UINT32_MAX).",
6577 #endif
6578 kmod_info->name,
6579 kmod_info->size);
6580 result = KERN_FAILURE;
6581 goto finish;
6582 }
6583
6584 if (!isInterface() && linkedExecutable) {
6585 OSKextLog(this,
6586 kOSKextLogProgressLevel |
6587 kOSKextLogLoadFlag,
6588 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6589 kmod_info->name,
6590 (unsigned)kmod_info->size / PAGE_SIZE,
6591 (unsigned long)ml_static_unslide(kmod_info->address),
6592 (unsigned)kmod_info->id);
6593 }
6594
6595 /* VM protections and wiring for the Aux KC are done at collection loading time */
6596 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6597 /* if prelinked and primary KC, VM protections are already set */
6598 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6599 if (result != KERN_SUCCESS) {
6600 goto finish;
6601 }
6602 }
6603
6604 #if KASAN
6605 if (linkedExecutable) {
6606 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6607 linkedExecutable->getLength(), getIdentifierCString());
6608 }
6609 #else
6610 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6611 OSKextLog(this,
6612 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6613 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6614 getIdentifierCString()
6615 );
6616 result = KERN_FAILURE;
6617 goto finish;
6618 }
6619 #endif
6620
6621 result = kOSReturnSuccess;
6622
6623 finish:
6624
6625 #if CONFIG_KXLD
6626 /* Clear up locally allocated dependency info.
6627 */
6628 for (i = 0; i < num_kxlddeps; ++i) {
6629 size_t size;
6630
6631 if (kxlddeps[i].kext_name) {
6632 size = 1 + strlen(kxlddeps[i].kext_name);
6633 kfree_data(kxlddeps[i].kext_name, size);
6634 }
6635 if (kxlddeps[i].interface_name) {
6636 size = 1 + strlen(kxlddeps[i].interface_name);
6637 kfree_data(kxlddeps[i].interface_name, size);
6638 }
6639 }
6640 if (kxlddeps) {
6641 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
6642 }
6643 #endif // CONFIG_KXLD
6644
6645 /* We no longer need the unrelocated executable (which the linker
6646 * has altered anyhow).
6647 */
6648 setExecutable(NULL);
6649
6650 if (result != kOSReturnSuccess) {
6651 OSKextLog(this,
6652 kOSKextLogErrorLevel |
6653 kOSKextLogLoadFlag,
6654 "Failed to load executable for kext %s.",
6655 getIdentifierCString());
6656
6657 if (kmod_info && kmod_info->reference_list) {
6658 kfree_type(kmod_reference_t, num_kmod_refs,
6659 kmod_info->reference_list);
6660 }
6661 if (isInterface()) {
6662 kfree_type(kmod_info_t, kmod_info);
6663 kmod_info = NULL;
6664 }
6665 if (kc_type == KCKindUnknown) {
6666 kmod_info = NULL;
6667 if (linkedExecutable) {
6668 linkedExecutable.reset();
6669 }
6670 }
6671 }
6672
6673 return result;
6674 }
6675
6676 /* static */
6677 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)6678 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6679 {
6680 kernel_segment_command_t *linkeditseg = NULL;
6681
6682 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6683 if (linkeditseg == NULL) {
6684 panic("FileSet booted with no Linkedit segment");
6685 }
6686
6687 #if VM_MAPPED_KEXTS
6688 /* BootKC on x86_64 is not vm mapped */
6689 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6690
6691 OSKextLog(/* kext */ NULL,
6692 kOSKextLogProgressLevel |
6693 kOSKextLogGeneralFlag,
6694 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6695 linkeditseg->vmaddr, linkeditseg->vmsize);
6696 #else
6697 /* BootKC on arm64 is not vm mapped, but is slid */
6698 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
6699
6700 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
6701
6702 OSKextLog(/* kext */ NULL,
6703 kOSKextLogProgressLevel |
6704 kOSKextLogGeneralFlag,
6705 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6706 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
6707 #endif /* VM_MAPPED_KEXTS */
6708 }
6709
6710 /*********************************************************************
6711 * The linkedit segment is used by the kext linker for dependency
6712 * resolution, and by dtrace for probe initialization. We can free it
6713 * for non-library kexts, since no kexts depend on non-library kexts
6714 * by definition, once dtrace has been initialized.
6715 *********************************************************************/
6716 void
jettisonLinkeditSegment(void)6717 OSKext::jettisonLinkeditSegment(void)
6718 {
6719 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6720 kernel_segment_command_t * linkedit = NULL;
6721 vm_offset_t start;
6722 vm_size_t linkeditsize, kextsize;
6723 OSSharedPtr<OSData> data;
6724
6725 if (isInFileset()) {
6726 return;
6727 }
6728
6729 #if NO_KEXTD
6730 /* We can free symbol tables for all embedded kexts because we don't
6731 * support runtime kext linking.
6732 */
6733 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6734 #else
6735 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6736 #endif
6737 goto finish;
6738 }
6739
6740 /* Find the linkedit segment. If it's not the last segment, then freeing
6741 * it will fragment the kext into multiple VM regions, which OSKext is not
6742 * designed to handle, so we'll have to skip it.
6743 */
6744 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6745 if (!linkedit) {
6746 goto finish;
6747 }
6748
6749 if (round_page(kmod_info->address + kmod_info->size) !=
6750 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6751 goto finish;
6752 }
6753
6754 /* Create a new OSData for the smaller kext object.
6755 */
6756 linkeditsize = round_page(linkedit->vmsize);
6757 kextsize = kmod_info->size - linkeditsize;
6758 start = linkedit->vmaddr;
6759
6760 if (kextsize > UINT_MAX) {
6761 goto finish;
6762 }
6763 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6764 if (!data) {
6765 goto finish;
6766 }
6767
6768 /* Fix the kmod info and linkedExecutable.
6769 */
6770 kmod_info->size = kextsize;
6771
6772 #if VM_MAPPED_KEXTS
6773 data->setDeallocFunction(osdata_kext_free);
6774 #else
6775 data->setDeallocFunction(osdata_phys_free);
6776 #endif
6777 linkedExecutable->setDeallocFunction(NULL);
6778 linkedExecutable = os::move(data);
6779 flags.jettisonLinkeditSeg = 1;
6780
6781 /* Free the linkedit segment.
6782 */
6783 #if VM_MAPPED_KEXTS
6784 kext_free(start, linkeditsize);
6785 #else
6786 ml_static_mfree(start, linkeditsize);
6787 #endif
6788
6789 finish:
6790 return;
6791 }
6792
6793 /*********************************************************************
6794 * If there are whole pages that are unused betweem the last section
6795 * of the DATA segment and the end of the DATA segment then we can free
6796 * them
6797 *********************************************************************/
6798 void
6799 OSKext::jettisonDATASegmentPadding(void)
6800 {
6801 kernel_mach_header_t * mh;
6802 kernel_segment_command_t * dataSeg;
6803 kernel_section_t * sec, * lastSec;
6804 vm_offset_t dataSegEnd, lastSecEnd;
6805 vm_size_t padSize;
6806
6807 if (flags.builtin) {
6808 return;
6809 }
6810 mh = (kernel_mach_header_t *)kmod_info->address;
6811
6812 if (isInFileset()) {
6813 return;
6814 }
6815
6816 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6817 if (dataSeg == NULL) {
6818 return;
6819 }
6820
6821 lastSec = NULL;
6822 sec = firstsect(dataSeg);
6823 while (sec != NULL) {
6824 lastSec = sec;
6825 sec = nextsect(dataSeg, sec);
6826 }
6827
6828 if (lastSec == NULL) {
6829 return;
6830 }
6831
6832 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6833 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6834 return;
6835 }
6836
6837 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6838 lastSecEnd = round_page(lastSec->addr + lastSec->size);
6839
6840 if (dataSegEnd <= lastSecEnd) {
6841 return;
6842 }
6843
6844 padSize = dataSegEnd - lastSecEnd;
6845
6846 if (padSize >= PAGE_SIZE) {
6847 #if VM_MAPPED_KEXTS
6848 kext_free(lastSecEnd, padSize);
6849 #else
6850 ml_static_mfree(lastSecEnd, padSize);
6851 #endif
6852 }
6853 }
6854
6855 /*********************************************************************
6856 *********************************************************************/
6857 void
6858 OSKext::setLinkedExecutable(OSData * anExecutable)
6859 {
6860 if (linkedExecutable) {
6861 panic("Attempt to set linked executable on kext "
6862 "that already has one (%s).\n",
6863 getIdentifierCString());
6864 }
6865 linkedExecutable.reset(anExecutable, OSRetain);
6866 return;
6867 }
6868
6869 #if CONFIG_DTRACE
6870 /*********************************************************************
6871 * Go through all loaded kexts and tell them to register with dtrace.
6872 * The instance method only registers if necessary.
6873 *********************************************************************/
6874 /* static */
6875 void
6876 OSKext::registerKextsWithDTrace(void)
6877 {
6878 uint32_t count = sLoadedKexts->getCount();
6879 uint32_t i;
6880
6881 IORecursiveLockLock(sKextLock);
6882
6883 for (i = 0; i < count; i++) {
6884 OSKext * thisKext = NULL; // do not release
6885
6886 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6887 if (!thisKext || !thisKext->isExecutable()) {
6888 continue;
6889 }
6890
6891 thisKext->registerWithDTrace();
6892 }
6893
6894 IORecursiveLockUnlock(sKextLock);
6895
6896 return;
6897 }
6898
6899 extern "C" {
6900 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6901 extern int (*dtrace_modunload)(struct kmod_info *);
6902 };
6903
6904 /*********************************************************************
6905 *********************************************************************/
6906 void
6907 OSKext::registerWithDTrace(void)
6908 {
6909 /* Register kext with dtrace. A dtrace_modload failure should not
6910 * prevent a kext from loading, so we ignore the return code.
6911 */
6912 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6913 uint32_t modflag = 0;
6914 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
6915
6916 #if XNU_TARGET_OS_OSX
6917 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6918 if (forceInit == kOSBooleanTrue) {
6919 OSKextLog(this,
6920 kOSKextLogBasicLevel |
6921 kOSKextLogGeneralFlag,
6922 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
6923 getIdentifierCString());
6924 forceInit = kOSBooleanFalse;
6925 }
6926 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6927 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6928 }
6929 #endif /* XNU_TARGET_OS_OSX */
6930 if (forceInit == kOSBooleanTrue) {
6931 modflag |= KMOD_DTRACE_FORCE_INIT;
6932 }
6933 if (flags.builtin) {
6934 modflag |= KMOD_DTRACE_STATIC_KEXT;
6935 }
6936
6937 (void)(*dtrace_modload)(kmod_info, modflag);
6938 flags.dtraceInitialized = true;
6939 jettisonLinkeditSegment();
6940 }
6941 return;
6942 }
6943 /*********************************************************************
6944 *********************************************************************/
6945 void
6946 OSKext::unregisterWithDTrace(void)
6947 {
6948 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6949 * prevent a kext from loading, so we ignore the return code.
6950 */
6951 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6952 (void)(*dtrace_modunload)(kmod_info);
6953 flags.dtraceInitialized = false;
6954 }
6955 return;
6956 }
6957 #endif /* CONFIG_DTRACE */
6958
6959
6960 /*********************************************************************
6961 * called only by loadExecutable()
6962 *********************************************************************/
6963 #if !VM_MAPPED_KEXTS
6964 #if defined(__arm__) || defined(__arm64__)
6965 static inline kern_return_t
6966 OSKext_protect(
6967 kernel_mach_header_t *kext_mh,
6968 vm_map_t map,
6969 vm_map_offset_t start,
6970 vm_map_offset_t end,
6971 vm_prot_t new_prot,
6972 boolean_t set_max,
6973 kc_kind_t kc_type)
6974 {
6975 #pragma unused(kext_mh,map,kc_type)
6976 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
6977 assert(start <= end);
6978 if (start >= end) {
6979 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6980 } else if (set_max) {
6981 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
6982 } else {
6983 return ml_static_protect(start, end - start, new_prot);
6984 }
6985 }
6986
6987 static inline kern_return_t
6988 OSKext_wire(
6989 kernel_mach_header_t *kext_mh,
6990 vm_map_t map,
6991 vm_map_offset_t start,
6992 vm_map_offset_t end,
6993 vm_prot_t access_type,
6994 boolean_t user_wire,
6995 kc_kind_t kc_type)
6996 {
6997 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6998 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
6999 }
7000 #else
7001 #error Unrecognized architecture
7002 #endif
7003 #else
7004 static inline kern_return_t
7005 OSKext_protect(
7006 kernel_mach_header_t *kext_mh,
7007 vm_map_t map,
7008 vm_map_offset_t start,
7009 vm_map_offset_t end,
7010 vm_prot_t new_prot,
7011 boolean_t set_max,
7012 kc_kind_t kc_type)
7013 {
7014 if (start == end) { // 10538581
7015 return KERN_SUCCESS;
7016 }
7017 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7018 /*
7019 * XXX: This will probably need to be different for AuxKC and
7020 * pageableKC!
7021 */
7022 return ml_static_protect(start, end - start, new_prot);
7023 }
7024 return vm_map_protect(map, start, end, new_prot, set_max);
7025 }
7026
7027 static inline kern_return_t
7028 OSKext_wire(
7029 kernel_mach_header_t *kext_mh,
7030 vm_map_t map,
7031 vm_map_offset_t start,
7032 vm_map_offset_t end,
7033 vm_prot_t access_type,
7034 boolean_t user_wire,
7035 kc_kind_t kc_type)
7036 {
7037 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7038 /* TODO: we may need to hook this for the pageableKC */
7039 return KERN_SUCCESS;
7040 }
7041 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7042 }
7043 #endif
7044
7045 OSReturn
7046 OSKext::setVMAttributes(bool protect, bool wire)
7047 {
7048 vm_map_t kext_map = NULL;
7049 kernel_segment_command_t * seg = NULL;
7050 vm_map_offset_t start_protect = 0;
7051 vm_map_offset_t start_wire = 0;
7052 vm_map_offset_t end_protect = 0;
7053 vm_map_offset_t end_wire = 0;
7054 OSReturn result = kOSReturnError;
7055
7056 if (isInterface() || !declaresExecutable() || flags.builtin) {
7057 result = kOSReturnSuccess;
7058 goto finish;
7059 }
7060
7061 /* Get the kext's vm map */
7062 kext_map = kext_get_vm_map(kmod_info);
7063 if (!kext_map) {
7064 result = KERN_MEMORY_ERROR;
7065 goto finish;
7066 }
7067
7068 #if !VM_MAPPED_KEXTS
7069 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7070 /* This is a split kext in a prelinked kernelcache; we'll let the
7071 * platform code take care of protecting it. It is already wired.
7072 */
7073 /* TODO: Should this still allow protections for the first segment
7074 * to go through, in the event that we have a mix of split and
7075 * unsplit kexts?
7076 */
7077 result = KERN_SUCCESS;
7078 goto finish;
7079 }
7080
7081 if (isInFileset() && kc_type != KCKindPageable) {
7082 // kexts in filesets have protections setup as part of collection loading
7083 result = KERN_SUCCESS;
7084 goto finish;
7085 }
7086 #endif
7087
7088 /* Protect the headers as read-only; they do not need to be wired */
7089 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7090 kext_map, kmod_info->address,
7091 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7092 : KERN_SUCCESS;
7093 if (result != KERN_SUCCESS) {
7094 goto finish;
7095 }
7096
7097 /* Set the VM protections and wire down each of the segments */
7098 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7099 while (seg) {
7100 #if __arm__
7101 /* We build all ARM kexts, so we can ensure they are aligned */
7102 assert((seg->vmaddr & PAGE_MASK) == 0);
7103 assert((seg->vmsize & PAGE_MASK) == 0);
7104 #endif
7105
7106 /*
7107 * For the non page aligned segments, the range calculation for protection
7108 * and wiring differ as follows:
7109 *
7110 * Protection: The non page aligned data at the start or at the end of the
7111 * segment is excluded from the protection. This exclusion is needed to make
7112 * sure OSKext_protect is not called twice on same page, if the page is shared
7113 * between two segments.
7114 *
7115 * Wiring: The non page aligned data at the start or at the end of the
7116 * segment is included in the wiring range, this inclusion is needed to make sure
7117 * all the data of the segment is wired.
7118 */
7119 start_protect = round_page(seg->vmaddr);
7120 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7121
7122 start_wire = trunc_page(seg->vmaddr);
7123 end_wire = round_page(seg->vmaddr + seg->vmsize);
7124
7125 /*
7126 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7127 * across kexts and data from kexts is not page aligned
7128 */
7129 if (protect && (end_protect > start_protect) &&
7130 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7131 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7132 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7133 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7134 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7135 if (result != KERN_SUCCESS) {
7136 OSKextLog(this,
7137 kOSKextLogErrorLevel |
7138 kOSKextLogLoadFlag,
7139 "Kext %s failed to set maximum VM protections "
7140 "for segment %s - 0x%x.",
7141 getIdentifierCString(), seg->segname, (int)result);
7142 goto finish;
7143 }
7144
7145 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7146 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7147 if (result != KERN_SUCCESS) {
7148 OSKextLog(this,
7149 kOSKextLogErrorLevel |
7150 kOSKextLogLoadFlag,
7151 "Kext %s failed to set initial VM protections "
7152 "for segment %s - 0x%x.",
7153 getIdentifierCString(), seg->segname, (int)result);
7154 goto finish;
7155 }
7156 }
7157
7158 if (segmentShouldBeWired(seg) && wire) {
7159 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7160 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7161 if (result != KERN_SUCCESS) {
7162 goto finish;
7163 }
7164 }
7165
7166 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7167 }
7168
7169 finish:
7170 return result;
7171 }
7172
7173 /*********************************************************************
7174 *********************************************************************/
7175 boolean_t
7176 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7177 {
7178 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7179 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7180 }
7181
7182 /*********************************************************************
7183 *********************************************************************/
7184 OSReturn
7185 OSKext::validateKextMapping(bool startFlag)
7186 {
7187 OSReturn result = kOSReturnError;
7188 const char * whichOp = startFlag ? "start" : "stop";
7189 kern_return_t kern_result = 0;
7190 vm_map_t kext_map = NULL;
7191 kernel_segment_command_t * seg = NULL;
7192 mach_vm_address_t address = 0;
7193 mach_vm_size_t size = 0;
7194 uint32_t depth = 0;
7195 uint64_t kext_segbase = 0;
7196 uint64_t kext_segsize = 0;
7197 mach_msg_type_number_t count;
7198 vm_region_submap_short_info_data_64_t info;
7199 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7200
7201 if (flags.builtin) {
7202 return kOSReturnSuccess;
7203 }
7204
7205 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7206 bzero(&info, sizeof(info));
7207
7208 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7209 // xxx - sufficient?
7210
7211 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7212 */
7213 if (!kmod_info) {
7214 OSKextLog(this,
7215 kOSKextLogErrorLevel |
7216 kOSKextLogLoadFlag,
7217 "Kext %s - NULL kmod_info pointer.",
7218 getIdentifierCString());
7219 result = kOSKextReturnBadData;
7220 goto finish;
7221 }
7222
7223 if (startFlag) {
7224 address = (mach_vm_address_t)kmod_info->start;
7225 } else {
7226 address = (mach_vm_address_t)kmod_info->stop;
7227 }
7228
7229 if (!address) {
7230 OSKextLog(this,
7231 kOSKextLogErrorLevel |
7232 kOSKextLogLoadFlag,
7233 "Kext %s - NULL module %s pointer.",
7234 getIdentifierCString(), whichOp);
7235 result = kOSKextReturnBadData;
7236 goto finish;
7237 }
7238
7239 kext_map = kext_get_vm_map(kmod_info);
7240 depth = (kernel_map == kext_map) ? 1 : 2;
7241 if (isInFileset()) {
7242 #if defined(HAS_APPLE_PAC)
7243 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7244 #endif /* defined(HAS_APPLE_PAC) */
7245 }
7246
7247 /* Verify that the start/stop function lies within the kext's address range.
7248 */
7249 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7250 isInFileset()) {
7251 /* This will likely be how we deal with split kexts; walk the segments to
7252 * check that the function lies inside one of the segments of this kext.
7253 */
7254 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7255 seg != NULL;
7256 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7257 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7258 kext_segbase = seg->vmaddr;
7259 kext_segsize = seg->vmsize;
7260 break;
7261 }
7262 }
7263
7264 if (!seg) {
7265 OSKextLog(this,
7266 kOSKextLogErrorLevel |
7267 kOSKextLogLoadFlag,
7268 "Kext %s module %s pointer is outside of kext range "
7269 "(%s %p - kext starts at %p).",
7270 getIdentifierCString(),
7271 whichOp,
7272 whichOp,
7273 (void *)(((uintptr_t)address) - kext_slide),
7274 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7275 result = kOSKextReturnBadData;
7276 goto finish;
7277 }
7278
7279 seg = NULL;
7280 } else {
7281 if (address < kmod_info->address + kmod_info->hdr_size ||
7282 kmod_info->address + kmod_info->size <= address) {
7283 OSKextLog(this,
7284 kOSKextLogErrorLevel |
7285 kOSKextLogLoadFlag,
7286 "Kext %s module %s pointer is outside of kext range "
7287 "(%s %p - kext at %p-%p).",
7288 getIdentifierCString(),
7289 whichOp,
7290 whichOp,
7291 (void *)(((uintptr_t)address) - kext_slide),
7292 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7293 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7294 result = kOSKextReturnBadData;
7295 goto finish;
7296 }
7297 }
7298
7299 /* Only do these checks before calling the start function;
7300 * If anything goes wrong with the mapping while the kext is running,
7301 * we'll likely have panicked well before any attempt to stop the kext.
7302 */
7303 if (startFlag) {
7304 if (!isInFileset() || kc_type != KCKindPrimary) {
7305 /*
7306 * Verify that the start/stop function is executable.
7307 */
7308 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7309 (vm_region_recurse_info_t)&info, &count);
7310 if (kern_result != KERN_SUCCESS) {
7311 OSKextLog(this,
7312 kOSKextLogErrorLevel |
7313 kOSKextLogLoadFlag,
7314 "Kext %s - bad %s pointer %p.",
7315 getIdentifierCString(),
7316 whichOp, (void *)ml_static_unslide(address));
7317 result = kOSKextReturnBadData;
7318 goto finish;
7319 }
7320 } else {
7321 /*
7322 * Since kexts loaded from the primary KC are held in memory
7323 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7324 * discover that memory's protection flags. Instead, we need to
7325 * get that information from the kernel pmap itself. Above, we
7326 * (potentially) saved the size of the segment in which the address
7327 * in question was located. If we have a non-zero size, verify
7328 * that all pages in the (address, address + kext_segsize) range
7329 * are marked executable. If we somehow did not record the size
7330 * (or the base) just verify the single page that includes the address.
7331 */
7332 if (kext_segbase == 0 || kext_segsize == 0) {
7333 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7334 kext_segsize = PAGE_SIZE;
7335 }
7336 }
7337
7338 #if VM_MAPPED_KEXTS
7339 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7340 ((isInFileset() && kc_type == KCKindPrimary) &&
7341 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
7342 OSKextLog(this,
7343 kOSKextLogErrorLevel |
7344 kOSKextLogLoadFlag,
7345 "Kext %s - memory region containing module %s function "
7346 "is not executable.",
7347 getIdentifierCString(), whichOp);
7348 result = kOSKextReturnBadData;
7349 goto finish;
7350 }
7351 #endif
7352
7353 /* Verify that the kext's segments are backed by physical memory.
7354 */
7355 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7356 while (seg) {
7357 if (!verifySegmentMapping(seg)) {
7358 result = kOSKextReturnBadData;
7359 goto finish;
7360 }
7361
7362 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7363 }
7364 }
7365
7366 result = kOSReturnSuccess;
7367 finish:
7368 return result;
7369 }
7370
7371 /*********************************************************************
7372 *********************************************************************/
7373 boolean_t
7374 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7375 {
7376 mach_vm_address_t address = 0;
7377
7378 if (seg->vmsize > UINT32_MAX) {
7379 return false;
7380 }
7381
7382 if (!segmentShouldBeWired(seg)) {
7383 return true;
7384 }
7385
7386 for (address = seg->vmaddr;
7387 address < round_page(seg->vmaddr + seg->vmsize);
7388 address += PAGE_SIZE) {
7389 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7390 OSKextLog(this,
7391 kOSKextLogErrorLevel |
7392 kOSKextLogLoadFlag,
7393 "Kext %s - page %p is not backed by physical memory.",
7394 getIdentifierCString(),
7395 (void *)address);
7396 return false;
7397 }
7398 }
7399
7400 return true;
7401 }
7402
7403 /*********************************************************************
7404 *********************************************************************/
7405 static void
7406 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7407 {
7408 uint64_t stamp = 0;
7409 firehose_tracepoint_id_u trace_id;
7410 struct firehose_trace_uuid_info_s uuid_info_s;
7411 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7412 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
7413 OSSharedPtr<OSData> uuid_data;
7414
7415 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7416 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
7417
7418 uuid_data = aKext->copyTextUUID();
7419 if (uuid_data) {
7420 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
7421 }
7422
7423 uuid_info->ftui_size = size;
7424 if (aKext->isDriverKit()) {
7425 uuid_info->ftui_address = address;
7426 } else {
7427 uuid_info->ftui_address = ml_static_unslide(address);
7428 }
7429 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7430 return;
7431 }
7432
7433 void
7434 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7435 {
7436 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7437 }
7438
7439 /*********************************************************************
7440 *********************************************************************/
7441 OSReturn
7442 OSKext::start(bool startDependenciesFlag)
7443 {
7444 OSReturn result = kOSReturnError;
7445 kern_return_t (* startfunc)(kmod_info_t *, void *);
7446 unsigned int i, count;
7447 void * kmodStartData = NULL;
7448
7449 if (isStarted() || isInterface() || isKernelComponent()) {
7450 result = kOSReturnSuccess;
7451 goto finish;
7452 }
7453
7454 if (!isLoaded()) {
7455 OSKextLog(this,
7456 kOSKextLogErrorLevel |
7457 kOSKextLogLoadFlag,
7458 "Attempt to start nonloaded kext %s.",
7459 getIdentifierCString());
7460 result = kOSKextReturnInvalidArgument;
7461 goto finish;
7462 }
7463
7464 if (!sLoadEnabled) {
7465 OSKextLog(this,
7466 kOSKextLogErrorLevel |
7467 kOSKextLogLoadFlag,
7468 "Kext loading is disabled (attempt to start kext %s).",
7469 getIdentifierCString());
7470 result = kOSKextReturnDisabled;
7471 goto finish;
7472 }
7473
7474 result = validateKextMapping(/* start? */ true);
7475 if (result != kOSReturnSuccess) {
7476 goto finish;
7477 }
7478
7479 startfunc = kmod_info->start;
7480
7481 count = getNumDependencies();
7482 for (i = 0; i < count; i++) {
7483 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7484 if (dependency == NULL) {
7485 OSKextLog(this,
7486 kOSKextLogErrorLevel |
7487 kOSKextLogLoadFlag,
7488 "Kext %s start - internal error, dependency disappeared.",
7489 getIdentifierCString());
7490 goto finish;
7491 }
7492 if (!dependency->isStarted()) {
7493 if (startDependenciesFlag) {
7494 OSReturn dependencyResult =
7495 dependency->start(startDependenciesFlag);
7496 if (dependencyResult != KERN_SUCCESS) {
7497 OSKextLog(this,
7498 kOSKextLogErrorLevel |
7499 kOSKextLogLoadFlag,
7500 "Kext %s start - dependency %s failed to start (error 0x%x).",
7501 getIdentifierCString(),
7502 dependency->getIdentifierCString(),
7503 dependencyResult);
7504 goto finish;
7505 }
7506 } else {
7507 OSKextLog(this,
7508 kOSKextLogErrorLevel |
7509 kOSKextLogLoadFlag,
7510 "Not starting %s - dependency %s not started yet.",
7511 getIdentifierCString(),
7512 dependency->getIdentifierCString());
7513 result = kOSKextReturnStartStopError; // xxx - make new return?
7514 goto finish;
7515 }
7516 }
7517 }
7518
7519 OSKextLog(this,
7520 kOSKextLogDetailLevel |
7521 kOSKextLogLoadFlag,
7522 "Kext %s calling module start function.",
7523 getIdentifierCString());
7524
7525 flags.starting = 1;
7526
7527 // Drop a log message so logd can grab the needed information to decode this kext
7528 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7529 result = OSRuntimeInitializeCPP(this);
7530 if (result == KERN_SUCCESS) {
7531 result = startfunc(kmod_info, kmodStartData);
7532 }
7533
7534 flags.starting = 0;
7535
7536 /* On success overlap the setting of started/starting. On failure just
7537 * clear starting.
7538 */
7539 if (result == KERN_SUCCESS) {
7540 flags.started = 1;
7541
7542 // xxx - log start error from kernel?
7543 OSKextLog(this,
7544 kOSKextLogProgressLevel |
7545 kOSKextLogLoadFlag,
7546 "Kext %s is now started.",
7547 getIdentifierCString());
7548 } else {
7549 invokeOrCancelRequestCallbacks(
7550 /* result not actually used */ kOSKextReturnStartStopError,
7551 /* invokeFlag */ false);
7552 OSKextLog(this,
7553 kOSKextLogWarningLevel |
7554 kOSKextLogLoadFlag,
7555 "Kext %s did not start (return code 0x%x).",
7556 getIdentifierCString(), result);
7557 }
7558
7559 finish:
7560 return result;
7561 }
7562
7563 /*********************************************************************
7564 *********************************************************************/
7565 /* static */
7566 bool
7567 OSKext::canUnloadKextWithIdentifier(
7568 OSString * kextIdentifier,
7569 bool checkClassesFlag)
7570 {
7571 bool result = false;
7572 OSKext * aKext = NULL; // do not release
7573
7574 IORecursiveLockLock(sKextLock);
7575
7576 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7577
7578 if (!aKext) {
7579 goto finish; // can't unload what's not loaded
7580 }
7581
7582 if (aKext->isLoaded()) {
7583 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7584 goto finish;
7585 }
7586 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7587 goto finish;
7588 }
7589 }
7590
7591 result = true;
7592
7593 finish:
7594 IORecursiveLockUnlock(sKextLock);
7595 return result;
7596 }
7597
7598 /*********************************************************************
7599 *********************************************************************/
7600 OSReturn
7601 OSKext::stop(void)
7602 {
7603 OSReturn result = kOSReturnError;
7604 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7605
7606 if (!isStarted() || isInterface()) {
7607 result = kOSReturnSuccess;
7608 goto finish;
7609 }
7610
7611 if (!isLoaded()) {
7612 OSKextLog(this,
7613 kOSKextLogErrorLevel |
7614 kOSKextLogLoadFlag,
7615 "Attempt to stop nonloaded kext %s.",
7616 getIdentifierCString());
7617 result = kOSKextReturnInvalidArgument;
7618 goto finish;
7619 }
7620
7621 /* Refuse to stop if we have clients or instances. It is up to
7622 * the caller to make sure those aren't true.
7623 */
7624 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7625 OSKextLog(this,
7626 kOSKextLogErrorLevel |
7627 kOSKextLogLoadFlag,
7628 "Kext %s - C++ instances; can't stop.",
7629 getIdentifierCString());
7630 result = kOSKextReturnInUse;
7631 goto finish;
7632 }
7633
7634 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7635 OSKextLog(this,
7636 kOSKextLogErrorLevel |
7637 kOSKextLogLoadFlag,
7638 "Kext %s - has references (linkage or tracking object); "
7639 "can't stop.",
7640 getIdentifierCString());
7641 result = kOSKextReturnInUse;
7642 goto finish;
7643 }
7644
7645 /* Note: If validateKextMapping fails on the stop & unload path,
7646 * we are in serious trouble and a kernel panic is likely whether
7647 * we stop & unload the kext or not.
7648 */
7649 result = validateKextMapping(/* start? */ false);
7650 if (result != kOSReturnSuccess) {
7651 goto finish;
7652 }
7653
7654 stopfunc = kmod_info->stop;
7655 if (stopfunc) {
7656 OSKextLog(this,
7657 kOSKextLogDetailLevel |
7658 kOSKextLogLoadFlag,
7659 "Kext %s calling module stop function.",
7660 getIdentifierCString());
7661
7662 flags.stopping = 1;
7663
7664 result = stopfunc(kmod_info, /* userData */ NULL);
7665 if (result == KERN_SUCCESS) {
7666 result = OSRuntimeFinalizeCPP(this);
7667 }
7668
7669 flags.stopping = 0;
7670
7671 if (result == KERN_SUCCESS) {
7672 flags.started = 0;
7673
7674 OSKextLog(this,
7675 kOSKextLogDetailLevel |
7676 kOSKextLogLoadFlag,
7677 "Kext %s is now stopped and ready to unload.",
7678 getIdentifierCString());
7679 } else {
7680 OSKextLog(this,
7681 kOSKextLogErrorLevel |
7682 kOSKextLogLoadFlag,
7683 "Kext %s did not stop (return code 0x%x).",
7684 getIdentifierCString(), result);
7685 result = kOSKextReturnStartStopError;
7686 }
7687 }
7688
7689 finish:
7690 // Drop a log message so logd can update this kext's metadata
7691 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7692 return result;
7693 }
7694
7695 /*********************************************************************
7696 *********************************************************************/
7697 OSReturn
7698 OSKext::unload(void)
7699 {
7700 OSReturn result = kOSReturnError;
7701 unsigned int index;
7702 uint32_t num_kmod_refs = 0;
7703 OSKextAccount * freeAccount;
7704 bool in_fileset = false;
7705
7706 if (!sUnloadEnabled) {
7707 OSKextLog(this,
7708 kOSKextLogErrorLevel |
7709 kOSKextLogLoadFlag,
7710 "Kext unloading is disabled (%s).",
7711 this->getIdentifierCString());
7712
7713 result = kOSKextReturnDisabled;
7714 goto finish;
7715 }
7716
7717 // cache this result so we don't need to access the kmod_info after
7718 // it's been potentially free'd
7719 in_fileset = isInFileset();
7720
7721 /* Refuse to unload if we have clients or instances. It is up to
7722 * the caller to make sure those aren't true.
7723 */
7724 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7725 // xxx - Don't log under errors? this is more of an info thing
7726 OSKextLog(this,
7727 kOSKextLogErrorLevel |
7728 kOSKextLogKextBookkeepingFlag,
7729 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7730 getIdentifierCString());
7731 result = kOSKextReturnInUse;
7732 goto finish;
7733 }
7734
7735 if (isDriverKit()) {
7736 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7737 if (index != (unsigned int)-1) {
7738 sLoadedDriverKitKexts->removeObject(index);
7739 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7740 loadTag = 0;
7741 }
7742 }
7743
7744 if (!isLoaded()) {
7745 result = kOSReturnSuccess;
7746 goto finish;
7747 }
7748
7749 if (isKernelComponent()) {
7750 result = kOSKextReturnInvalidArgument;
7751 goto finish;
7752 }
7753
7754 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
7755 OSKextLog(this,
7756 kOSKextLogErrorLevel |
7757 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7758 "Can't unload kext %s; classes have instances:",
7759 getIdentifierCString());
7760 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7761 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7762 result = kOSKextReturnInUse;
7763 goto finish;
7764 }
7765
7766 /* Note that the kext is unloading before running any code that
7767 * might be in the kext (request callbacks, module stop function).
7768 * We will deny certain requests made against a kext in the process
7769 * of unloading.
7770 */
7771 flags.unloading = 1;
7772
7773 /* Update the string describing the last kext to unload in case we panic.
7774 */
7775 savePanicString(/* isLoading */ false);
7776
7777 if (isStarted()) {
7778 result = stop();
7779 if (result != KERN_SUCCESS) {
7780 OSKextLog(this,
7781 kOSKextLogErrorLevel |
7782 kOSKextLogLoadFlag,
7783 "Kext %s can't unload - module stop returned 0x%x.",
7784 getIdentifierCString(), (unsigned)result);
7785 result = kOSKextReturnStartStopError;
7786 goto finish;
7787 }
7788 }
7789
7790 OSKextLog(this,
7791 kOSKextLogProgressLevel |
7792 kOSKextLogLoadFlag,
7793 "Kext %s unloading.",
7794 getIdentifierCString());
7795
7796 {
7797 struct list_head *p;
7798 struct list_head *prev;
7799 struct list_head *next;
7800 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7801 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7802 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7803 prev = p->prev;
7804 next = p->next;
7805 prev->next = next;
7806 next->prev = prev;
7807 p->prev = p;
7808 p->next = p;
7809 IORecursiveLockWakeup(sKextLock, s, false);
7810 }
7811 }
7812
7813
7814 /* Even if we don't call the stop function, we want to be sure we
7815 * have no OSMetaClass references before unloading the kext executable
7816 * from memory. OSMetaClasses may have pointers into the kext executable
7817 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7818 */
7819 if (metaClasses) {
7820 metaClasses->flushCollection();
7821 }
7822 (void) OSRuntimeFinalizeCPP(this);
7823
7824 /* Remove the kext from the list of loaded kexts, patch the gap
7825 * in the kmod_info_t linked list, and reset "kmod" to point to the
7826 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7827 */
7828 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7829 if (index != (unsigned int)-1) {
7830 sLoadedKexts->removeObject(index);
7831
7832 OSKext * nextKext = OSDynamicCast(OSKext,
7833 sLoadedKexts->getObject(index));
7834
7835 if (nextKext) {
7836 if (index > 0) {
7837 OSKext * gapKext = OSDynamicCast(OSKext,
7838 sLoadedKexts->getObject(index - 1));
7839
7840 nextKext->kmod_info->next = gapKext->kmod_info;
7841 } else { /* index == 0 */
7842 nextKext->kmod_info->next = NULL;
7843 }
7844 }
7845
7846 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7847 if (lastKext && !lastKext->isKernel()) {
7848 kmod = lastKext->kmod_info;
7849 } else {
7850 kmod = NULL; // clear the global kmod variable
7851 }
7852 }
7853
7854 /* Clear out the kmod references that we're keeping for compatibility
7855 * with current panic backtrace code & kgmacros.
7856 * xxx - will want to update those bits sometime and remove this.
7857 */
7858 num_kmod_refs = getNumDependencies();
7859 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7860 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7861 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7862 ref->info->reference_count--;
7863 }
7864 kfree_type(kmod_reference_t, num_kmod_refs,
7865 kmod_info->reference_list);
7866 }
7867
7868 #if CONFIG_DTRACE
7869 unregisterWithDTrace();
7870 #endif /* CONFIG_DTRACE */
7871
7872 notifyKextUnloadObservers(this);
7873
7874 freeAccount = NULL;
7875 IOSimpleLockLock(sKextAccountsLock);
7876 account->kext = NULL;
7877 if (account->site.tag) {
7878 account->site.flags |= VM_TAG_UNLOAD;
7879 } else {
7880 freeAccount = account;
7881 }
7882
7883 #if DEVELOPMENT || DEBUG
7884 assertf(account->task_refgrp.grp_count == 0,
7885 "unloading a kext with active task references");
7886 #endif /* DEVELOPMENT || DEBUG */
7887
7888 IOSimpleLockUnlock(sKextAccountsLock);
7889 if (freeAccount) {
7890 IOFreeType(freeAccount, OSKextAccount);
7891 }
7892
7893 /* Unwire and free the linked executable.
7894 */
7895 if (linkedExecutable) {
7896 #if KASAN
7897 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
7898 #endif
7899
7900 #if VM_MAPPED_KEXTS
7901 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
7902 kernel_segment_command_t *seg = NULL;
7903 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7904
7905 if (!kext_map) {
7906 OSKextLog(this,
7907 kOSKextLogErrorLevel |
7908 kOSKextLogLoadFlag,
7909 "Failed to free kext %s; couldn't find the kext map.",
7910 getIdentifierCString());
7911 result = kOSKextReturnInternalError;
7912 goto finish;
7913 }
7914
7915 OSKextLog(this,
7916 kOSKextLogProgressLevel |
7917 kOSKextLogLoadFlag,
7918 "Kext %s unwiring and unmapping linked executable.",
7919 getIdentifierCString());
7920
7921 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7922 while (seg) {
7923 if (segmentShouldBeWired(seg)) {
7924 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7925 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7926
7927 result = vm_map_unwire(kext_map, start_wire,
7928 end_wire, FALSE);
7929 if (result != KERN_SUCCESS) {
7930 OSKextLog(this,
7931 kOSKextLogErrorLevel |
7932 kOSKextLogLoadFlag,
7933 "Failed to unwire kext %s.",
7934 getIdentifierCString());
7935 result = kOSKextReturnInternalError;
7936 goto finish;
7937 }
7938 }
7939
7940 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7941 }
7942 #if defined(__x86_64__) || defined(__i386__)
7943 if (in_fileset && flags.resetSegmentsFromVnode) {
7944 IORecursiveLockLock(sKextLock);
7945 resetKCFileSetSegments();
7946 IORecursiveLockUnlock(sKextLock);
7947 }
7948 #endif // (__x86_64__) || defined(__i386__)
7949 }
7950 #endif /* VM_MAPPED_KEXTS */
7951 if (flags.resetSegmentsFromImmutableCopy) {
7952 result = resetMutableSegments();
7953 if (result != kOSReturnSuccess) {
7954 OSKextLog(this,
7955 kOSKextLogErrorLevel |
7956 kOSKextLogLoadFlag,
7957 "Failed to reset kext %s.",
7958 getIdentifierCString());
7959 result = kOSKextReturnInternalError;
7960 goto finish;
7961 }
7962 }
7963 if (kc_type == KCKindUnknown) {
7964 linkedExecutable.reset();
7965 }
7966 }
7967
7968 /* An interface kext has a fake kmod_info that was allocated,
7969 * so we have to free it.
7970 */
7971 if (isInterface()) {
7972 kfree_type(kmod_info_t, kmod_info);
7973 kmod_info = NULL;
7974 }
7975
7976 if (!in_fileset) {
7977 kmod_info = NULL;
7978 }
7979
7980 flags.loaded = false;
7981 flushDependencies();
7982
7983 /* save a copy of the bundle ID for us to check when deciding to
7984 * rebuild the kernel cache file. If a kext was already in the kernel
7985 * cache and unloaded then later loaded we do not need to rebuild the
7986 * kernel cache. 9055303
7987 */
7988 if (isPrelinked()) {
7989 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
7990 IORecursiveLockLock(sKextLock);
7991 if (sUnloadedPrelinkedKexts) {
7992 sUnloadedPrelinkedKexts->setObject(bundleID.get());
7993 }
7994 IORecursiveLockUnlock(sKextLock);
7995 }
7996 }
7997
7998 OSKextLog(this,
7999 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8000 "Kext %s unloaded.", getIdentifierCString());
8001
8002 queueKextNotification(kKextRequestPredicateUnloadNotification,
8003 OSDynamicCast(OSString, bundleID.get()));
8004
8005 finish:
8006 OSKext::saveLoadedKextPanicList();
8007 OSKext::updateLoadedKextSummaries();
8008
8009 flags.unloading = 0;
8010 return result;
8011 }
8012
8013 /*********************************************************************
8014 * Assumes sKextLock is held.
8015 *********************************************************************/
8016 /* static */
8017 OSReturn
8018 OSKext::queueKextNotification(
8019 const char * notificationName,
8020 OSString * kextIdentifier)
8021 {
8022 OSReturn result = kOSReturnError;
8023 OSSharedPtr<OSDictionary> loadRequest;
8024
8025 if (!kextIdentifier) {
8026 result = kOSKextReturnInvalidArgument;
8027 goto finish;
8028 }
8029
8030 /* Create a new request unless one is already sitting
8031 * in sKernelRequests for this bundle identifier
8032 */
8033 result = _OSKextCreateRequest(notificationName, loadRequest);
8034 if (result != kOSReturnSuccess) {
8035 goto finish;
8036 }
8037 if (!_OSKextSetRequestArgument(loadRequest.get(),
8038 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8039 result = kOSKextReturnNoMemory;
8040 goto finish;
8041 }
8042 if (!sKernelRequests->setObject(loadRequest.get())) {
8043 result = kOSKextReturnNoMemory;
8044 goto finish;
8045 }
8046
8047 /* We might want to only queue the notification if the IOKit daemon is active,
8048 * but that wouldn't work for embedded. Note that we don't care if
8049 * the ping immediately succeeds here so don't do anything with the
8050 * result of this call.
8051 */
8052 OSKext::pingIOKitDaemon();
8053
8054 result = kOSReturnSuccess;
8055
8056 finish:
8057 return result;
8058 }
8059
8060
8061 #if CONFIG_KXLD
8062 /*********************************************************************
8063 *********************************************************************/
8064 static void
8065 _OSKextConsiderDestroyingLinkContext(
8066 __unused thread_call_param_t p0,
8067 __unused thread_call_param_t p1)
8068 {
8069 /* Take multiple locks in the correct order.
8070 */
8071 IORecursiveLockLock(sKextLock);
8072 IORecursiveLockLock(sKextInnerLock);
8073
8074 /* The first time we destroy the kxldContext is in the first
8075 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8076 * before calling this function. Thereafter any call to this function
8077 * will actually destroy the context.
8078 */
8079 if (sConsiderUnloadsCalled && sKxldContext) {
8080 kxld_destroy_context(sKxldContext);
8081 sKxldContext = NULL;
8082 }
8083
8084 /* Free the thread_call that was allocated to execute this function.
8085 */
8086 if (sDestroyLinkContextThread) {
8087 if (!thread_call_free(sDestroyLinkContextThread)) {
8088 OSKextLog(/* kext */ NULL,
8089 kOSKextLogErrorLevel |
8090 kOSKextLogGeneralFlag,
8091 "thread_call_free() failed for kext link context.");
8092 }
8093 sDestroyLinkContextThread = NULL;
8094 }
8095
8096 IORecursiveLockUnlock(sKextInnerLock);
8097 IORecursiveLockUnlock(sKextLock);
8098
8099 return;
8100 }
8101
8102 /*********************************************************************
8103 * Destroying the kxldContext requires checking variables under both
8104 * sKextInnerLock and sKextLock, so we do it on a separate thread
8105 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8106 * call relationship.
8107 *
8108 * This function must be invoked with sKextInnerLock held.
8109 * Do not call any function that takes sKextLock here!
8110 *********************************************************************/
8111 /* static */
8112 void
8113 OSKext::considerDestroyingLinkContext(void)
8114 {
8115 IORecursiveLockLock(sKextInnerLock);
8116
8117 /* If we have already queued a thread to destroy the link context,
8118 * don't bother resetting; that thread will take care of it.
8119 */
8120 if (sDestroyLinkContextThread) {
8121 goto finish;
8122 }
8123
8124 /* The function to be invoked in the thread will deallocate
8125 * this thread_call, so don't share it around.
8126 */
8127 sDestroyLinkContextThread = thread_call_allocate(
8128 &_OSKextConsiderDestroyingLinkContext, NULL);
8129 if (!sDestroyLinkContextThread) {
8130 OSKextLog(/* kext */ NULL,
8131 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8132 "Can't create thread to destroy kext link context.");
8133 goto finish;
8134 }
8135
8136 thread_call_enter(sDestroyLinkContextThread);
8137
8138 finish:
8139 IORecursiveLockUnlock(sKextInnerLock);
8140 return;
8141 }
8142
8143 #else // !CONFIG_KXLD
8144
8145 /* static */
8146 void
8147 OSKext::considerDestroyingLinkContext(void)
8148 {
8149 return;
8150 }
8151
8152 #endif // CONFIG_KXLD
8153
8154 #if PRAGMA_MARK
8155 #pragma mark Autounload
8156 #endif
8157 /*********************************************************************
8158 * This is a static method because the kext will be deallocated if it
8159 * does unload!
8160 *********************************************************************/
8161 /* static */
8162 OSReturn
8163 OSKext::autounloadKext(OSKext * aKext)
8164 {
8165 OSReturn result = kOSKextReturnInUse;
8166
8167 #if NO_KEXTD
8168 /*
8169 * Do not unload prelinked kexts on platforms that do not have an
8170 * IOKit daemon as there is no way to reload the kext or restart
8171 * matching.
8172 */
8173 if (aKext->isPrelinked()) {
8174 goto finish;
8175 }
8176 #endif /* defined(__x86_64__) */
8177
8178 /* Check for external references to this kext (usu. dependents),
8179 * instances of defined classes (or classes derived from them),
8180 * outstanding requests.
8181 */
8182 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8183 !aKext->flags.autounloadEnabled ||
8184 aKext->isKernelComponent()) {
8185 goto finish;
8186 }
8187
8188 /* Skip a delay-autounload kext, once.
8189 */
8190 if (aKext->flags.delayAutounload) {
8191 OSKextLog(aKext,
8192 kOSKextLogProgressLevel |
8193 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8194 "Kext %s has delayed autounload set; skipping and clearing flag.",
8195 aKext->getIdentifierCString());
8196 aKext->flags.delayAutounload = 0;
8197 goto finish;
8198 }
8199
8200 if (aKext->hasOSMetaClassInstances() ||
8201 aKext->countRequestCallbacks()) {
8202 goto finish;
8203 }
8204
8205 result = OSKext::removeKext(aKext);
8206
8207 finish:
8208 return result;
8209 }
8210
8211 /*********************************************************************
8212 *********************************************************************/
8213 void
8214 _OSKextConsiderUnloads(
8215 __unused thread_call_param_t p0,
8216 __unused thread_call_param_t p1)
8217 {
8218 bool didUnload = false;
8219 unsigned int count, i;
8220
8221 /* Take multiple locks in the correct order
8222 * (note also sKextSummaries lock further down).
8223 */
8224 IORecursiveLockLock(sKextLock);
8225 IORecursiveLockLock(sKextInnerLock);
8226
8227 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8228
8229 /* If the system is powering down, don't try to unload anything.
8230 */
8231 if (sSystemSleep) {
8232 goto finish;
8233 }
8234
8235 OSKextLog(/* kext */ NULL,
8236 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8237 "Checking for unused kexts to autounload.");
8238
8239 /*****
8240 * Remove any request callbacks marked as stale,
8241 * and mark as stale any currently in flight.
8242 */
8243 count = sRequestCallbackRecords->getCount();
8244 if (count) {
8245 i = count - 1;
8246 do {
8247 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8248 sRequestCallbackRecords->getObject(i));
8249 if (callbackRecord) {
8250 OSBoolean * stale = OSDynamicCast(OSBoolean,
8251 callbackRecord->getObject(kKextRequestStaleKey));
8252
8253 if (stale == kOSBooleanTrue) {
8254 OSKext::invokeRequestCallback(callbackRecord,
8255 kOSKextReturnTimeout);
8256 } else {
8257 callbackRecord->setObject(kKextRequestStaleKey,
8258 kOSBooleanTrue);
8259 }
8260 }
8261 } while (i--);
8262 }
8263
8264 /*****
8265 * Make multiple passes through the array of loaded kexts until
8266 * we don't unload any. This handles unwinding of dependency
8267 * chains. We have to go *backwards* through the array because
8268 * kexts are removed from it when unloaded, and we cannot make
8269 * a copy or we'll mess up the retain counts we rely on to
8270 * check whether a kext will unload. If only we could have
8271 * nonretaining collections like CF has....
8272 */
8273 do {
8274 didUnload = false;
8275
8276 count = sLoadedKexts->getCount();
8277 if (count) {
8278 i = count - 1;
8279 do {
8280 OSKext * thisKext = OSDynamicCast(OSKext,
8281 sLoadedKexts->getObject(i));
8282 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8283 } while (i--);
8284 }
8285 } while (didUnload);
8286
8287 finish:
8288 sConsiderUnloadsPending = false;
8289 sConsiderUnloadsExecuted = true;
8290
8291 (void) OSKext::considerRebuildOfPrelinkedKernel();
8292
8293 IORecursiveLockUnlock(sKextInnerLock);
8294 IORecursiveLockUnlock(sKextLock);
8295
8296 return;
8297 }
8298
8299 /*********************************************************************
8300 * Do not call any function that takes sKextLock here!
8301 *********************************************************************/
8302 void
8303 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8304 {
8305 AbsoluteTime when;
8306
8307 IORecursiveLockLock(sKextInnerLock);
8308
8309 if (!sUnloadCallout) {
8310 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8311 }
8312
8313 /* we only reset delay value for unloading if we already have something
8314 * pending. rescheduleOnlyFlag should not start the count down.
8315 */
8316 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8317 goto finish;
8318 }
8319
8320 thread_call_cancel(sUnloadCallout);
8321 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8322 #if !NO_KEXTD
8323 && sIOKitDaemonActive
8324 #endif
8325 ) {
8326 clock_interval_to_deadline(sConsiderUnloadDelay,
8327 1000 * 1000 * 1000, &when);
8328
8329 OSKextLog(/* kext */ NULL,
8330 kOSKextLogProgressLevel |
8331 kOSKextLogLoadFlag,
8332 "%scheduling %sscan for unused kexts in %lu seconds.",
8333 sConsiderUnloadsPending ? "Res" : "S",
8334 sConsiderUnloadsCalled ? "" : "initial ",
8335 (unsigned long)sConsiderUnloadDelay);
8336
8337 sConsiderUnloadsPending = true;
8338 thread_call_enter_delayed(sUnloadCallout, when);
8339 }
8340
8341 finish:
8342 /* The kxld context should be reused throughout boot. We mark the end of
8343 * period as the first time considerUnloads() is called, and we destroy
8344 * the first kxld context in that function. Afterwards, it will be
8345 * destroyed in flushNonloadedKexts.
8346 */
8347 if (!sConsiderUnloadsCalled) {
8348 sConsiderUnloadsCalled = true;
8349 OSKext::considerDestroyingLinkContext();
8350 }
8351
8352 IORecursiveLockUnlock(sKextInnerLock);
8353 return;
8354 }
8355
8356 /*********************************************************************
8357 * Do not call any function that takes sKextLock here!
8358 *********************************************************************/
8359 extern "C" {
8360 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
8361 IOReturn
8362 OSKextSystemSleepOrWake(UInt32 messageType)
8363 {
8364 IORecursiveLockLock(sKextInnerLock);
8365
8366 /* If the system is going to sleep, cancel the reaper thread timer,
8367 * and note that we're in a sleep state in case it just fired but hasn't
8368 * taken the lock yet. If we are coming back from sleep, just
8369 * clear the sleep flag; IOService's normal operation will cause
8370 * unloads to be considered soon enough.
8371 */
8372 if (messageType == kIOMessageSystemWillSleep) {
8373 if (sUnloadCallout) {
8374 thread_call_cancel(sUnloadCallout);
8375 }
8376 sSystemSleep = true;
8377 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8378 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8379 sSystemSleep = false;
8380 clock_get_uptime(&sLastWakeTime);
8381 }
8382 IORecursiveLockUnlock(sKextInnerLock);
8383
8384 return kIOReturnSuccess;
8385 }
8386 };
8387
8388
8389 #if PRAGMA_MARK
8390 #pragma mark Prelinked Kernel
8391 #endif
8392
8393 #ifdef CONFIG_KXLD
8394 /*********************************************************************
8395 * Do not access sConsiderUnloads... variables other than
8396 * sConsiderUnloadsExecuted in this function. They are guarded by a
8397 * different lock.
8398 *********************************************************************/
8399 /* static */
8400 void
8401 OSKext::considerRebuildOfPrelinkedKernel(void)
8402 {
8403 static bool requestedPrelink = false;
8404 OSReturn checkResult = kOSReturnError;
8405 OSSharedPtr<OSDictionary> prelinkRequest;
8406 OSSharedPtr<OSCollectionIterator> kextIterator;
8407 const OSSymbol * thisID = NULL; // do not release
8408 bool doRebuild = false;
8409 AbsoluteTime my_abstime;
8410 UInt64 my_ns;
8411 SInt32 delta_secs;
8412
8413 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8414 if (requestedPrelink || !sPrelinkBoot) {
8415 return;
8416 }
8417
8418 /* no direct return from this point */
8419 IORecursiveLockLock(sKextLock);
8420
8421 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8422 * and any new startup kexts loaded.
8423 */
8424 if (!sConsiderUnloadsExecuted ||
8425 !sDeferredLoadSucceeded) {
8426 goto finish;
8427 }
8428
8429 /* we really only care about boot / system start up related kexts so bail
8430 * if we're here after REBUILD_MAX_TIME.
8431 */
8432 if (!_OSKextInPrelinkRebuildWindow()) {
8433 OSKextLog(/* kext */ NULL,
8434 kOSKextLogArchiveFlag,
8435 "%s prebuild rebuild has expired",
8436 __FUNCTION__);
8437 requestedPrelink = true;
8438 goto finish;
8439 }
8440
8441 /* we do not want to trigger a rebuild if we get here too close to waking
8442 * up. (see radar 10233768)
8443 */
8444 IORecursiveLockLock(sKextInnerLock);
8445
8446 clock_get_uptime(&my_abstime);
8447 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8448 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8449 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8450 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8451 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8452 }
8453 IORecursiveLockUnlock(sKextInnerLock);
8454
8455 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8456 /* too close to time of last wake from sleep */
8457 goto finish;
8458 }
8459 requestedPrelink = true;
8460
8461 /* Now it's time to see if we have a reason to rebuild. We may have done
8462 * some loads and unloads but the kernel cache didn't actually change.
8463 * We will rebuild if any kext is not marked prelinked AND is not in our
8464 * list of prelinked kexts that got unloaded. (see radar 9055303)
8465 */
8466 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
8467 if (!kextIterator) {
8468 goto finish;
8469 }
8470
8471 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
8472 OSKext * thisKext; // do not release
8473
8474 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8475 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8476 continue;
8477 }
8478
8479 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
8480 continue;
8481 }
8482 /* kext is loaded and was not in current kernel cache so let's rebuild
8483 */
8484 doRebuild = true;
8485 OSKextLog(/* kext */ NULL,
8486 kOSKextLogArchiveFlag,
8487 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8488 thisKext->bundleID->getCStringNoCopy());
8489 break;
8490 }
8491 sUnloadedPrelinkedKexts->flushCollection();
8492
8493 if (!doRebuild) {
8494 goto finish;
8495 }
8496
8497 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
8498 prelinkRequest);
8499 if (checkResult != kOSReturnSuccess) {
8500 goto finish;
8501 }
8502
8503 if (!sKernelRequests->setObject(prelinkRequest.get())) {
8504 goto finish;
8505 }
8506
8507 OSKext::pingIOKitDaemon();
8508
8509 finish:
8510 IORecursiveLockUnlock(sKextLock);
8511
8512 return;
8513 }
8514
8515 #else /* !CONFIG_KXLD */
8516
8517 void
8518 OSKext::considerRebuildOfPrelinkedKernel(void)
8519 {
8520 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8521 return;
8522 }
8523
8524 #endif /* CONFIG_KXLD */
8525
8526 #if PRAGMA_MARK
8527 #pragma mark Dependencies
8528 #endif
8529 /*********************************************************************
8530 *********************************************************************/
8531 bool
8532 OSKext::resolveDependencies(
8533 OSArray * loopStack)
8534 {
8535 bool result = false;
8536 OSSharedPtr<OSArray> localLoopStack;
8537 bool addedToLoopStack = false;
8538 OSDictionary * libraries = NULL; // do not release
8539 OSSharedPtr<OSCollectionIterator> libraryIterator;
8540 OSString * libraryID = NULL; // do not release
8541 OSKext * libraryKext = NULL; // do not release
8542 bool hasRawKernelDependency = false;
8543 bool hasKernelDependency = false;
8544 bool hasKPIDependency = false;
8545 bool hasPrivateKPIDependency = false;
8546 unsigned int count;
8547
8548 #if CONFIG_KXLD
8549 OSString * infoString = NULL; // do not release
8550 OSString * readableString = NULL; // do not release
8551 #endif // CONFIG_KXLD
8552
8553 /* A kernel component will automatically have this flag set,
8554 * and a loaded kext should also have it set (as should all its
8555 * loaded dependencies).
8556 */
8557 if (flags.hasAllDependencies) {
8558 result = true;
8559 goto finish;
8560 }
8561
8562 /* Check for loops in the dependency graph.
8563 */
8564 if (loopStack) {
8565 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8566 OSKextLog(this,
8567 kOSKextLogErrorLevel |
8568 kOSKextLogDependenciesFlag,
8569 "Kext %s has a dependency loop; can't resolve dependencies.",
8570 getIdentifierCString());
8571 goto finish;
8572 }
8573 } else {
8574 OSKextLog(this,
8575 kOSKextLogStepLevel |
8576 kOSKextLogDependenciesFlag,
8577 "Kext %s resolving dependencies.",
8578 getIdentifierCString());
8579
8580 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8581 if (!localLoopStack) {
8582 OSKextLog(this,
8583 kOSKextLogErrorLevel |
8584 kOSKextLogDependenciesFlag,
8585 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8586 getIdentifierCString());
8587 goto finish;
8588 }
8589 loopStack = localLoopStack.get();
8590 }
8591 if (!loopStack->setObject(this)) {
8592 OSKextLog(this,
8593 kOSKextLogErrorLevel |
8594 kOSKextLogDependenciesFlag,
8595 "Kext %s - internal error resolving dependencies.",
8596 getIdentifierCString());
8597 goto finish;
8598 }
8599 addedToLoopStack = true;
8600
8601 /* Purge any existing kexts in the dependency list and start over.
8602 */
8603 flushDependencies();
8604 if (dependencies) {
8605 OSKextLog(this,
8606 kOSKextLogErrorLevel |
8607 kOSKextLogDependenciesFlag,
8608 "Kext %s - internal error resolving dependencies.",
8609 getIdentifierCString());
8610 }
8611
8612 libraries = OSDynamicCast(OSDictionary,
8613 getPropertyForHostArch(kOSBundleLibrariesKey));
8614 if (libraries == NULL || libraries->getCount() == 0) {
8615 OSKextLog(this,
8616 kOSKextLogErrorLevel |
8617 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8618 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8619 getIdentifierCString(), kOSBundleLibrariesKey);
8620 goto finish;
8621 }
8622
8623 /* Make a new array to hold the dependencies (flush freed the old one).
8624 */
8625 dependencies = OSArray::withCapacity(libraries->getCount());
8626 if (!dependencies) {
8627 OSKextLog(this,
8628 kOSKextLogErrorLevel |
8629 kOSKextLogDependenciesFlag,
8630 "Kext %s - can't allocate dependencies array.",
8631 getIdentifierCString());
8632 goto finish;
8633 }
8634
8635 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8636 // xxx - compat: if none were declared.
8637
8638 libraryIterator = OSCollectionIterator::withCollection(libraries);
8639 if (!libraryIterator) {
8640 OSKextLog(this,
8641 kOSKextLogErrorLevel |
8642 kOSKextLogDependenciesFlag,
8643 "Kext %s - can't allocate dependencies iterator.",
8644 getIdentifierCString());
8645 goto finish;
8646 }
8647
8648 while ((libraryID = OSDynamicCast(OSString,
8649 libraryIterator->getNextObject()))) {
8650 const char * library_id = libraryID->getCStringNoCopy();
8651
8652 OSString * libraryVersion = OSDynamicCast(OSString,
8653 libraries->getObject(libraryID));
8654 if (libraryVersion == NULL) {
8655 OSKextLog(this,
8656 kOSKextLogErrorLevel |
8657 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8658 "Kext %s - illegal type in OSBundleLibraries.",
8659 getIdentifierCString());
8660 goto finish;
8661 }
8662
8663 OSKextVersion libraryVers =
8664 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8665 if (libraryVers == -1) {
8666 OSKextLog(this,
8667 kOSKextLogErrorLevel |
8668 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8669 "Kext %s - invalid library version %s.",
8670 getIdentifierCString(),
8671 libraryVersion->getCStringNoCopy());
8672 goto finish;
8673 }
8674
8675 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8676 if (libraryKext == NULL) {
8677 OSKextLog(this,
8678 kOSKextLogErrorLevel |
8679 kOSKextLogDependenciesFlag,
8680 "Kext %s - library kext %s not found.",
8681 getIdentifierCString(), library_id);
8682 goto finish;
8683 }
8684
8685 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8686 OSKextLog(this,
8687 kOSKextLogErrorLevel |
8688 kOSKextLogDependenciesFlag,
8689 "Kext %s - library kext %s not compatible "
8690 "with requested version %s.",
8691 getIdentifierCString(), library_id,
8692 libraryVersion->getCStringNoCopy());
8693 goto finish;
8694 }
8695
8696 /* If a nonprelinked library somehow got into the mix for a
8697 * prelinked kext, at any point in the chain, we must fail
8698 * because the prelinked relocs for the library will be all wrong.
8699 */
8700 if (this->isPrelinked() &&
8701 libraryKext->declaresExecutable() &&
8702 !libraryKext->isPrelinked()) {
8703 OSKextLog(this,
8704 kOSKextLogErrorLevel |
8705 kOSKextLogDependenciesFlag,
8706 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8707 getIdentifierCString(), library_id,
8708 libraryVersion->getCStringNoCopy());
8709 goto finish;
8710 }
8711
8712 if (!libraryKext->resolveDependencies(loopStack)) {
8713 goto finish;
8714 }
8715
8716 /* Add the library directly only if it has an executable to link.
8717 * Otherwise it's just used to collect other dependencies, so put
8718 * *its* dependencies on the list for this kext.
8719 */
8720 // xxx - We are losing info here; would like to make fake entries or
8721 // xxx - keep these in the dependency graph for loaded kexts.
8722 // xxx - I really want to make kernel components not a special case!
8723 if (libraryKext->declaresExecutable() ||
8724 libraryKext->isInterface()) {
8725 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8726 dependencies->setObject(libraryKext);
8727
8728 OSKextLog(this,
8729 kOSKextLogDetailLevel |
8730 kOSKextLogDependenciesFlag,
8731 "Kext %s added dependency %s.",
8732 getIdentifierCString(),
8733 libraryKext->getIdentifierCString());
8734 }
8735 } else {
8736 int numLibDependencies = libraryKext->getNumDependencies();
8737 OSArray * libraryDependencies = libraryKext->getDependencies();
8738 int index;
8739
8740 if (numLibDependencies) {
8741 // xxx - this msg level should be 1 lower than the per-kext one
8742 OSKextLog(this,
8743 kOSKextLogDetailLevel |
8744 kOSKextLogDependenciesFlag,
8745 "Kext %s pulling %d dependencies from codeless library %s.",
8746 getIdentifierCString(),
8747 numLibDependencies,
8748 libraryKext->getIdentifierCString());
8749 }
8750 for (index = 0; index < numLibDependencies; index++) {
8751 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8752 libraryDependencies->getObject(index));
8753 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8754 dependencies->setObject(thisLibDependency);
8755 OSKextLog(this,
8756 kOSKextLogDetailLevel |
8757 kOSKextLogDependenciesFlag,
8758 "Kext %s added dependency %s from codeless library %s.",
8759 getIdentifierCString(),
8760 thisLibDependency->getIdentifierCString(),
8761 libraryKext->getIdentifierCString());
8762 }
8763 }
8764 }
8765
8766 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8767 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8768 hasRawKernelDependency = true;
8769 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8770 hasKernelDependency = true;
8771 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8772 hasKPIDependency = true;
8773 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8774 hasPrivateKPIDependency = true;
8775 }
8776 }
8777 }
8778
8779 if (hasRawKernelDependency) {
8780 OSKextLog(this,
8781 kOSKextLogErrorLevel |
8782 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8783 "Error - kext %s declares a dependency on %s, which is not permitted.",
8784 getIdentifierCString(), KERNEL_LIB);
8785 goto finish;
8786 }
8787 #if __LP64__
8788 if (hasKernelDependency) {
8789 OSKextLog(this,
8790 kOSKextLogErrorLevel |
8791 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8792 "Error - kext %s declares %s dependencies. "
8793 "Only %s* dependencies are supported for 64-bit kexts.",
8794 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8795 goto finish;
8796 }
8797 if (!hasKPIDependency) {
8798 OSKextLog(this,
8799 kOSKextLogWarningLevel |
8800 kOSKextLogDependenciesFlag,
8801 "Warning - kext %s declares no %s* dependencies. "
8802 "If it uses any KPIs, the link may fail with undefined symbols.",
8803 getIdentifierCString(), KPI_LIB_PREFIX);
8804 }
8805 #else /* __LP64__ */
8806 // xxx - will change to flatly disallow "kernel" dependencies at some point
8807 // xxx - is it invalid to do both "com.apple.kernel" and any
8808 // xxx - "com.apple.kernel.*"?
8809
8810 if (hasKernelDependency && hasKPIDependency) {
8811 OSKextLog(this,
8812 kOSKextLogWarningLevel |
8813 kOSKextLogDependenciesFlag,
8814 "Warning - kext %s has immediate dependencies on both "
8815 "%s* and %s* components; use only one style.",
8816 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8817 }
8818
8819 if (!hasKernelDependency && !hasKPIDependency) {
8820 // xxx - do we want to use validation flag for these too?
8821 OSKextLog(this,
8822 kOSKextLogWarningLevel |
8823 kOSKextLogDependenciesFlag,
8824 "Warning - %s declares no kernel dependencies; using %s.",
8825 getIdentifierCString(), KERNEL6_LIB);
8826 OSKext * kernelKext = OSDynamicCast(OSKext,
8827 sKextsByID->getObject(KERNEL6_LIB));
8828 if (kernelKext) {
8829 dependencies->setObject(kernelKext);
8830 } else {
8831 OSKextLog(this,
8832 kOSKextLogErrorLevel |
8833 kOSKextLogDependenciesFlag,
8834 "Error - Library %s not found for %s.",
8835 KERNEL6_LIB, getIdentifierCString());
8836 }
8837 }
8838
8839 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8840 * its indirect dependencies to simulate old-style linking. XXX - Should
8841 * check for duplicates.
8842 */
8843 if (!hasKPIDependency) {
8844 unsigned int i;
8845
8846 flags.hasBleedthrough = true;
8847
8848 count = getNumDependencies();
8849
8850 /* We add to the dependencies array in this loop, but do not iterate
8851 * past its original count.
8852 */
8853 for (i = 0; i < count; i++) {
8854 OSKext * dependencyKext = OSDynamicCast(OSKext,
8855 dependencies->getObject(i));
8856 dependencyKext->addBleedthroughDependencies(dependencies.get());
8857 }
8858 }
8859 #endif /* __LP64__ */
8860
8861 #if CONFIG_KXLD
8862 /*
8863 * If we're not dynamically linking kexts, then we don't need to check
8864 * copyright strings. The linker in user space has already done this.
8865 */
8866 if (hasPrivateKPIDependency) {
8867 bool hasApplePrefix = false;
8868 bool infoCopyrightIsValid = false;
8869 bool readableCopyrightIsValid = false;
8870
8871 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8872 APPLE_KEXT_PREFIX);
8873
8874 infoString = OSDynamicCast(OSString,
8875 getPropertyForHostArch("CFBundleGetInfoString"));
8876 if (infoString) {
8877 infoCopyrightIsValid =
8878 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8879 }
8880
8881 readableString = OSDynamicCast(OSString,
8882 getPropertyForHostArch("NSHumanReadableCopyright"));
8883 if (readableString) {
8884 readableCopyrightIsValid =
8885 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8886 }
8887
8888 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8889 OSKextLog(this,
8890 kOSKextLogErrorLevel |
8891 kOSKextLogDependenciesFlag,
8892 "Error - kext %s declares a dependency on %s. "
8893 "Only Apple kexts may declare a dependency on %s.",
8894 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8895 goto finish;
8896 }
8897 }
8898 #endif // CONFIG_KXLD
8899
8900 result = true;
8901 flags.hasAllDependencies = 1;
8902
8903 finish:
8904
8905 if (addedToLoopStack) {
8906 count = loopStack->getCount();
8907 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8908 loopStack->removeObject(count - 1);
8909 } else {
8910 OSKextLog(this,
8911 kOSKextLogErrorLevel |
8912 kOSKextLogDependenciesFlag,
8913 "Kext %s - internal error resolving dependencies.",
8914 getIdentifierCString());
8915 }
8916 }
8917
8918 if (result && localLoopStack) {
8919 OSKextLog(this,
8920 kOSKextLogStepLevel |
8921 kOSKextLogDependenciesFlag,
8922 "Kext %s successfully resolved dependencies.",
8923 getIdentifierCString());
8924 }
8925
8926 return result;
8927 }
8928
8929 /*********************************************************************
8930 *********************************************************************/
8931 bool
8932 OSKext::addBleedthroughDependencies(OSArray * anArray)
8933 {
8934 bool result = false;
8935 unsigned int dependencyIndex, dependencyCount;
8936
8937 dependencyCount = getNumDependencies();
8938
8939 for (dependencyIndex = 0;
8940 dependencyIndex < dependencyCount;
8941 dependencyIndex++) {
8942 OSKext * dependency = OSDynamicCast(OSKext,
8943 dependencies->getObject(dependencyIndex));
8944 if (!dependency) {
8945 OSKextLog(this,
8946 kOSKextLogErrorLevel |
8947 kOSKextLogDependenciesFlag,
8948 "Kext %s - internal error propagating compatibility dependencies.",
8949 getIdentifierCString());
8950 goto finish;
8951 }
8952 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8953 anArray->setObject(dependency);
8954 }
8955 dependency->addBleedthroughDependencies(anArray);
8956 }
8957
8958 result = true;
8959
8960 finish:
8961 return result;
8962 }
8963
8964 /*********************************************************************
8965 *********************************************************************/
8966 bool
8967 OSKext::flushDependencies(bool forceFlag)
8968 {
8969 bool result = false;
8970
8971 /* Only clear the dependencies if the kext isn't loaded;
8972 * we need the info for loaded kexts to track references.
8973 */
8974 if (!isLoaded() || forceFlag) {
8975 if (dependencies) {
8976 // xxx - check level
8977 OSKextLog(this,
8978 kOSKextLogProgressLevel |
8979 kOSKextLogDependenciesFlag,
8980 "Kext %s flushing dependencies.",
8981 getIdentifierCString());
8982 dependencies.reset();
8983 }
8984 if (!isKernelComponent()) {
8985 flags.hasAllDependencies = 0;
8986 }
8987 result = true;
8988 }
8989
8990 return result;
8991 }
8992
8993 /*********************************************************************
8994 *********************************************************************/
8995 uint32_t
8996 OSKext::getNumDependencies(void)
8997 {
8998 if (!dependencies) {
8999 return 0;
9000 }
9001 return dependencies->getCount();
9002 }
9003
9004 /*********************************************************************
9005 *********************************************************************/
9006 OSArray *
9007 OSKext::getDependencies(void)
9008 {
9009 return dependencies.get();
9010 }
9011
9012 bool
9013 OSKext::hasDependency(const OSSymbol * depID)
9014 {
9015 bool result __block;
9016
9017 if (depID == getIdentifier()) {
9018 return true;
9019 }
9020 if (!dependencies) {
9021 return false;
9022 }
9023 result = false;
9024 dependencies->iterateObjects(^bool (OSObject * obj) {
9025 OSKext * kext;
9026 kext = OSDynamicCast(OSKext, obj);
9027 if (!kext) {
9028 return false;
9029 }
9030 result = (depID == kext->getIdentifier());
9031 return result;
9032 });
9033 return result;
9034 }
9035
9036 #if PRAGMA_MARK
9037 #pragma mark OSMetaClass Support
9038 #endif
9039 /*********************************************************************
9040 *********************************************************************/
9041 OSReturn
9042 OSKext::addClass(
9043 OSMetaClass * aClass,
9044 uint32_t numClasses)
9045 {
9046 OSReturn result = kOSMetaClassNoInsKModSet;
9047
9048 if (!metaClasses) {
9049 metaClasses = OSSet::withCapacity(numClasses);
9050 if (!metaClasses) {
9051 goto finish;
9052 }
9053 }
9054
9055 if (metaClasses->containsObject(aClass)) {
9056 OSKextLog(this,
9057 kOSKextLogWarningLevel |
9058 kOSKextLogLoadFlag,
9059 "Notice - kext %s has already registered class %s.",
9060 getIdentifierCString(),
9061 aClass->getClassName());
9062 result = kOSReturnSuccess;
9063 goto finish;
9064 }
9065
9066 if (!metaClasses->setObject(aClass)) {
9067 goto finish;
9068 } else {
9069 OSKextLog(this,
9070 kOSKextLogDetailLevel |
9071 kOSKextLogLoadFlag,
9072 "Kext %s registered class %s.",
9073 getIdentifierCString(),
9074 aClass->getClassName());
9075 }
9076
9077 if (!flags.autounloadEnabled) {
9078 const OSMetaClass * metaScan = NULL; // do not release
9079
9080 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9081 if (metaScan == OSTypeID(IOService)) {
9082 OSKextLog(this,
9083 kOSKextLogProgressLevel |
9084 kOSKextLogLoadFlag,
9085 "Kext %s has IOService subclass %s; enabling autounload.",
9086 getIdentifierCString(),
9087 aClass->getClassName());
9088
9089 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9090 break;
9091 }
9092 }
9093 }
9094
9095 notifyAddClassObservers(this, aClass, flags);
9096
9097 result = kOSReturnSuccess;
9098
9099 finish:
9100 if (result != kOSReturnSuccess) {
9101 OSKextLog(this,
9102 kOSKextLogErrorLevel |
9103 kOSKextLogLoadFlag,
9104 "Kext %s failed to register class %s.",
9105 getIdentifierCString(),
9106 aClass->getClassName());
9107 }
9108
9109 return result;
9110 }
9111
9112 /*********************************************************************
9113 *********************************************************************/
9114 OSReturn
9115 OSKext::removeClass(
9116 OSMetaClass * aClass)
9117 {
9118 OSReturn result = kOSMetaClassNoKModSet;
9119
9120 if (!metaClasses) {
9121 goto finish;
9122 }
9123
9124 if (!metaClasses->containsObject(aClass)) {
9125 OSKextLog(this,
9126 kOSKextLogWarningLevel |
9127 kOSKextLogLoadFlag,
9128 "Notice - kext %s asked to unregister unknown class %s.",
9129 getIdentifierCString(),
9130 aClass->getClassName());
9131 result = kOSReturnSuccess;
9132 goto finish;
9133 }
9134
9135 OSKextLog(this,
9136 kOSKextLogDetailLevel |
9137 kOSKextLogLoadFlag,
9138 "Kext %s unregistering class %s.",
9139 getIdentifierCString(),
9140 aClass->getClassName());
9141
9142 metaClasses->removeObject(aClass);
9143
9144 notifyRemoveClassObservers(this, aClass, flags);
9145
9146 result = kOSReturnSuccess;
9147
9148 finish:
9149 if (result != kOSReturnSuccess) {
9150 OSKextLog(this,
9151 kOSKextLogErrorLevel |
9152 kOSKextLogLoadFlag,
9153 "Failed to unregister kext %s class %s.",
9154 getIdentifierCString(),
9155 aClass->getClassName());
9156 }
9157 return result;
9158 }
9159
9160 /*********************************************************************
9161 *********************************************************************/
9162 OSSet *
9163 OSKext::getMetaClasses(void)
9164 {
9165 return metaClasses.get();
9166 }
9167
9168 /*********************************************************************
9169 *********************************************************************/
9170 bool
9171 OSKext::hasOSMetaClassInstances(void)
9172 {
9173 bool result = false;
9174 OSSharedPtr<OSCollectionIterator> classIterator;
9175 OSMetaClass * checkClass = NULL; // do not release
9176
9177 if (!metaClasses) {
9178 goto finish;
9179 }
9180
9181 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9182 if (!classIterator) {
9183 // xxx - log alloc failure?
9184 goto finish;
9185 }
9186 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9187 if (checkClass->getInstanceCount()) {
9188 result = true;
9189 goto finish;
9190 }
9191 }
9192
9193 finish:
9194 return result;
9195 }
9196
9197 /*********************************************************************
9198 *********************************************************************/
9199 /* static */
9200 void
9201 OSKext::reportOSMetaClassInstances(
9202 const char * kextIdentifier,
9203 OSKextLogSpec msgLogSpec)
9204 {
9205 OSSharedPtr<OSKext> theKext;
9206
9207 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9208 if (!theKext) {
9209 goto finish;
9210 }
9211
9212 theKext->reportOSMetaClassInstances(msgLogSpec);
9213 finish:
9214 return;
9215 }
9216
9217 /*********************************************************************
9218 *********************************************************************/
9219 void
9220 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9221 {
9222 OSSharedPtr<OSCollectionIterator> classIterator;
9223 OSMetaClass * checkClass = NULL; // do not release
9224
9225 if (!metaClasses) {
9226 goto finish;
9227 }
9228
9229 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9230 if (!classIterator) {
9231 goto finish;
9232 }
9233 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9234 if (checkClass->getInstanceCount()) {
9235 OSKextLog(this,
9236 msgLogSpec,
9237 " Kext %s class %s has %d instance%s.",
9238 getIdentifierCString(),
9239 checkClass->getClassName(),
9240 checkClass->getInstanceCount(),
9241 checkClass->getInstanceCount() == 1 ? "" : "s");
9242 }
9243 }
9244
9245 finish:
9246 return;
9247 }
9248
9249 #if PRAGMA_MARK
9250 #pragma mark User-Space Requests
9251 #endif
9252
9253 static kern_return_t
9254 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9255 {
9256 OSReturn result = kOSReturnSuccess;
9257 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9258 OSDictionary * request = NULL; //do not release
9259 IOUserServerCheckInToken * token = NULL; //do not release
9260 OSString * requestPredicate = NULL; //do not release
9261 OSSharedPtr<OSNumber> portNameNumber;
9262 mach_port_name_t portName = 0;
9263 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9264 if (!request) {
9265 OSKextLog(/* kext */ NULL,
9266 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9267 "Elements of request should be of type OSDictionary");
9268 result = kOSKextReturnInternalError;
9269 goto finish;
9270 }
9271 requestPredicate = _OSKextGetRequestPredicate(request);
9272 if (!requestPredicate) {
9273 OSKextLog(/* kext */ NULL,
9274 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9275 "Failed to get request predicate");
9276 result = kOSKextReturnInternalError;
9277 goto finish;
9278 }
9279 // is this a dext launch?
9280 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9281 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9282 if (!token) {
9283 OSKextLog(/* kext */ NULL,
9284 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9285 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9286 result = kOSKextReturnInternalError;
9287 goto finish;
9288 }
9289 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9290 if (portName == 0 || portName == MACH_PORT_DEAD) {
9291 OSKextLog(/* kext */ NULL,
9292 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9293 "Could not create send right for object.");
9294 result = kOSKextReturnInternalError;
9295 goto finish;
9296 }
9297 // Store the mach port name as a OSNumber
9298 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9299 if (!portNameNumber) {
9300 OSKextLog(/* kext */ NULL,
9301 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9302 "Could not create OSNumber object.");
9303 result = kOSKextReturnNoMemory;
9304 goto finish;
9305 }
9306 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9307 OSKextLog(/* kext */ NULL,
9308 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9309 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9310 result = kOSKextReturnNoMemory;
9311 goto finish;
9312 }
9313 }
9314 finish:
9315 if (result != kOSReturnSuccess) {
9316 break;
9317 }
9318 }
9319 return result;
9320 }
9321
9322 /*********************************************************************
9323 * XXX - this function is a big ugly mess
9324 *********************************************************************/
9325 /* static */
9326 OSReturn
9327 OSKext::handleRequest(
9328 host_priv_t hostPriv,
9329 OSKextLogSpec clientLogFilter,
9330 char * requestBuffer,
9331 uint32_t requestLength,
9332 char ** responseOut,
9333 uint32_t * responseLengthOut,
9334 char ** logInfoOut,
9335 uint32_t * logInfoLengthOut)
9336 {
9337 OSReturn result = kOSReturnError;
9338 kern_return_t kmem_result = KERN_FAILURE;
9339
9340 char * response = NULL; // returned by reference
9341 uint32_t responseLength = 0;
9342
9343 bool taskCanManageAllKCs = false;
9344 bool taskOnlyManagesBootKC = false;
9345
9346 OSSharedPtr<OSObject> parsedXML;
9347 OSDictionary * requestDict = NULL; // do not release
9348 OSSharedPtr<OSString> errorString;
9349
9350 OSSharedPtr<OSObject> responseObject;
9351
9352 OSSharedPtr<OSSerialize> serializer;
9353
9354 OSSharedPtr<OSArray> logInfoArray;
9355
9356 OSString * predicate = NULL; // do not release
9357 OSString * kextIdentifier = NULL; // do not release
9358 OSArray * kextIdentifiers = NULL; // do not release
9359 OSKext * theKext = NULL; // do not release
9360 OSBoolean * boolArg = NULL; // do not release
9361
9362 IORecursiveLockLock(sKextLock);
9363
9364 if (responseOut) {
9365 *responseOut = NULL;
9366 *responseLengthOut = 0;
9367 }
9368 if (logInfoOut) {
9369 *logInfoOut = NULL;
9370 *logInfoLengthOut = 0;
9371 }
9372
9373 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9374
9375 /* XML must be nul-terminated.
9376 */
9377 if (requestBuffer[requestLength - 1] != '\0') {
9378 OSKextLog(/* kext */ NULL,
9379 kOSKextLogErrorLevel |
9380 kOSKextLogIPCFlag,
9381 "Invalid request from user space (not nul-terminated).");
9382 result = kOSKextReturnBadData;
9383 goto finish;
9384 }
9385 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
9386 if (parsedXML) {
9387 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
9388 }
9389 if (!requestDict) {
9390 const char * errorCString = "(unknown error)";
9391
9392 if (errorString && errorString->getCStringNoCopy()) {
9393 errorCString = errorString->getCStringNoCopy();
9394 } else if (parsedXML) {
9395 errorCString = "not a dictionary";
9396 }
9397 OSKextLog(/* kext */ NULL,
9398 kOSKextLogErrorLevel |
9399 kOSKextLogIPCFlag,
9400 "Error unserializing request from user space: %s.",
9401 errorCString);
9402 result = kOSKextReturnSerialization;
9403 goto finish;
9404 }
9405
9406 predicate = _OSKextGetRequestPredicate(requestDict);
9407 if (!predicate) {
9408 OSKextLog(/* kext */ NULL,
9409 kOSKextLogErrorLevel |
9410 kOSKextLogIPCFlag,
9411 "Recieved kext request from user space with no predicate.");
9412 result = kOSKextReturnInvalidArgument;
9413 goto finish;
9414 }
9415
9416 OSKextLog(/* kext */ NULL,
9417 kOSKextLogDebugLevel |
9418 kOSKextLogIPCFlag,
9419 "Received '%s' request from user space.",
9420 predicate->getCStringNoCopy());
9421
9422 /*
9423 * All management of file sets requires an entitlement
9424 */
9425 result = kOSKextReturnNotPrivileged;
9426 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9427 predicate->isEqualTo(kKextRequestPredicateStart) ||
9428 predicate->isEqualTo(kKextRequestPredicateStop) ||
9429 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9430 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9431 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9432 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9433 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9434 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9435 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9436 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9437 if (hostPriv == HOST_PRIV_NULL) {
9438 OSKextLog(/* kext */ NULL,
9439 kOSKextLogErrorLevel |
9440 kOSKextLogIPCFlag,
9441 "Access Failure - must be root user.");
9442 goto finish;
9443 }
9444 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
9445 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9446
9447 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9448 OSKextLog(/* kext */ NULL,
9449 kOSKextLogErrorLevel |
9450 kOSKextLogIPCFlag,
9451 "Access Failure - client not entitled to manage file sets.");
9452 goto finish;
9453 }
9454
9455 /*
9456 * The OnlyBootKC entitlement restricts the
9457 * collection-management entitlement to only managing kexts in
9458 * the BootKC. All other predicates that alter global state or
9459 * add new KCs are disallowed.
9460 */
9461 if (taskOnlyManagesBootKC &&
9462 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9463 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9464 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9465 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9466 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9467 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9468 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9469 OSKextLog(/* kext */ NULL,
9470 kOSKextLogErrorLevel |
9471 kOSKextLogIPCFlag,
9472 "Access Failure - client not entitled to manage non-primary KCs");
9473 goto finish;
9474 }
9475
9476 /*
9477 * If we get here, then the process either has the full KC
9478 * management entitlement, or it has the BootKC-only
9479 * entitlement and the request is about the BootKC.
9480 */
9481 }
9482
9483 /* Get common args in anticipation of use.
9484 */
9485 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9486 requestDict, kKextRequestArgumentBundleIdentifierKey));
9487 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9488 requestDict, kKextRequestArgumentBundleIdentifierKey));
9489 if (kextIdentifier) {
9490 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9491 }
9492 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9493 requestDict, kKextRequestArgumentValueKey));
9494
9495 if (taskOnlyManagesBootKC &&
9496 theKext &&
9497 theKext->isInFileset() &&
9498 theKext->kc_type != KCKindPrimary) {
9499 OSKextLog(/* kext */ NULL,
9500 kOSKextLogErrorLevel |
9501 kOSKextLogIPCFlag,
9502 "Access Failure - client not entitled to manage kext in non-primary KC");
9503 result = kOSKextReturnNotPrivileged;
9504 goto finish;
9505 }
9506
9507 result = kOSKextReturnInvalidArgument;
9508
9509 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9510 if (!kextIdentifier) {
9511 OSKextLog(/* kext */ NULL,
9512 kOSKextLogErrorLevel |
9513 kOSKextLogIPCFlag,
9514 "Invalid arguments to kext start request.");
9515 } else if (!theKext) {
9516 OSKextLog(/* kext */ NULL,
9517 kOSKextLogErrorLevel |
9518 kOSKextLogIPCFlag,
9519 "Kext %s not found for start request.",
9520 kextIdentifier->getCStringNoCopy());
9521 result = kOSKextReturnNotFound;
9522 } else {
9523 result = theKext->start();
9524 }
9525 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9526 if (!kextIdentifier) {
9527 OSKextLog(/* kext */ NULL,
9528 kOSKextLogErrorLevel |
9529 kOSKextLogIPCFlag,
9530 "Invalid arguments to kext stop request.");
9531 } else if (!theKext) {
9532 OSKextLog(/* kext */ NULL,
9533 kOSKextLogErrorLevel |
9534 kOSKextLogIPCFlag,
9535 "Kext %s not found for stop request.",
9536 kextIdentifier->getCStringNoCopy());
9537 result = kOSKextReturnNotFound;
9538 } else {
9539 result = theKext->stop();
9540 }
9541 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9542 result = OSKext::setMissingAuxKCBundles(requestDict);
9543 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9544 if (!kextIdentifier) {
9545 OSKextLog(/* kext */ NULL,
9546 kOSKextLogErrorLevel |
9547 kOSKextLogIPCFlag,
9548 "Invalid arguments to AuxKC Bundle Available request.");
9549 } else {
9550 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9551 }
9552 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9553 if (!kextIdentifier) {
9554 OSKextLog(/* kext */ NULL,
9555 kOSKextLogErrorLevel |
9556 kOSKextLogIPCFlag,
9557 "Invalid arguments to kext load from KC request.");
9558 } else if (!theKext) {
9559 OSKextLog(/* kext */ NULL,
9560 kOSKextLogErrorLevel |
9561 kOSKextLogIPCFlag,
9562 "Kext %s not found for load from KC request.",
9563 kextIdentifier->getCStringNoCopy());
9564 result = kOSKextReturnNotFound;
9565 } else if (!theKext->isInFileset()) {
9566 OSKextLog(/* kext */ NULL,
9567 kOSKextLogErrorLevel |
9568 kOSKextLogIPCFlag,
9569 "Kext %s does not exist in a KC: refusing to load.",
9570 kextIdentifier->getCStringNoCopy());
9571 result = kOSKextReturnNotLoadable;
9572 } else {
9573 result = OSKext::loadKextFromKC(theKext, requestDict);
9574 }
9575 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9576 if (!kextIdentifier) {
9577 OSKextLog(/* kext */ NULL,
9578 kOSKextLogErrorLevel |
9579 kOSKextLogIPCFlag,
9580 "Invalid arguments to codeless kext load interface (missing identifier).");
9581 } else {
9582 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9583 }
9584 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9585 if (!kextIdentifier) {
9586 OSKextLog(/* kext */ NULL,
9587 kOSKextLogErrorLevel |
9588 kOSKextLogIPCFlag,
9589 "Invalid arguments to kext unload request.");
9590 } else if (!theKext) {
9591 OSKextLog(/* kext */ NULL,
9592 kOSKextLogErrorLevel |
9593 kOSKextLogIPCFlag,
9594 "Kext %s not found for unload request.",
9595 kextIdentifier->getCStringNoCopy());
9596 result = kOSKextReturnNotFound;
9597 } else {
9598 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9599 _OSKextGetRequestArgument(requestDict,
9600 kKextRequestArgumentTerminateIOServicesKey));
9601 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9602 }
9603 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9604 result = OSKext::dispatchResource(requestDict);
9605 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9606 OSNumber *lookupNum = NULL;
9607 lookupNum = OSDynamicCast(OSNumber,
9608 _OSKextGetRequestArgument(requestDict,
9609 kKextRequestArgumentLookupAddressKey));
9610
9611 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9612 if (responseObject) {
9613 result = kOSReturnSuccess;
9614 } else {
9615 goto finish;
9616 }
9617 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
9618 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9619 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9620 OSBoolean * delayAutounloadBool = NULL;
9621 OSObject * infoKeysRaw = NULL;
9622 OSArray * infoKeys = NULL;
9623 uint32_t infoKeysCount = 0;
9624
9625 delayAutounloadBool = OSDynamicCast(OSBoolean,
9626 _OSKextGetRequestArgument(requestDict,
9627 kKextRequestArgumentDelayAutounloadKey));
9628
9629 /* If asked to delay autounload, reset the timer if it's currently set.
9630 * (That is, don't schedule an unload if one isn't already pending.
9631 */
9632 if (delayAutounloadBool == kOSBooleanTrue) {
9633 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9634 }
9635
9636 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9637 kKextRequestArgumentInfoKeysKey);
9638 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9639 if (infoKeysRaw && !infoKeys) {
9640 OSKextLog(/* kext */ NULL,
9641 kOSKextLogErrorLevel |
9642 kOSKextLogIPCFlag,
9643 "Invalid arguments to kext info request.");
9644 goto finish;
9645 }
9646
9647 if (infoKeys) {
9648 infoKeysCount = infoKeys->getCount();
9649 for (uint32_t i = 0; i < infoKeysCount; i++) {
9650 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9651 OSKextLog(/* kext */ NULL,
9652 kOSKextLogErrorLevel |
9653 kOSKextLogIPCFlag,
9654 "Invalid arguments to kext info request.");
9655 goto finish;
9656 }
9657 }
9658 }
9659
9660 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9661 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9662 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9663 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
9664 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9665 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
9666 }
9667
9668 if (!responseObject) {
9669 result = kOSKextReturnInternalError;
9670 } else {
9671 OSKextLog(/* kext */ NULL,
9672 kOSKextLogDebugLevel |
9673 kOSKextLogIPCFlag,
9674 "Returning loaded kext info.");
9675 result = kOSReturnSuccess;
9676 }
9677 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9678 /* Hand the current sKernelRequests array to the caller
9679 * (who must release it), and make a new one.
9680 */
9681 responseObject = os::move(sKernelRequests);
9682 sKernelRequests = OSArray::withCapacity(0);
9683 sPostedKextLoadIdentifiers->flushCollection();
9684 OSKextLog(/* kext */ NULL,
9685 kOSKextLogDebugLevel |
9686 kOSKextLogIPCFlag,
9687 "Returning kernel requests.");
9688 result = kOSReturnSuccess;
9689 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9690 /* Return the set of all requested bundle identifiers */
9691 responseObject = sAllKextLoadIdentifiers;
9692 OSKextLog(/* kext */ NULL,
9693 kOSKextLogDebugLevel |
9694 kOSKextLogIPCFlag,
9695 "Returning load requests.");
9696 result = kOSReturnSuccess;
9697 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9698 printf("KextLog: Loading FileSet KC(s)\n");
9699 result = OSKext::loadFileSetKexts(requestDict);
9700 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9701 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9702 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
9703 } else {
9704 OSKextLog(/* kext */ NULL,
9705 kOSKextLogDebugLevel |
9706 kOSKextLogIPCFlag,
9707 "Received '%s' invalid request from user space.",
9708 predicate->getCStringNoCopy());
9709 goto finish;
9710 }
9711
9712 /**********
9713 * Now we have handle the request, or not. Gather up the response & logging
9714 * info to ship to user space.
9715 *********/
9716
9717 /* Note: Nothing in OSKext is supposed to retain requestDict,
9718 * but you never know....
9719 */
9720 if (requestDict->getRetainCount() > 1) {
9721 OSKextLog(/* kext */ NULL,
9722 kOSKextLogWarningLevel |
9723 kOSKextLogIPCFlag,
9724 "Request from user space still retained by a kext; "
9725 "probable memory leak.");
9726 }
9727
9728 if (responseOut && responseObject) {
9729 serializer = OSSerialize::withCapacity(0);
9730 if (!serializer) {
9731 result = kOSKextReturnNoMemory;
9732 goto finish;
9733 }
9734 /*
9735 * Before serializing the kernel requests, patch the dext launch requests so
9736 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9737 * IOUserServerCheckInToken kernel object.
9738 */
9739 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9740 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9741 task_t calling_task = current_task();
9742 if (!requests) {
9743 OSKextLog(/* kext */ NULL,
9744 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9745 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9746 result = kOSKextReturnInternalError;
9747 goto finish;
9748 }
9749 result = patchDextLaunchRequests(calling_task, requests);
9750 if (result != kOSReturnSuccess) {
9751 OSKextLog(/* kext */ NULL,
9752 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9753 "Failed to patch dext launch requests.");
9754 goto finish;
9755 }
9756 }
9757
9758 if (!responseObject->serialize(serializer.get())) {
9759 OSKextLog(/* kext */ NULL,
9760 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9761 "Failed to serialize response to request from user space.");
9762 result = kOSKextReturnSerialization;
9763 goto finish;
9764 }
9765
9766 response = (char *)serializer->text();
9767 responseLength = serializer->getLength();
9768 }
9769
9770 if (responseOut && response) {
9771 char * buffer;
9772
9773 /* This kmem_alloc sets the return value of the function.
9774 */
9775 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9776 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
9777 if (kmem_result != KERN_SUCCESS) {
9778 OSKextLog(/* kext */ NULL,
9779 kOSKextLogErrorLevel |
9780 kOSKextLogIPCFlag,
9781 "Failed to copy response to request from user space.");
9782 result = kmem_result;
9783 goto finish;
9784 } else {
9785 /* 11981737 - clear uninitialized data in last page */
9786 bzero((void *)(buffer + responseLength),
9787 (round_page(responseLength) - responseLength));
9788 memcpy(buffer, response, responseLength);
9789 *responseOut = buffer;
9790 *responseLengthOut = responseLength;
9791 }
9792 }
9793
9794 finish:
9795
9796 /* Gather up the collected log messages for user space. Any messages
9797 * messages past this call will not make it up as log messages but
9798 * will be in the system log. Note that we ignore the return of the
9799 * serialize; it has no bearing on the operation at hand even if we
9800 * fail to get the log messages.
9801 */
9802 logInfoArray = OSKext::clearUserSpaceLogFilter();
9803
9804 if (logInfoArray && logInfoOut && logInfoLengthOut) {
9805 (void)OSKext::serializeLogInfo(logInfoArray.get(),
9806 logInfoOut, logInfoLengthOut);
9807 }
9808
9809 IORecursiveLockUnlock(sKextLock);
9810
9811 return result;
9812 }
9813
9814 #if PRAGMA_MARK
9815 #pragma mark Linked Kext Collection Support
9816 #endif
9817
9818 static int
9819 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9820 {
9821 for (int i = 0; i < segCount; i++) {
9822 vm_offset_t segStart = segAddrs[i];
9823 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9824
9825 if (theAddr >= segStart && theAddr < segEnd) {
9826 return i;
9827 }
9828 }
9829 return -1;
9830 }
9831
9832 static void
9833 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
9834 kernel_segment_command_t *kextTextSeg,
9835 OSData *kaslrOffsets)
9836 {
9837 static const char *plk_segNames[] = {
9838 "__TEXT",
9839 "__TEXT_EXEC",
9840 "__DATA",
9841 "__DATA_CONST",
9842 "__LINKEDIT",
9843 "__PRELINK_TEXT",
9844 "__PLK_TEXT_EXEC",
9845 "__PRELINK_DATA",
9846 "__PLK_DATA_CONST",
9847 "__PLK_LLVM_COV",
9848 "__PLK_LINKEDIT",
9849 "__PRELINK_INFO"
9850 };
9851 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9852
9853 unsigned long plk_segSizes[num_plk_seg];
9854 vm_offset_t plk_segAddrs[num_plk_seg];
9855
9856 for (size_t i = 0; i < num_plk_seg; i++) {
9857 plk_segSizes[i] = 0;
9858 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9859 }
9860
9861 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9862
9863 int slidKextAddrCount = 0;
9864 int badSlideAddr = 0;
9865 int badSlideTarget = 0;
9866
9867 struct kaslrPackedOffsets {
9868 uint32_t count; /* number of offsets */
9869 uint32_t offsetsArray[]; /* offsets to slide */
9870 };
9871 const struct kaslrPackedOffsets *myOffsets = NULL;
9872 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9873
9874 for (uint32_t j = 0; j < myOffsets->count; j++) {
9875 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9876 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9877 int slideAddrSegIndex = -1;
9878 int addrToSlideSegIndex = -1;
9879
9880 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9881 if (slideAddrSegIndex >= 0) {
9882 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9883 if (addrToSlideSegIndex < 0) {
9884 badSlideTarget++;
9885 continue;
9886 }
9887 } else {
9888 badSlideAddr++;
9889 continue;
9890 }
9891
9892 slidKextAddrCount++;
9893 *slideAddr = ml_static_slide(*slideAddr);
9894 } // for ...
9895 }
9896
9897
9898
9899 /********************************************************************
9900 * addKextsFromKextCollection
9901 *
9902 * Input: MachO header of kext collection. The MachO is assumed to
9903 * have a section named 'info_seg_name,info_sect_name' that
9904 * contains a serialized XML info dictionary. This dictionary
9905 * contains a UUID, possibly a set of relocations (for older
9906 * kxld-built binaries), and an array of kext personalities.
9907 *
9908 ********************************************************************/
9909 bool
9910 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9911 OSDictionary *infoDict, const char *text_seg_name,
9912 OSData **kcUUID, kc_kind_t type)
9913 {
9914 bool result = false;
9915
9916 OSArray *kextArray = NULL; // do not release
9917 OSData *infoDictKCUUID = NULL; // do not release
9918 OSData *kaslrOffsets = NULL; // do not release
9919
9920 IORegistryEntry *registryRoot = NULL; // do not release
9921 OSSharedPtr<OSNumber> kcKextCount;
9922
9923 /* extract the KC UUID from the dictionary */
9924 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9925 if (infoDictKCUUID) {
9926 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9927 panic("kcUUID length is %d, expected %lu",
9928 infoDictKCUUID->getLength(), sizeof(uuid_t));
9929 }
9930 }
9931
9932 /* locate the array of kext dictionaries */
9933 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9934 if (!kextArray) {
9935 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9936 "The given KC has no kext info dictionaries");
9937 goto finish;
9938 }
9939
9940 /*
9941 * old-style KASLR offsets may be present in the info dictionary. If
9942 * we find them, use them and eventually slide them.
9943 */
9944 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9945
9946 /*
9947 * Before processing any kexts, locate the special kext bundle which
9948 * contains a list of kexts that we are to prevent from loading.
9949 */
9950 createExcludeListFromPrelinkInfo(kextArray);
9951
9952 /*
9953 * Create OSKext objects for each kext we find in the array of kext
9954 * info plist dictionaries.
9955 */
9956 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9957 OSDictionary *kextDict = NULL;
9958 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9959 if (!kextDict) {
9960 OSKextLog(/* kext */ NULL,
9961 kOSKextLogErrorLevel |
9962 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9963 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9964 continue;
9965 }
9966
9967 /*
9968 * Create the kext for the entry, then release it, because the
9969 * kext system keeps a reference around until the kext is
9970 * explicitly removed. Any creation/registration failures are
9971 * already logged for us.
9972 */
9973 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9974 }
9975
9976 /*
9977 * slide old-style kxld relocations
9978 * NOTE: this is still used on embedded KCs built with kcgen
9979 * TODO: Remove this once we use the new kext linker everywhere!
9980 */
9981 if (kaslrOffsets && vm_kernel_slide > 0) {
9982 kernel_segment_command_t *text_segment = NULL;
9983 text_segment = getsegbynamefromheader(mh, text_seg_name);
9984 if (!text_segment) {
9985 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9986 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9987 goto finish;
9988 }
9989
9990 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9991 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9992 setAllVMAttributes();
9993 }
9994
9995 /* Store the number of prelinked kexts in the registry so we can tell
9996 * when the system has been started from a prelinked kernel.
9997 */
9998 registryRoot = IORegistryEntry::getRegistryRoot();
9999 assert(registryRoot);
10000
10001 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10002 assert(kcKextCount);
10003 if (kcKextCount) {
10004 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10005 OSNumber *num;
10006 num = OSDynamicCast(OSNumber, prop.get());
10007 if (num) {
10008 kcKextCount->addValue(num->unsigned64BitValue());
10009 }
10010 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10011 }
10012
10013 OSKextLog(/* kext */ NULL,
10014 kOSKextLogProgressLevel |
10015 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10016 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10017 "%u prelinked kexts", infoDict->getCount());
10018
10019
10020 if (kcUUID && infoDictKCUUID) {
10021 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10022 }
10023
10024 result = true;
10025
10026 finish:
10027 return result;
10028 }
10029
10030 bool
10031 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10032 OSDictionary *infoDict, const char *text_seg_name,
10033 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10034 {
10035 OSData *result = NULL;
10036 bool success = addKextsFromKextCollection(mh,
10037 infoDict,
10038 text_seg_name,
10039 &result,
10040 type);
10041 if (success) {
10042 kcUUID.reset(result, OSNoRetain);
10043 }
10044 return success;
10045 }
10046
10047 static OSSharedPtr<OSObject> deferredAuxKCXML;
10048 bool
10049 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10050 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10051 {
10052 if (type != KCKindAuxiliary) {
10053 return false;
10054 }
10055
10056 kernel_mach_header_t *_mh;
10057 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
10058 if (!_mh || _mh != mh) {
10059 return false;
10060 }
10061
10062 if (deferredAuxKCXML) {
10063 /* only allow this to be called once */
10064 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10065 "An Aux KC has already been registered for deferred processing.");
10066 return false;
10067 }
10068
10069 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
10070 if (!infoDict) {
10071 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10072 "The Aux KC has info dictionary");
10073 return false;
10074 }
10075
10076 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10077 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10078 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10079 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10080 return false;
10081 }
10082
10083 /*
10084 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10085 * sysctl can return the UUID to user space which will check this
10086 * value for errors.
10087 */
10088 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10089 kcUUID->getLength());
10090 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10091 auxkc_uuid_valid = TRUE;
10092
10093 deferredAuxKCXML = parsedXML;
10094
10095 return true;
10096 }
10097
10098 OSSharedPtr<OSObject>
10099 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10100 {
10101 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10102 return NULL;
10103 }
10104
10105 return os::move(deferredAuxKCXML);
10106 }
10107
10108 #if PRAGMA_MARK
10109 #pragma mark Profile-Guided-Optimization Support
10110 #endif
10111
10112 // #include <InstrProfiling.h>
10113 extern "C" {
10114 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10115 const char *DataEnd,
10116 const char *CountersBegin,
10117 const char *CountersEnd,
10118 const char *NamesBegin,
10119 const char *NamesEnd);
10120 int __llvm_profile_write_buffer_internal(char *Buffer,
10121 const char *DataBegin,
10122 const char *DataEnd,
10123 const char *CountersBegin,
10124 const char *CountersEnd,
10125 const char *NamesBegin,
10126 const char *NamesEnd);
10127 }
10128
10129
10130 static
10131 void
10132 OSKextPgoMetadataPut(char *pBuffer,
10133 size_t *position,
10134 size_t bufferSize,
10135 uint32_t *num_pairs,
10136 const char *key,
10137 const char *value)
10138 {
10139 size_t strlen_key = strlen(key);
10140 size_t strlen_value = strlen(value);
10141 size_t len = strlen(key) + 1 + strlen(value) + 1;
10142 char *pos = pBuffer + *position;
10143 *position += len;
10144 if (pBuffer && bufferSize && *position <= bufferSize) {
10145 memcpy(pos, key, strlen_key); pos += strlen_key;
10146 *(pos++) = '=';
10147 memcpy(pos, value, strlen_value); pos += strlen_value;
10148 *(pos++) = 0;
10149 if (num_pairs) {
10150 (*num_pairs)++;
10151 }
10152 }
10153 }
10154
10155
10156 static
10157 void
10158 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10159 {
10160 *position += strlen(key) + 1 + value_max + 1;
10161 }
10162
10163
10164 static
10165 void
10166 OSKextPgoMetadataPutAll(OSKext *kext,
10167 uuid_t instance_uuid,
10168 char *pBuffer,
10169 size_t *position,
10170 size_t bufferSize,
10171 uint32_t *num_pairs)
10172 {
10173 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10174 //log_10 2^16 ≈ 4.82
10175 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10176 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10177
10178 if (!pBuffer) {
10179 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10180 OSKextPgoMetadataPutMax(position, "UUID", 36);
10181 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10182 } else {
10183 uuid_string_t instance_uuid_string;
10184 uuid_unparse(instance_uuid, instance_uuid_string);
10185 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10186 "INSTANCE", instance_uuid_string);
10187
10188 OSSharedPtr<OSData> uuid_data;
10189 uuid_t uuid;
10190 uuid_string_t uuid_string;
10191 uuid_data = kext->copyUUID();
10192 if (uuid_data) {
10193 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10194 uuid_unparse(uuid, uuid_string);
10195 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10196 "UUID", uuid_string);
10197 }
10198
10199 clock_sec_t secs;
10200 clock_usec_t usecs;
10201 clock_get_calendar_microtime(&secs, &usecs);
10202 assert(usecs < 1000000);
10203 char timestamp[max_timestamp_string_size + 1];
10204 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10205 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10206 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10207 "TIMESTAMP", timestamp);
10208 }
10209
10210 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10211 "NAME", kext->getIdentifierCString());
10212
10213 char versionCString[kOSKextVersionMaxLength];
10214 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10215 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10216 "VERSION", versionCString);
10217 }
10218
10219 static
10220 size_t
10221 OSKextPgoMetadataSize(OSKext *kext)
10222 {
10223 size_t position = 0;
10224 uuid_t fakeuuid = {};
10225 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10226 return position;
10227 }
10228
10229 int
10230 OSKextGrabPgoDataLocked(OSKext *kext,
10231 bool metadata,
10232 uuid_t instance_uuid,
10233 uint64_t *pSize,
10234 char *pBuffer,
10235 uint64_t bufferSize)
10236 {
10237 int err = 0;
10238
10239 kernel_section_t *sect_prf_data = NULL;
10240 kernel_section_t *sect_prf_name = NULL;
10241 kernel_section_t *sect_prf_cnts = NULL;
10242 uint64_t size;
10243 size_t metadata_size = 0;
10244 size_t offset_to_pairs = 0;
10245
10246 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10247 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10248 if (!sect_prf_name) {
10249 // kextcache sometimes truncates the section name to 15 chars
10250 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10251 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10252 }
10253 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10254
10255 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10256 err = ENOTSUP;
10257 goto out;
10258 }
10259
10260 size = __llvm_profile_get_size_for_buffer_internal(
10261 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10262 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10263 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10264
10265 if (metadata) {
10266 metadata_size = OSKextPgoMetadataSize(kext);
10267 size += metadata_size;
10268 size += sizeof(pgo_metadata_footer);
10269 }
10270
10271
10272 if (pSize) {
10273 *pSize = size;
10274 }
10275
10276 if (pBuffer && bufferSize) {
10277 if (bufferSize < size) {
10278 err = ERANGE;
10279 goto out;
10280 }
10281
10282 err = __llvm_profile_write_buffer_internal(
10283 pBuffer,
10284 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10285 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10286 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10287
10288 if (err) {
10289 err = EIO;
10290 goto out;
10291 }
10292
10293 if (metadata) {
10294 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10295 if (offset_to_pairs > UINT32_MAX) {
10296 err = E2BIG;
10297 goto out;
10298 }
10299
10300 char *end_of_buffer = pBuffer + size;
10301 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10302 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10303
10304 size_t metadata_position = 0;
10305 uint32_t num_pairs = 0;
10306 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10307 while (metadata_position < metadata_size) {
10308 metadata_buffer[metadata_position++] = 0;
10309 }
10310
10311 struct pgo_metadata_footer footer;
10312 footer.magic = htonl(0x6d657461);
10313 footer.number_of_pairs = htonl( num_pairs );
10314 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
10315 memcpy(footerp, &footer, sizeof(footer));
10316 }
10317 }
10318
10319 out:
10320 return err;
10321 }
10322
10323
10324 int
10325 OSKextGrabPgoData(uuid_t uuid,
10326 uint64_t *pSize,
10327 char *pBuffer,
10328 uint64_t bufferSize,
10329 int wait_for_unload,
10330 int metadata)
10331 {
10332 int err = 0;
10333 OSSharedPtr<OSKext> kext;
10334
10335
10336 IORecursiveLockLock(sKextLock);
10337
10338 kext = OSKext::lookupKextWithUUID(uuid);
10339 if (!kext) {
10340 err = ENOENT;
10341 goto out;
10342 }
10343
10344 if (wait_for_unload) {
10345 OSKextGrabPgoStruct s;
10346
10347 s.metadata = metadata;
10348 s.pSize = pSize;
10349 s.pBuffer = pBuffer;
10350 s.bufferSize = bufferSize;
10351 s.err = EINTR;
10352
10353 struct list_head *prev = &kext->pendingPgoHead;
10354 struct list_head *next = kext->pendingPgoHead.next;
10355
10356 s.list_head.prev = prev;
10357 s.list_head.next = next;
10358
10359 prev->next = &s.list_head;
10360 next->prev = &s.list_head;
10361
10362 kext.reset();
10363
10364 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
10365
10366 prev = s.list_head.prev;
10367 next = s.list_head.next;
10368
10369 prev->next = next;
10370 next->prev = prev;
10371
10372 err = s.err;
10373 } else {
10374 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
10375 }
10376
10377 out:
10378
10379 IORecursiveLockUnlock(sKextLock);
10380
10381 return err;
10382 }
10383
10384 void
10385 OSKextResetPgoCountersLock()
10386 {
10387 IORecursiveLockLock(sKextLock);
10388 }
10389
10390 void
10391 OSKextResetPgoCountersUnlock()
10392 {
10393 IORecursiveLockUnlock(sKextLock);
10394 }
10395
10396
10397 extern unsigned int not_in_kdp;
10398
10399 void
10400 OSKextResetPgoCounters()
10401 {
10402 assert(!not_in_kdp);
10403 uint32_t count = sLoadedKexts->getCount();
10404 for (uint32_t i = 0; i < count; i++) {
10405 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10406 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10407 if (!sect_prf_cnts) {
10408 continue;
10409 }
10410 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10411 }
10412 }
10413
10414 OSSharedPtr<OSDictionary>
10415 OSKext::copyLoadedKextInfoByUUID(
10416 OSArray * kextIdentifiers,
10417 OSArray * infoKeys)
10418 {
10419 OSSharedPtr<OSDictionary> result;
10420 OSSharedPtr<OSDictionary> kextInfo;
10421 uint32_t max_count, i, j;
10422 uint32_t idCount = 0;
10423 uint32_t idIndex = 0;
10424 IORecursiveLockLock(sKextLock);
10425 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
10426 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
10427
10428 #if CONFIG_MACF
10429 /* Is the calling process allowed to query kext info? */
10430 if (current_task() != kernel_task) {
10431 int macCheckResult = 0;
10432 kauth_cred_t cred = NULL;
10433
10434 cred = kauth_cred_get_with_ref();
10435 macCheckResult = mac_kext_check_query(cred);
10436 kauth_cred_unref(&cred);
10437
10438 if (macCheckResult != 0) {
10439 OSKextLog(/* kext */ NULL,
10440 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10441 "Failed to query kext info (MAC policy error 0x%x).",
10442 macCheckResult);
10443 goto finish;
10444 }
10445 }
10446 #endif
10447
10448 /* Empty list of UUIDs is equivalent to no list (get all).
10449 */
10450 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10451 kextIdentifiers = NULL;
10452 } else if (kextIdentifiers) {
10453 idCount = kextIdentifiers->getCount();
10454 }
10455
10456 /* Same for keys.
10457 */
10458 if (infoKeys && !infoKeys->getCount()) {
10459 infoKeys = NULL;
10460 }
10461
10462 max_count = count[0] + count[1];
10463 result = OSDictionary::withCapacity(max_count);
10464 if (!result) {
10465 goto finish;
10466 }
10467
10468 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10469 for (i = 0; i < count[j]; i++) {
10470 OSKext *thisKext = NULL; // do not release
10471 Boolean includeThis = true;
10472 uuid_t thisKextUUID;
10473 uuid_t thisKextTextUUID;
10474 OSSharedPtr<OSData> uuid_data;
10475 uuid_string_t uuid_key;
10476
10477 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10478 if (!thisKext) {
10479 continue;
10480 }
10481
10482 uuid_data = thisKext->copyUUID();
10483 if (!uuid_data) {
10484 continue;
10485 }
10486
10487 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
10488
10489 uuid_unparse(thisKextUUID, uuid_key);
10490
10491 uuid_data = thisKext->copyTextUUID();
10492 if (!uuid_data) {
10493 continue;
10494 }
10495 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
10496
10497 /* Skip current kext if we have a list of UUIDs and
10498 * it isn't in the list.
10499 */
10500 if (kextIdentifiers) {
10501 includeThis = false;
10502
10503 for (idIndex = 0; idIndex < idCount; idIndex++) {
10504 const OSString* wantedUUID = OSDynamicCast(OSString,
10505 kextIdentifiers->getObject(idIndex));
10506
10507 uuid_t uuid;
10508 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10509
10510 if ((0 == uuid_compare(uuid, thisKextUUID))
10511 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10512 includeThis = true;
10513 /* Only need to find the first kext if multiple match,
10514 * ie. asking for the kernel uuid does not need to find
10515 * interface kexts or builtin static kexts.
10516 */
10517 kextIdentifiers->removeObject(idIndex);
10518 uuid_unparse(uuid, uuid_key);
10519 break;
10520 }
10521 }
10522 }
10523
10524 if (!includeThis) {
10525 continue;
10526 }
10527
10528 kextInfo = thisKext->copyInfo(infoKeys);
10529 if (kextInfo) {
10530 result->setObject(uuid_key, kextInfo.get());
10531 }
10532
10533 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10534 goto finish;
10535 }
10536 }
10537 }
10538
10539 finish:
10540 IORecursiveLockUnlock(sKextLock);
10541
10542 return result;
10543 }
10544
10545 /*********************************************************************
10546 *********************************************************************/
10547 /* static */
10548 OSSharedPtr<OSDictionary>
10549 OSKext::copyKextCollectionInfo(
10550 OSDictionary *requestDict,
10551 OSArray *infoKeys)
10552 {
10553 OSSharedPtr<OSDictionary> result;
10554 OSString *collectionType = NULL;
10555 OSObject *rawLoadedState = NULL;
10556 OSString *loadedState = NULL;
10557
10558 kc_kind_t kc_request_kind = KCKindUnknown;
10559 bool onlyLoaded = false;
10560 bool onlyUnloaded = false;
10561
10562 #if CONFIG_MACF
10563 /* Is the calling process allowed to query kext info? */
10564 if (current_task() != kernel_task) {
10565 int macCheckResult = 0;
10566 kauth_cred_t cred = NULL;
10567
10568 cred = kauth_cred_get_with_ref();
10569 macCheckResult = mac_kext_check_query(cred);
10570 kauth_cred_unref(&cred);
10571
10572 if (macCheckResult != 0) {
10573 OSKextLog(/* kext */ NULL,
10574 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10575 "Failed to query kext info (MAC policy error 0x%x).",
10576 macCheckResult);
10577 goto finish;
10578 }
10579 }
10580 #endif
10581
10582 if (infoKeys && !infoKeys->getCount()) {
10583 infoKeys = NULL;
10584 }
10585
10586 collectionType = OSDynamicCast(OSString,
10587 _OSKextGetRequestArgument(requestDict,
10588 kKextRequestArgumentCollectionTypeKey));
10589 if (!collectionType) {
10590 OSKextLog(/* kext */ NULL,
10591 kOSKextLogErrorLevel |
10592 kOSKextLogIPCFlag,
10593 "Invalid '%s' argument to kext collection info request.",
10594 kKextRequestArgumentCollectionTypeKey);
10595 goto finish;
10596 }
10597 if (collectionType->isEqualTo(kKCTypePrimary)) {
10598 kc_request_kind = KCKindPrimary;
10599 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10600 kc_request_kind = KCKindPageable;
10601 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10602 kc_request_kind = KCKindAuxiliary;
10603 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10604 kc_request_kind = KCKindNone;
10605 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10606 OSKextLog(/* kext */ NULL,
10607 kOSKextLogErrorLevel |
10608 kOSKextLogIPCFlag,
10609 "Invalid '%s' argument value '%s' to kext collection info request.",
10610 kKextRequestArgumentCollectionTypeKey,
10611 collectionType->getCStringNoCopy());
10612 goto finish;
10613 }
10614
10615 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10616 kKextRequestArgumentLoadedStateKey);
10617 if (rawLoadedState) {
10618 loadedState = OSDynamicCast(OSString, rawLoadedState);
10619 if (!loadedState) {
10620 OSKextLog(/* kext */ NULL,
10621 kOSKextLogErrorLevel |
10622 kOSKextLogIPCFlag,
10623 "Invalid '%s' argument to kext collection info request.",
10624 kKextRequestArgumentLoadedStateKey);
10625 goto finish;
10626 }
10627 }
10628 if (loadedState) {
10629 if (loadedState->isEqualTo("Loaded")) {
10630 onlyLoaded = true;
10631 } else if (loadedState->isEqualTo("Unloaded")) {
10632 onlyUnloaded = true;
10633 } else if (!loadedState->isEqualTo("Any")) {
10634 OSKextLog(/* kext */ NULL,
10635 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10636 "Invalid '%s' argument value '%s' for '%s' collection info",
10637 kKextRequestArgumentLoadedStateKey,
10638 loadedState->getCStringNoCopy(),
10639 collectionType->getCStringNoCopy());
10640 goto finish;
10641 }
10642 }
10643
10644 result = OSDictionary::withCapacity(sKextsByID->getCount());
10645 if (!result) {
10646 goto finish;
10647 }
10648
10649 IORecursiveLockLock(sKextLock);
10650 { // start block scope
10651 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10652 {
10653 OSKext *thisKext = NULL; // do not release
10654 OSSharedPtr<OSDictionary> kextInfo;
10655
10656 (void)thisKextID;
10657
10658 thisKext = OSDynamicCast(OSKext, obj);
10659 if (!thisKext) {
10660 return false;
10661 }
10662
10663 /*
10664 * skip the kext if it came from the wrong collection type
10665 * (and the caller requested a specific type)
10666 */
10667 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10668 return false;
10669 }
10670
10671 /*
10672 * respect the caller's desire to find only loaded or
10673 * unloaded kexts
10674 */
10675 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10676 return false;
10677 }
10678 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10679 return false;
10680 }
10681
10682 kextInfo = thisKext->copyInfo(infoKeys);
10683 if (kextInfo) {
10684 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10685 }
10686 return false;
10687 });
10688 } // end block scope
10689 IORecursiveLockUnlock(sKextLock);
10690
10691 finish:
10692 return result;
10693 }
10694
10695 /*********************************************************************
10696 *********************************************************************/
10697 /* static */
10698 OSSharedPtr<OSDictionary>
10699 OSKext::copyLoadedKextInfo(
10700 OSArray * kextIdentifiers,
10701 OSArray * infoKeys)
10702 {
10703 OSSharedPtr<OSDictionary> result;
10704 uint32_t idCount = 0;
10705 bool onlyLoaded;
10706
10707 IORecursiveLockLock(sKextLock);
10708
10709 #if CONFIG_MACF
10710 /* Is the calling process allowed to query kext info? */
10711 if (current_task() != kernel_task) {
10712 int macCheckResult = 0;
10713 kauth_cred_t cred = NULL;
10714
10715 cred = kauth_cred_get_with_ref();
10716 macCheckResult = mac_kext_check_query(cred);
10717 kauth_cred_unref(&cred);
10718
10719 if (macCheckResult != 0) {
10720 OSKextLog(/* kext */ NULL,
10721 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10722 "Failed to query kext info (MAC policy error 0x%x).",
10723 macCheckResult);
10724 goto finish;
10725 }
10726 }
10727 #endif
10728
10729 /* Empty list of bundle ids is equivalent to no list (get all).
10730 */
10731 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10732 kextIdentifiers = NULL;
10733 } else if (kextIdentifiers) {
10734 idCount = kextIdentifiers->getCount();
10735 }
10736
10737 /* Same for keys.
10738 */
10739 if (infoKeys && !infoKeys->getCount()) {
10740 infoKeys = NULL;
10741 }
10742
10743 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10744
10745 result = OSDictionary::withCapacity(128);
10746 if (!result) {
10747 goto finish;
10748 }
10749
10750 #if 0
10751 OSKextLog(/* kext */ NULL,
10752 kOSKextLogErrorLevel |
10753 kOSKextLogGeneralFlag,
10754 "kaslr: vm_kernel_slide 0x%lx \n",
10755 vm_kernel_slide);
10756 OSKextLog(/* kext */ NULL,
10757 kOSKextLogErrorLevel |
10758 kOSKextLogGeneralFlag,
10759 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10760 vm_kernel_stext, vm_kernel_etext);
10761 OSKextLog(/* kext */ NULL,
10762 kOSKextLogErrorLevel |
10763 kOSKextLogGeneralFlag,
10764 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10765 vm_kernel_base, vm_kernel_top);
10766 OSKextLog(/* kext */ NULL,
10767 kOSKextLogErrorLevel |
10768 kOSKextLogGeneralFlag,
10769 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10770 vm_kext_base, vm_kext_top);
10771 OSKextLog(/* kext */ NULL,
10772 kOSKextLogErrorLevel |
10773 kOSKextLogGeneralFlag,
10774 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10775 vm_prelink_stext, vm_prelink_etext);
10776 OSKextLog(/* kext */ NULL,
10777 kOSKextLogErrorLevel |
10778 kOSKextLogGeneralFlag,
10779 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10780 vm_prelink_sinfo, vm_prelink_einfo);
10781 OSKextLog(/* kext */ NULL,
10782 kOSKextLogErrorLevel |
10783 kOSKextLogGeneralFlag,
10784 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10785 vm_slinkedit, vm_elinkedit);
10786 #endif
10787 { // start block scope
10788 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10789 {
10790 OSKext * thisKext = NULL; // do not release
10791 Boolean includeThis = true;
10792 OSSharedPtr<OSDictionary> kextInfo;
10793
10794 thisKext = OSDynamicCast(OSKext, obj);
10795 if (!thisKext) {
10796 return false;
10797 }
10798
10799 /* Skip current kext if not yet started and caller didn't request all.
10800 */
10801 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10802 return false;
10803 }
10804
10805 /* Skip current kext if we have a list of bundle IDs and
10806 * it isn't in the list.
10807 */
10808 if (kextIdentifiers) {
10809 includeThis = false;
10810
10811 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10812 const OSString * thisRequestID = OSDynamicCast(OSString,
10813 kextIdentifiers->getObject(idIndex));
10814 if (thisKextID->isEqualTo(thisRequestID)) {
10815 includeThis = true;
10816 break;
10817 }
10818 }
10819 }
10820
10821 if (!includeThis) {
10822 return false;
10823 }
10824
10825 kextInfo = thisKext->copyInfo(infoKeys);
10826 if (kextInfo) {
10827 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10828 }
10829 return false;
10830 });
10831 } // end block scope
10832
10833 finish:
10834 IORecursiveLockUnlock(sKextLock);
10835
10836 return result;
10837 }
10838
10839 /*********************************************************************
10840 * Any info that needs to do allocations must goto finish on alloc
10841 * failure. Info that is just a lookup should just not set the object
10842 * if the info does not exist.
10843 *********************************************************************/
10844 #define _OSKextLoadInfoDictCapacity (12)
10845
10846 OSSharedPtr<OSDictionary>
10847 OSKext::copyInfo(OSArray * infoKeys)
10848 {
10849 OSSharedPtr<OSDictionary> result;
10850 bool success = false;
10851 OSSharedPtr<OSData> headerData;
10852 OSSharedPtr<OSData> logData;
10853 OSSharedPtr<OSNumber> cpuTypeNumber;
10854 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10855 OSString * versionString = NULL; // do not release
10856 OSString * bundleType = NULL; // do not release
10857 uint32_t executablePathCStringSize = 0;
10858 char * executablePathCString = NULL; // must kfree
10859 OSSharedPtr<OSString> executablePathString;
10860 OSSharedPtr<OSData> uuid;
10861 OSSharedPtr<OSArray> dependencyLoadTags;
10862 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10863 OSSharedPtr<OSArray> metaClassInfo;
10864 OSSharedPtr<OSDictionary> metaClassDict;
10865 OSMetaClass * thisMetaClass = NULL; // do not release
10866 OSSharedPtr<OSString> metaClassName;
10867 OSSharedPtr<OSString> superclassName;
10868 kc_format_t kcformat;
10869 uint32_t count, i;
10870
10871 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10872 if (!result) {
10873 goto finish;
10874 }
10875
10876
10877 /* Empty keys means no keys, but NULL is quicker to check.
10878 */
10879 if (infoKeys && !infoKeys->getCount()) {
10880 infoKeys = NULL;
10881 }
10882
10883 if (!PE_get_primary_kc_format(&kcformat)) {
10884 goto finish;
10885 }
10886
10887 /* Headers, CPU type, and CPU subtype.
10888 */
10889 if (!infoKeys ||
10890 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10891 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10892 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10893 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10894 if (linkedExecutable && !isInterface()) {
10895 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10896 linkedExecutable->getBytesNoCopy();
10897
10898 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10899 // do not return macho header info on shipping embedded - 19095897
10900 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10901 kernel_mach_header_t * temp_kext_mach_hdr;
10902 struct load_command * lcp;
10903
10904 headerData = OSData::withBytes(kext_mach_hdr,
10905 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10906 if (!headerData) {
10907 goto finish;
10908 }
10909
10910 // unslide any vmaddrs we return to userspace - 10726716
10911 temp_kext_mach_hdr = (kernel_mach_header_t *)
10912 headerData->getBytesNoCopy();
10913 if (temp_kext_mach_hdr == NULL) {
10914 goto finish;
10915 }
10916
10917 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10918 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10919 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10920 kernel_segment_command_t * segp;
10921 kernel_section_t * secp;
10922
10923 segp = (kernel_segment_command_t *) lcp;
10924 // 10543468 - if we jettisoned __LINKEDIT clear size info
10925 if (flags.jettisonLinkeditSeg) {
10926 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10927 segp->vmsize = 0;
10928 segp->fileoff = 0;
10929 segp->filesize = 0;
10930 }
10931 }
10932
10933 #if __arm__ || __arm64__
10934 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10935 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10936 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10937 segp->vmaddr = gVirtBase;
10938 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10939 secp->size = 0; // paranoia :)
10940 secp->addr = gVirtBase;
10941 }
10942 }
10943 #endif
10944
10945 #if 0
10946 OSKextLog(/* kext */ NULL,
10947 kOSKextLogErrorLevel |
10948 kOSKextLogGeneralFlag,
10949 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10950 __FUNCTION__, segp->segname, segp->vmaddr,
10951 VM_KERNEL_UNSLIDE(segp->vmaddr),
10952 segp->vmsize, segp->nsects);
10953 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10954 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10955 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10956 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10957 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10958 OSKextLog(/* kext */ NULL,
10959 kOSKextLogErrorLevel |
10960 kOSKextLogGeneralFlag,
10961 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10962 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10963 }
10964 #endif
10965 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10966
10967 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10968 secp->addr = ml_static_unslide(secp->addr);
10969 }
10970 }
10971 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10972 }
10973 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
10974 }
10975 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10976
10977 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10978 osLogDataHeaderRef *header;
10979 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10980
10981 void *os_log_data = NULL;
10982 void *cstring_data = NULL;
10983 void *asan_cstring_data = NULL;
10984 unsigned long os_log_size = 0;
10985 unsigned long cstring_size = 0;
10986 unsigned long asan_cstring_size = 0;
10987 uint32_t os_log_offset = 0;
10988 uint32_t cstring_offset = 0;
10989 uint32_t asan_cstring_offset = 0;
10990 bool res;
10991
10992 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
10993 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
10994 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
10995 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
10996 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
10997 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
10998
10999 header = (osLogDataHeaderRef *) headerBytes;
11000 header->version = OS_LOG_HDR_VERSION;
11001 header->sect_count = NUM_OS_LOG_SECTIONS;
11002 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
11003 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
11004 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
11005 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
11006 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
11007 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
11008
11009
11010 logData = OSData::withValue(*header);
11011 if (!logData) {
11012 goto finish;
11013 }
11014 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11015 if (!res) {
11016 goto finish;
11017 }
11018 if (os_log_data) {
11019 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
11020 if (!res) {
11021 goto finish;
11022 }
11023 }
11024 if (cstring_data) {
11025 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
11026 if (!res) {
11027 goto finish;
11028 }
11029 }
11030 if (asan_cstring_data) {
11031 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
11032 if (!res) {
11033 goto finish;
11034 }
11035 }
11036 result->setObject(kOSBundleLogStringsKey, logData.get());
11037 }
11038
11039 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
11040 cpuTypeNumber = OSNumber::withNumber(
11041 (uint64_t) kext_mach_hdr->cputype,
11042 8 * sizeof(kext_mach_hdr->cputype));
11043 if (!cpuTypeNumber) {
11044 goto finish;
11045 }
11046 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
11047 }
11048
11049 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11050 cpuSubtypeNumber = OSNumber::withNumber(
11051 (uint64_t) kext_mach_hdr->cpusubtype,
11052 8 * sizeof(kext_mach_hdr->cpusubtype));
11053 if (!cpuSubtypeNumber) {
11054 goto finish;
11055 }
11056 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
11057 }
11058 } else {
11059 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11060 osLogDataHeaderRef *header;
11061 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11062 bool res;
11063
11064 header = (osLogDataHeaderRef *) headerBytes;
11065 header->version = OS_LOG_HDR_VERSION;
11066 header->sect_count = NUM_OS_LOG_SECTIONS;
11067 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
11068 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
11069 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
11070 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11071 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
11072 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11073
11074 logData = OSData::withValue(*header);
11075 if (!logData) {
11076 goto finish;
11077 }
11078 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11079 if (!res) {
11080 goto finish;
11081 }
11082 result->setObject(kOSBundleLogStringsKey, logData.get());
11083 }
11084 }
11085 }
11086
11087 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
11088 */
11089 result->setObject(kCFBundleIdentifierKey, bundleID.get());
11090
11091 /* CFBundlePackageType
11092 */
11093 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
11094 if (bundleType) {
11095 result->setObject(kCFBundlePackageTypeKey, bundleType);
11096 }
11097
11098 /* CFBundleVersion.
11099 */
11100 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
11101 versionString = OSDynamicCast(OSString,
11102 getPropertyForHostArch(kCFBundleVersionKey));
11103 if (versionString) {
11104 result->setObject(kCFBundleVersionKey, versionString);
11105 }
11106 }
11107
11108 /* OSBundleCompatibleVersion.
11109 */
11110 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
11111 versionString = OSDynamicCast(OSString,
11112 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
11113 if (versionString) {
11114 result->setObject(kOSBundleCompatibleVersionKey, versionString);
11115 }
11116 }
11117
11118 /* Path.
11119 */
11120 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
11121 if (path) {
11122 result->setObject(kOSBundlePathKey, path.get());
11123 }
11124 }
11125
11126
11127 /* OSBundleExecutablePath.
11128 */
11129 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
11130 if (path && executableRelPath) {
11131 uint32_t pathLength = path->getLength(); // gets incremented below
11132
11133 // +1 for slash, +1 for \0
11134 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11135
11136 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
11137 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
11138 if (!executablePathCString) {
11139 goto finish;
11140 }
11141 strlcpy(executablePathCString, path->getCStringNoCopy(),
11142 executablePathCStringSize);
11143 executablePathCString[pathLength++] = '/';
11144 executablePathCString[pathLength++] = '\0';
11145 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11146 executablePathCStringSize);
11147
11148 executablePathString = OSString::withCString(executablePathCString);
11149
11150 if (!executablePathString) {
11151 goto finish;
11152 }
11153
11154 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11155 } else if (flags.builtin) {
11156 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
11157 } else if (isDriverKit()) {
11158 if (path) {
11159 // +1 for slash, +1 for \0
11160 uint32_t pathLength = path->getLength();
11161 executablePathCStringSize = pathLength + 2;
11162
11163 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
11164 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
11165 if (!executablePathCString) {
11166 goto finish;
11167 }
11168 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11169 executablePathCString[pathLength++] = '/';
11170 executablePathCString[pathLength++] = '\0';
11171
11172 executablePathString = OSString::withCString(executablePathCString);
11173
11174 if (!executablePathString) {
11175 goto finish;
11176 }
11177
11178 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11179 }
11180 }
11181 }
11182
11183 /* UUID, if the kext has one.
11184 */
11185 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11186 uuid = copyUUID();
11187 if (uuid) {
11188 result->setObject(kOSBundleUUIDKey, uuid.get());
11189 }
11190 }
11191 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11192 uuid = copyTextUUID();
11193 if (uuid) {
11194 result->setObject(kOSBundleTextUUIDKey, uuid.get());
11195 }
11196 }
11197
11198 /*
11199 * Info.plist digest
11200 */
11201 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11202 OSData *digest;
11203 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11204 if (digest) {
11205 result->setObject(kOSKextInfoPlistDigestKey, digest);
11206 }
11207 }
11208
11209 /*
11210 * Collection type
11211 */
11212 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11213 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
11214 }
11215
11216 /*
11217 * Collection availability
11218 */
11219 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11220 result->setObject(kOSKextAuxKCAvailabilityKey,
11221 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11222 }
11223
11224 /*
11225 * Allows user load
11226 */
11227 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11228 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11229 if (allowUserLoad) {
11230 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11231 }
11232 }
11233
11234 /*
11235 * Bundle Dependencies (OSBundleLibraries)
11236 */
11237 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11238 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11239 if (libraries) {
11240 result->setObject(kOSBundleLibrariesKey, libraries);
11241 }
11242 }
11243
11244 /*****
11245 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11246 */
11247 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11248 result->setObject(kOSKernelResourceKey,
11249 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11250 }
11251
11252 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11253 result->setObject(kOSBundleIsInterfaceKey,
11254 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11255 }
11256
11257 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11258 result->setObject(kOSBundlePrelinkedKey,
11259 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
11260 }
11261
11262 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11263 result->setObject(kOSBundleStartedKey,
11264 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11265 }
11266
11267 /* LoadTag (Index).
11268 */
11269 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
11270 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
11271 /* numBits */ 8 * sizeof(loadTag));
11272 if (!scratchNumber) {
11273 goto finish;
11274 }
11275 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
11276 }
11277
11278 /* LoadAddress, LoadSize.
11279 */
11280 if (!infoKeys ||
11281 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11282 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11283 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11284 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11285 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11286 bool is_dext = isDriverKit();
11287 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
11288 /* These go to userspace via serialization, so we don't want any doubts
11289 * about their size.
11290 */
11291 uint64_t loadAddress = 0;
11292 uint32_t loadSize = 0;
11293 uint32_t wiredSize = 0;
11294 uint64_t execLoadAddress = 0;
11295 uint32_t execLoadSize = 0;
11296
11297 /* Interfaces always report 0 load address & size.
11298 * Just the way they roll.
11299 *
11300 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11301 * xxx - shouldn't have one!
11302 */
11303
11304 if (flags.builtin || linkedExecutable) {
11305 kernel_mach_header_t *mh = NULL;
11306 kernel_segment_command_t *seg = NULL;
11307
11308 if (flags.builtin) {
11309 loadAddress = kmod_info->address;
11310 loadSize = (uint32_t)kmod_info->size;
11311 } else {
11312 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11313 loadSize = linkedExecutable->getLength();
11314 }
11315 mh = (kernel_mach_header_t *)loadAddress;
11316 loadAddress = ml_static_unslide(loadAddress);
11317
11318 /* Walk through the kext, looking for the first executable
11319 * segment in case we were asked for its size/address.
11320 */
11321 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11322 if (seg->initprot & VM_PROT_EXECUTE) {
11323 execLoadAddress = ml_static_unslide(seg->vmaddr);
11324 execLoadSize = (uint32_t)seg->vmsize;
11325 break;
11326 }
11327 }
11328
11329 /* If we have a kmod_info struct, calculated the wired size
11330 * from that. Otherwise it's the full load size.
11331 */
11332 if (kmod_info) {
11333 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
11334 } else {
11335 wiredSize = loadSize;
11336 }
11337 } else if (is_dext) {
11338 /*
11339 * DriverKit userspace executables do not have a kernel linkedExecutable,
11340 * so we "fake" their address range with the LoadTag.
11341 */
11342 if (loadTag) {
11343 loadAddress = execLoadAddress = loadTag;
11344 loadSize = execLoadSize = 1;
11345 }
11346 }
11347
11348 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
11349 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11350 (unsigned long long)(loadAddress),
11351 /* numBits */ 8 * sizeof(loadAddress));
11352 if (!scratchNumber) {
11353 goto finish;
11354 }
11355 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
11356 }
11357 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11358 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11359 && loadAddress && loadSize) {
11360 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11361 if (!baseAddress) {
11362 goto finish;
11363 }
11364
11365 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11366 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11367 /* numBits */ 8 * sizeof(loadAddress));
11368 if (!scratchNumber) {
11369 goto finish;
11370 }
11371 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11372 }
11373 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11374 && (this == sKernelKext) && gBuiltinKmodsCount) {
11375 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
11376 }
11377 }
11378
11379 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
11380 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11381 (unsigned long long)(execLoadAddress),
11382 /* numBits */ 8 * sizeof(execLoadAddress));
11383 if (!scratchNumber) {
11384 goto finish;
11385 }
11386 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
11387 }
11388 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
11389 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11390 (unsigned long long)(loadSize),
11391 /* numBits */ 8 * sizeof(loadSize));
11392 if (!scratchNumber) {
11393 goto finish;
11394 }
11395 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
11396 }
11397 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
11398 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11399 (unsigned long long)(execLoadSize),
11400 /* numBits */ 8 * sizeof(execLoadSize));
11401 if (!scratchNumber) {
11402 goto finish;
11403 }
11404 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
11405 }
11406 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11407 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11408 (unsigned long long)(wiredSize),
11409 /* numBits */ 8 * sizeof(wiredSize));
11410 if (!scratchNumber) {
11411 goto finish;
11412 }
11413 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
11414 }
11415 }
11416 }
11417
11418 /* OSBundleDependencies. In descending order for
11419 * easy compatibility with kextstat(8).
11420 */
11421 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11422 if ((count = getNumDependencies())) {
11423 dependencyLoadTags = OSArray::withCapacity(count);
11424 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
11425
11426 i = count - 1;
11427 do {
11428 OSKext * dependency = OSDynamicCast(OSKext,
11429 dependencies->getObject(i));
11430
11431 if (!dependency) {
11432 continue;
11433 }
11434 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11435 (unsigned long long)dependency->getLoadTag(),
11436 /* numBits*/ 8 * sizeof(loadTag));
11437 if (!scratchNumber) {
11438 goto finish;
11439 }
11440 dependencyLoadTags->setObject(scratchNumber.get());
11441 } while (i--);
11442 }
11443 }
11444
11445 /* OSBundleMetaClasses.
11446 */
11447 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11448 if (metaClasses && metaClasses->getCount()) {
11449 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
11450 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11451 if (!metaClassIterator || !metaClassInfo) {
11452 goto finish;
11453 }
11454 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
11455
11456 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11457 metaClassIterator->getNextObject()))) {
11458 metaClassDict = OSDictionary::withCapacity(3);
11459 if (!metaClassDict) {
11460 goto finish;
11461 }
11462
11463 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11464 if (thisMetaClass->getSuperClass()) {
11465 superclassName = OSString::withCString(
11466 thisMetaClass->getSuperClass()->getClassName());
11467 }
11468 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
11469 8 * sizeof(unsigned int));
11470
11471 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11472 * of course.
11473 */
11474 if (!metaClassDict || !metaClassName || !scratchNumber) {
11475 goto finish;
11476 }
11477
11478 metaClassInfo->setObject(metaClassDict.get());
11479 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
11480 if (superclassName) {
11481 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
11482 }
11483 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
11484 }
11485 }
11486 }
11487
11488 /* OSBundleRetainCount.
11489 */
11490 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
11491 {
11492 int kextRetainCount = getRetainCount() - 1;
11493 if (isLoaded()) {
11494 kextRetainCount--;
11495 }
11496 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11497 (int)kextRetainCount,
11498 /* numBits*/ 8 * sizeof(int));
11499 if (scratchNumber) {
11500 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
11501 }
11502 }
11503 }
11504
11505 success = true;
11506
11507 finish:
11508 if (executablePathCString) {
11509 kfree_data(executablePathCString, executablePathCStringSize);
11510 }
11511 if (!success) {
11512 result.reset();
11513 }
11514 return result;
11515 }
11516
11517 /*********************************************************************
11518 *********************************************************************/
11519 /* static */
11520 bool
11521 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11522 {
11523 bool ok;
11524 OSSharedPtr<OSKext> kext;
11525
11526 IORecursiveLockLock(sKextLock);
11527 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
11528 IORecursiveLockUnlock(sKextLock);
11529
11530 if (!kext || !kext->path || !kext->userExecutableRelPath) {
11531 return false;
11532 }
11533 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11534 kext->path->getCStringNoCopy(),
11535 kext->userExecutableRelPath->getCStringNoCopy());
11536 ok = true;
11537
11538 return ok;
11539 }
11540
11541 /*********************************************************************
11542 *********************************************************************/
11543 /* static */
11544 OSReturn
11545 OSKext::requestResource(
11546 const char * kextIdentifierCString,
11547 const char * resourceNameCString,
11548 OSKextRequestResourceCallback callback,
11549 void * context,
11550 OSKextRequestTag * requestTagOut)
11551 {
11552 OSReturn result = kOSReturnError;
11553 OSSharedPtr<OSKext> callbackKext; // looked up
11554
11555 OSKextRequestTag requestTag = -1;
11556 OSSharedPtr<OSNumber> requestTagNum;
11557 OSSharedPtr<OSDictionary> requestDict;
11558 OSSharedPtr<OSString> kextIdentifier;
11559 OSSharedPtr<OSString> resourceName;
11560
11561 OSSharedPtr<OSDictionary> callbackRecord;
11562 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
11563
11564 OSSharedPtr<OSValueObject<void *> > contextWrapper;
11565
11566 IORecursiveLockLock(sKextLock);
11567
11568 if (requestTagOut) {
11569 *requestTagOut = kOSKextRequestTagInvalid;
11570 }
11571
11572 /* If requests to user space are disabled, don't go any further */
11573 if (!sKernelRequestsEnabled) {
11574 OSKextLog(/* kext */ NULL,
11575 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11576 "Can't request resource %s for %s - requests to user space are disabled.",
11577 resourceNameCString,
11578 kextIdentifierCString);
11579 result = kOSKextReturnDisabled;
11580 goto finish;
11581 }
11582
11583 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11584 result = kOSKextReturnInvalidArgument;
11585 goto finish;
11586 }
11587
11588 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11589 if (!callbackKext) {
11590 OSKextLog(/* kext */ NULL,
11591 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11592 "Resource request has bad callback address.");
11593 result = kOSKextReturnInvalidArgument;
11594 goto finish;
11595 }
11596 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11597 OSKextLog(/* kext */ NULL,
11598 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11599 "Resource request callback is in a kext that is not started.");
11600 result = kOSKextReturnInvalidArgument;
11601 goto finish;
11602 }
11603
11604 /* Do not allow any new requests to be made on a kext that is unloading.
11605 */
11606 if (callbackKext->flags.stopping) {
11607 result = kOSKextReturnStopping;
11608 goto finish;
11609 }
11610
11611 /* If we're wrapped the next available request tag around to the negative
11612 * numbers, we can't service any more requests.
11613 */
11614 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11615 OSKextLog(/* kext */ NULL,
11616 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11617 "No more request tags available; restart required.");
11618 result = kOSKextReturnNoResources;
11619 goto finish;
11620 }
11621 requestTag = sNextRequestTag++;
11622
11623 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
11624 requestDict);
11625 if (result != kOSReturnSuccess) {
11626 goto finish;
11627 }
11628
11629 kextIdentifier = OSString::withCString(kextIdentifierCString);
11630 resourceName = OSString::withCString(resourceNameCString);
11631 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11632 8 * sizeof(requestTag));
11633 if (!kextIdentifier ||
11634 !resourceName ||
11635 !requestTagNum ||
11636 !_OSKextSetRequestArgument(requestDict.get(),
11637 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11638 !_OSKextSetRequestArgument(requestDict.get(),
11639 kKextRequestArgumentNameKey, resourceName.get()) ||
11640 !_OSKextSetRequestArgument(requestDict.get(),
11641 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
11642 result = kOSKextReturnNoMemory;
11643 goto finish;
11644 }
11645
11646 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
11647 if (!callbackRecord) {
11648 result = kOSKextReturnNoMemory;
11649 goto finish;
11650 }
11651 // we validate callback address at call time
11652 callbackWrapper = OSValueObjectWithValue(callback);
11653 if (context) {
11654 contextWrapper = OSValueObjectWithValue(context);
11655 }
11656 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11657 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
11658 result = kOSKextReturnNoMemory;
11659 goto finish;
11660 }
11661
11662 if (context) {
11663 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11664 kKextRequestArgumentContextKey, contextWrapper.get())) {
11665 result = kOSKextReturnNoMemory;
11666 goto finish;
11667 }
11668 }
11669
11670 /* Only post the requests after all the other potential failure points
11671 * have been passed.
11672 */
11673 if (!sKernelRequests->setObject(requestDict.get()) ||
11674 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
11675 result = kOSKextReturnNoMemory;
11676 goto finish;
11677 }
11678
11679 OSKext::pingIOKitDaemon();
11680
11681 result = kOSReturnSuccess;
11682 if (requestTagOut) {
11683 *requestTagOut = requestTag;
11684 }
11685
11686 finish:
11687
11688 /* If we didn't succeed, yank the request & callback
11689 * from their holding arrays.
11690 */
11691 if (result != kOSReturnSuccess) {
11692 unsigned int index;
11693
11694 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
11695 if (index != (unsigned int)-1) {
11696 sKernelRequests->removeObject(index);
11697 }
11698 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
11699 if (index != (unsigned int)-1) {
11700 sRequestCallbackRecords->removeObject(index);
11701 }
11702 }
11703
11704 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11705
11706 IORecursiveLockUnlock(sKextLock);
11707
11708 return result;
11709 }
11710
11711 OSReturn
11712 OSKext::requestDaemonLaunch(
11713 OSString *kextIdentifier,
11714 OSString *serverName,
11715 OSNumber *serverTag,
11716 IOUserServerCheckInToken * checkInToken)
11717 {
11718 OSReturn result = kOSReturnError;
11719 OSSharedPtr<OSDictionary> requestDict;
11720
11721 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
11722 return kOSKextReturnInvalidArgument;
11723 }
11724
11725 IORecursiveLockLock(sKextLock);
11726
11727 OSKextLog(/* kext */ NULL,
11728 kOSKextLogDebugLevel |
11729 kOSKextLogGeneralFlag,
11730 "Requesting daemon launch for %s with serverName %s and tag %llu",
11731 kextIdentifier->getCStringNoCopy(),
11732 serverName->getCStringNoCopy(),
11733 serverTag->unsigned64BitValue()
11734 );
11735
11736 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
11737 if (result != kOSReturnSuccess) {
11738 goto finish;
11739 }
11740
11741 if (!_OSKextSetRequestArgument(requestDict.get(),
11742 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
11743 !_OSKextSetRequestArgument(requestDict.get(),
11744 kKextRequestArgumentDriverExtensionServerName, serverName) ||
11745 !_OSKextSetRequestArgument(requestDict.get(),
11746 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11747 !_OSKextSetRequestArgument(requestDict.get(),
11748 kKextRequestArgumentCheckInToken, checkInToken)) {
11749 result = kOSKextReturnNoMemory;
11750 goto finish;
11751 }
11752
11753 /* Only post the requests after all the other potential failure points
11754 * have been passed.
11755 */
11756 if (!sKernelRequests->setObject(requestDict.get())) {
11757 result = kOSKextReturnNoMemory;
11758 goto finish;
11759 }
11760 OSKext::pingIOKitDaemon();
11761
11762 result = kOSReturnSuccess;
11763 finish:
11764 IORecursiveLockUnlock(sKextLock);
11765 return result;
11766 }
11767
11768 /*********************************************************************
11769 * Assumes sKextLock is held.
11770 *********************************************************************/
11771 /* static */
11772 OSReturn
11773 OSKext::dequeueCallbackForRequestTag(
11774 OSKextRequestTag requestTag,
11775 OSSharedPtr<OSDictionary> &callbackRecordOut)
11776 {
11777 OSDictionary * callbackRecordOutRaw = NULL;
11778 OSReturn result;
11779
11780 result = dequeueCallbackForRequestTag(requestTag,
11781 &callbackRecordOutRaw);
11782
11783 if (kOSReturnSuccess == result) {
11784 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11785 }
11786
11787 return result;
11788 }
11789 OSReturn
11790 OSKext::dequeueCallbackForRequestTag(
11791 OSKextRequestTag requestTag,
11792 OSDictionary ** callbackRecordOut)
11793 {
11794 OSReturn result = kOSReturnError;
11795 OSSharedPtr<OSNumber> requestTagNum;
11796
11797 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11798 8 * sizeof(requestTag));
11799 if (!requestTagNum) {
11800 goto finish;
11801 }
11802
11803 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11804 callbackRecordOut);
11805
11806 finish:
11807 return result;
11808 }
11809
11810 /*********************************************************************
11811 * Assumes sKextLock is held.
11812 *********************************************************************/
11813 /* static */
11814 OSReturn
11815 OSKext::dequeueCallbackForRequestTag(
11816 OSNumber * requestTagNum,
11817 OSSharedPtr<OSDictionary> &callbackRecordOut)
11818 {
11819 OSDictionary * callbackRecordOutRaw = NULL;
11820 OSReturn result;
11821
11822 result = dequeueCallbackForRequestTag(requestTagNum,
11823 &callbackRecordOutRaw);
11824
11825 if (kOSReturnSuccess == result) {
11826 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11827 }
11828
11829 return result;
11830 }
11831 OSReturn
11832 OSKext::dequeueCallbackForRequestTag(
11833 OSNumber * requestTagNum,
11834 OSDictionary ** callbackRecordOut)
11835 {
11836 OSReturn result = kOSKextReturnInvalidArgument;
11837 OSDictionary * callbackRecord = NULL; // retain if matched!
11838 OSNumber * callbackTagNum = NULL; // do not release
11839 unsigned int count, i;
11840
11841 result = kOSReturnError;
11842 count = sRequestCallbackRecords->getCount();
11843 for (i = 0; i < count; i++) {
11844 callbackRecord = OSDynamicCast(OSDictionary,
11845 sRequestCallbackRecords->getObject(i));
11846 if (!callbackRecord) {
11847 goto finish;
11848 }
11849
11850 /* If we don't find a tag, we basically have a leak here. Maybe
11851 * we should just remove it.
11852 */
11853 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11854 callbackRecord, kKextRequestArgumentRequestTagKey));
11855 if (!callbackTagNum) {
11856 goto finish;
11857 }
11858
11859 /* We could be even more paranoid and check that all the incoming
11860 * args match what's in the callback record.
11861 */
11862 if (callbackTagNum->isEqualTo(requestTagNum)) {
11863 if (callbackRecordOut) {
11864 *callbackRecordOut = callbackRecord;
11865 callbackRecord->retain();
11866 }
11867 sRequestCallbackRecords->removeObject(i);
11868 result = kOSReturnSuccess;
11869 goto finish;
11870 }
11871 }
11872 result = kOSKextReturnNotFound;
11873
11874 finish:
11875 return result;
11876 }
11877
11878
11879 /*********************************************************************
11880 * Busy timeout triage
11881 *********************************************************************/
11882 /* static */
11883 bool
11884 OSKext::pendingIOKitDaemonRequests(void)
11885 {
11886 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11887 }
11888
11889 extern "C" int vm_enable_driverkit_shared_region;
11890
11891 /*********************************************************************
11892 * Acquires and releases sKextLock
11893 *
11894 * This function is designed to be called exactly once on boot by
11895 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11896 * kext and dext personalities, and then attempts to map a System
11897 * (pageable) KC and an Auxiliary (aux) KC.
11898 *
11899 * Even if the pageable or aux KC fail to load - this function will
11900 * not allow a second call. This avoids security issues where
11901 * kernelmanagerd has been compromised or the pageable kc has been
11902 * tampered with and the attacker attempts to re-load a malicious
11903 * variant.
11904 *
11905 * Return: if a KC fails to load the return value will contain:
11906 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11907 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11908 * Similarly, if the aux kc load fails, the return value will
11909 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11910 * compose with each other and with kOSKextReturnKCLoadFailure.
11911 *********************************************************************/
11912 /* static */
11913 OSReturn
11914 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11915 {
11916 static bool daemon_ready = false;
11917
11918 OSReturn ret = kOSKextReturnInvalidArgument;
11919 OSReturn kcerr = 0;
11920 bool start_matching = false;
11921
11922 bool allow_fileset_load = !daemon_ready;
11923 #if !(defined(__x86_64__) || defined(__i386__))
11924 /* never allow KCs full of kexts on non-x86 machines */
11925 allow_fileset_load = false;
11926 #endif
11927
11928 /*
11929 * Change with 70582300
11930 */
11931 #if 0 || !defined(VM_MAPPED_KEXTS)
11932 /*
11933 * On platforms that don't support the SystemKC or a file-backed
11934 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
11935 * needs to be queried before we load any codeless kexts or release
11936 * any 3rd party kexts to run. On platforms that support a file-backed
11937 * AuxKC, this process is done via the kext audit mechanism.
11938 */
11939
11940 printf("KextLog: waiting for kext receipt to be queried.\n");
11941 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
11942 IOSleep(30);
11943 }
11944 #endif /* !VM_MAPPED_KEXTS */
11945
11946 /*
11947 * Get the args from the request. Right now we need the file
11948 * name for the pageable and the aux kext collection file sets.
11949 */
11950 OSDictionary * requestArgs = NULL; // do not release
11951 OSString * pageable_filepath = NULL; // do not release
11952 OSString * aux_filepath = NULL; // do not release
11953 OSArray * codeless_kexts = NULL; // do not release
11954 OSNumber * enable_dk_shared_region = NULL; // do not release
11955
11956 kernel_mach_header_t *akc_mh = NULL;
11957
11958 requestArgs = OSDynamicCast(OSDictionary,
11959 requestDict->getObject(kKextRequestArgumentsKey));
11960
11961 if (requestArgs == NULL) {
11962 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11963 "KextLog: No arguments in plist for loading fileset kext\n");
11964 printf("KextLog: No arguments in plist for loading fileset kext\n");
11965 return ret;
11966 }
11967
11968 ret = kOSKextReturnDisabled;
11969
11970 IORecursiveLockLock(sKextLock);
11971
11972 if (!sLoadEnabled) {
11973 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11974 "KextLog: Kext loading is disabled (attempt to load KCs).");
11975 IORecursiveLockUnlock(sKextLock);
11976 return ret;
11977 }
11978
11979 pageable_filepath = OSDynamicCast(OSString,
11980 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11981
11982 if (allow_fileset_load && pageable_filepath != NULL) {
11983 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11984
11985 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11986 if (ret) {
11987 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11988 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11989
11990 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11991 ret = kOSKextReturnKCLoadFailure;
11992 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11993 goto try_auxkc;
11994 }
11995 /*
11996 * Even if the AuxKC fails to load, we still want to send
11997 * the System KC personalities to the catalog for matching
11998 */
11999 start_matching = true;
12000 } else if (pageable_filepath != NULL) {
12001 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12002 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
12003 ret = kOSKextReturnUnsupported;
12004 }
12005
12006 try_auxkc:
12007 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
12008 if (akc_mh) {
12009 /*
12010 * If we try to load a deferred AuxKC, then don't ever attempt
12011 * a filesystem map of a file
12012 */
12013 allow_fileset_load = false;
12014
12015 /*
12016 * This function is only called once per boot, so we haven't
12017 * yet loaded an AuxKC. If we have registered the AuxKC mach
12018 * header, that means that the kext collection has been placed
12019 * in memory for us by the booter, and is waiting for us to
12020 * process it. Grab the deferred XML plist of info
12021 * dictionaries and add all the kexts.
12022 */
12023 OSSharedPtr<OSObject> parsedXML;
12024 OSSharedPtr<OSData> loaded_kcUUID;
12025 OSDictionary *infoDict;
12026 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
12027 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12028 #if !defined(VM_MAPPED_KEXTS)
12029 /*
12030 * On platforms where we don't dynamically wire-down / page-in
12031 * kext memory, we need to maintain the invariant that if the
12032 * AuxKC in memory does not contain a kext receipt, then we
12033 * should not load any of the kexts.
12034 */
12035 size_t receipt_sz = 0;
12036 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
12037 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12038 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
12039 ret = kOSKextReturnKCLoadFailure;
12040 goto try_codeless;
12041 }
12042 #endif
12043 if (infoDict) {
12044 bool added;
12045 printf("KextLog: Adding kexts from in-memory AuxKC\n");
12046 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
12047 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
12048 if (!loaded_kcUUID) {
12049 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12050 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
12051 } else if (!added) {
12052 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12053 "KextLog: WARNING: Failed to load AuxKC from memory.");
12054 }
12055 /* only return success if the pageable load (above) was successful */
12056 if (ret != kOSKextReturnKCLoadFailure) {
12057 ret = kOSReturnSuccess;
12058 }
12059 /* the registration of the AuxKC parsed out the KC's UUID already */
12060 } else {
12061 if (daemon_ready) {
12062 /*
12063 * Complain, but don't return an error if this isn't the first time the
12064 * IOKit daemon is checking in. If the daemon ever restarts, we will
12065 * hit this case because we've already consumed the deferred personalities.
12066 * We return success here so that a call to this function from a restarted
12067 * daemon with no codeless kexts will succeed.
12068 */
12069 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12070 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
12071 if (ret != kOSKextReturnKCLoadFailure) {
12072 ret = kOSReturnSuccess;
12073 }
12074 } else {
12075 /* this is a real error case */
12076 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12077 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
12078 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
12079 ret = kOSKextReturnKCLoadFailure;
12080 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12081 }
12082 }
12083 }
12084
12085 aux_filepath = OSDynamicCast(OSString,
12086 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
12087 if (allow_fileset_load && aux_filepath != NULL) {
12088 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
12089
12090 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
12091 if (ret) {
12092 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12093 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12094
12095 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12096 ret = kOSKextReturnKCLoadFailure;
12097 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12098 goto try_codeless;
12099 }
12100 start_matching = true;
12101 } else if (aux_filepath != NULL) {
12102 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12103 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
12104 if (ret != kOSKextReturnKCLoadFailure) {
12105 ret = kOSKextReturnUnsupported;
12106 }
12107 }
12108
12109 try_codeless:
12110 /*
12111 * Load codeless kexts last so that there is no possibilty of a
12112 * codeless kext bundle ID preventing a kext in the system KC from
12113 * loading
12114 */
12115 codeless_kexts = OSDynamicCast(OSArray,
12116 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
12117 if (codeless_kexts != NULL) {
12118 uint32_t count = codeless_kexts->getCount();
12119 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12120 "KextLog: loading %d codeless kexts/dexts", count);
12121 for (uint32_t i = 0; i < count; i++) {
12122 OSDictionary *infoDict;
12123 infoDict = OSDynamicCast(OSDictionary,
12124 codeless_kexts->getObject(i));
12125 if (!infoDict) {
12126 continue;
12127 }
12128 // instantiate a new kext, and don't hold a reference
12129 // (the kext subsystem will hold one implicitly)
12130 OSKext::withCodelessInfo(infoDict);
12131 }
12132 /* ignore errors that are not KC load failures */
12133 if (ret != kOSKextReturnKCLoadFailure) {
12134 ret = kOSReturnSuccess;
12135 }
12136 start_matching = true;
12137 }
12138
12139 enable_dk_shared_region = OSDynamicCast(OSNumber,
12140 requestArgs->getObject(kKextRequestEnableDriverKitSharedRegionKey));
12141 if (enable_dk_shared_region != NULL && enable_dk_shared_region->unsigned64BitValue() == 1) {
12142 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12143 "KextLog: Enabling DriverKit shared region.");
12144 vm_enable_driverkit_shared_region = 1;
12145 }
12146
12147 /* send personalities to the IOCatalog once */
12148 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
12149 OSKext::sendAllKextPersonalitiesToCatalog(true);
12150 /*
12151 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12152 * things as active and start all the delayed matching: the
12153 * dext and codeless kext personalities should have all been
12154 * delivered via this one call.
12155 */
12156 if (!daemon_ready) {
12157 OSKext::setIOKitDaemonActive();
12158 OSKext::setDeferredLoadSucceeded(TRUE);
12159 IOService::iokitDaemonLaunched();
12160 }
12161 if (sOSKextWasResetAfterUserspaceReboot) {
12162 sOSKextWasResetAfterUserspaceReboot = false;
12163 OSKext::setIOKitDaemonActive();
12164 IOService::startDeferredMatches();
12165 }
12166 }
12167
12168 if (ret == kOSKextReturnKCLoadFailure) {
12169 ret |= kcerr;
12170 }
12171
12172 /*
12173 * Only allow this function to attempt to load the pageable and
12174 * aux KCs once per boot.
12175 */
12176 daemon_ready = true;
12177
12178 IORecursiveLockUnlock(sKextLock);
12179
12180 return ret;
12181 }
12182
12183 OSReturn
12184 OSKext::resetMutableSegments(void)
12185 {
12186 kernel_segment_command_t *seg = NULL;
12187 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12188 u_int index = 0;
12189 OSKextSavedMutableSegment *savedSegment = NULL;
12190 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12191 OSReturn err;
12192
12193 if (!savedMutableSegments) {
12194 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12195 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12196 err = kOSKextReturnInternalError;
12197 goto finish;
12198 }
12199
12200 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12201 if (!segmentIsMutable(seg)) {
12202 continue;
12203 }
12204 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12205 uint64_t vmsize = seg->vmsize;
12206 err = kOSKextReturnInternalError;
12207 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12208 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12209 assert(savedSegment);
12210 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12211 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12212 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12213 err = savedSegment->restoreContents(seg);
12214 if (err != kOSReturnSuccess) {
12215 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12216 }
12217 }
12218 }
12219 if (err != kOSReturnSuccess) {
12220 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12221 }
12222 }
12223 err = kOSReturnSuccess;
12224 finish:
12225 return err;
12226 }
12227
12228
12229 /*********************************************************************
12230 * Assumes sKextLock is held.
12231 *********************************************************************/
12232 /* static */
12233 OSReturn
12234 OSKext::loadKCFileSet(
12235 const char *filepath,
12236 kc_kind_t type)
12237 {
12238 #if VM_MAPPED_KEXTS
12239 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12240 OSReturn err;
12241 struct vnode *vp = NULL;
12242 void *fileset_control;
12243 off_t fsize;
12244 bool pageable = (type == KCKindPageable);
12245
12246 if ((pageable && pageableKCloaded) ||
12247 (!pageable && auxKCloaded)) {
12248 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12249 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12250
12251 return kOSKextReturnInvalidArgument;
12252 }
12253
12254 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12255 if (!pageable && !pageableKCloaded) {
12256 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12257 "Trying to load the Aux KC without loading the Pageable KC");
12258 return kOSKextReturnInvalidArgument;
12259 }
12260
12261 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12262
12263 if (fileset_control == NULL) {
12264 printf("Could not get memory control object for file %s", filepath);
12265
12266 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12267 "Could not get memory control object for file %s", filepath);
12268 return kOSKextReturnInvalidArgument;
12269 }
12270 if (vp == NULL) {
12271 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12272 "Could not find vnode for file %s", filepath);
12273 return kOSKextReturnInvalidArgument;
12274 }
12275
12276 kernel_mach_header_t *mh = NULL;
12277 uintptr_t slide = 0;
12278
12279 #if CONFIG_CSR
12280 /*
12281 * When SIP is enabled, the KC we map must be SIP-protected
12282 */
12283 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12284 struct vnode_attr va;
12285 int error;
12286 VATTR_INIT(&va);
12287 VATTR_WANTED(&va, va_flags);
12288 error = vnode_getattr(vp, &va, vfs_context_current());
12289 if (error) {
12290 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12291 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12292 err = kOSKextReturnInternalError;
12293 goto finish;
12294 }
12295 if (!(va.va_flags & SF_RESTRICTED)) {
12296 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12297 "Path to KC '%s' is not SIP-protected", filepath);
12298 err = kOSKextReturnInvalidArgument;
12299 goto finish;
12300 }
12301 }
12302 #endif
12303
12304 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12305 if (err) {
12306 printf("KextLog: mapKCFileSet returned %d\n", err);
12307
12308 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12309 "mapKCFileSet returned %d\n", err);
12310
12311 err = kOSKextReturnInvalidArgument;
12312 }
12313
12314 #if CONFIG_CSR
12315 finish:
12316 #endif
12317 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12318 assert(vp != NULL);
12319 if (err == kOSReturnSuccess) {
12320 PE_set_kc_vp(type, vp);
12321 if (pageable) {
12322 pageableKCloaded = true;
12323 } else {
12324 auxKCloaded = true;
12325 }
12326 } else {
12327 vnode_put(vp);
12328 }
12329
12330 return err;
12331 #else
12332 (void)filepath;
12333 (void)type;
12334 return kOSKextReturnUnsupported;
12335 #endif // VM_MAPPED_KEXTS
12336 }
12337
12338 #if defined(__x86_64__) || defined(__i386__)
12339 /*********************************************************************
12340 * Assumes sKextLock is held.
12341 *********************************************************************/
12342 /* static */
12343 OSReturn
12344 OSKext::mapKCFileSet(
12345 void *control,
12346 vm_size_t fsize,
12347 kernel_mach_header_t **mhp,
12348 off_t file_offset,
12349 uintptr_t *slidep,
12350 bool pageable,
12351 void *map_entry_list)
12352 {
12353 bool fileset_load = false;
12354 kern_return_t ret;
12355 OSReturn err;
12356 kernel_section_t *infoPlistSection = NULL;
12357 OSDictionary *infoDict = NULL;
12358
12359 OSSharedPtr<OSObject> parsedXML;
12360 OSSharedPtr<OSString> errorString;
12361 OSSharedPtr<OSData> loaded_kcUUID;
12362
12363 /* Check if initial load for file set */
12364 if (*mhp == NULL) {
12365 fileset_load = true;
12366
12367 /* Get a page aligned address from kext map to map the file */
12368 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12369 if (pagealigned_addr == 0) {
12370 return kOSKextReturnNoMemory;
12371 }
12372
12373 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12374
12375 /* Allocate memory for bailout mechanism */
12376 map_entry_list = allocate_kcfileset_map_entry_list();
12377 if (map_entry_list == NULL) {
12378 return kOSKextReturnNoMemory;
12379 }
12380 }
12381
12382 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12383 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12384 /* mhp and slideptr are updated by mapKCTextSegment */
12385 if (err) {
12386 if (fileset_load) {
12387 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12388 }
12389 return err;
12390 }
12391
12392 /* Initialize the kc header globals */
12393 if (fileset_load) {
12394 if (pageable) {
12395 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12396 } else {
12397 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12398 }
12399 }
12400
12401 /* Iterate through all the segments and map necessary segments */
12402 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12403 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12404 vm_map_offset_t start;
12405 kernel_mach_header_t *k_mh = NULL;
12406 kernel_segment_command_t * seg = NULL;
12407 struct fileset_entry_command *fse = NULL;
12408
12409 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12410 seg = (kernel_segment_command_t *)lcp;
12411 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12412 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12413 fse = (struct fileset_entry_command *)lcp;
12414 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12415
12416 /* Map the segments of the mach-o binary */
12417 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12418 if (err) {
12419 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12420 return kOSKextReturnInvalidArgument;
12421 }
12422 continue;
12423 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12424 /* Check if the Aux KC is built pageable style */
12425 if (!pageable && !fileset_load && !auxKCloaded) {
12426 resetAuxKCSegmentOnUnload = true;
12427 }
12428 continue;
12429 } else {
12430 continue;
12431 }
12432
12433 if (fileset_load) {
12434 if (seg->vmsize == 0) {
12435 continue;
12436 }
12437
12438 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12439 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12440 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12441 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12442 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12443 continue;
12444 }
12445 } else {
12446 if (seg->vmsize == 0) {
12447 continue;
12448 }
12449
12450 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12451 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12452 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12453 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12454 continue;
12455 }
12456 }
12457
12458 ret = vm_map_kcfileset_segment(
12459 &start, seg->vmsize,
12460 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12461
12462 if (ret != KERN_SUCCESS) {
12463 if (fileset_load) {
12464 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12465 }
12466 return kOSKextReturnInvalidArgument;
12467 }
12468 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12469 }
12470
12471 /* Return if regular mach-o */
12472 if (!fileset_load) {
12473 return 0;
12474 }
12475
12476 /*
12477 * Fixup for the Pageable KC and the Aux KC is done by
12478 * i386_slide_kext_collection_mh_addrs, but it differs in
12479 * following ways:
12480 *
12481 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12482 * The fixup of kext segments and kext load commands are done at kext
12483 * load time by calling i386_slide_individual_kext.
12484 *
12485 * AuxKC old style: Fixup all the segments and all the load commands.
12486 *
12487 * AuxKC pageable style: Same as the Pageable KC.
12488 */
12489 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12490 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12491 if (ret != KERN_SUCCESS) {
12492 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12493 return kOSKextReturnInvalidArgument;
12494 }
12495
12496 /* Get the prelink info dictionary */
12497 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12498 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12499 if (parsedXML) {
12500 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12501 }
12502
12503 if (!infoDict) {
12504 const char *errorCString = "(unknown error)";
12505
12506 if (errorString && errorString->getCStringNoCopy()) {
12507 errorCString = errorString->getCStringNoCopy();
12508 } else if (parsedXML) {
12509 errorCString = "not a dictionary";
12510 }
12511 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12512 "Error unserializing kext info plist section: %s.", errorCString);
12513 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12514 return kOSKextReturnInvalidArgument;
12515 }
12516
12517 /* Validate that the Kext Collection is prelinked to the loaded KC */
12518 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12519 if (err) {
12520 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12521 return kOSKextReturnInvalidArgument;
12522 }
12523
12524 /* Set Protection of Segments */
12525 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12526
12527 OSKext::addKextsFromKextCollection(*mhp,
12528 infoDict, kPrelinkTextSegment,
12529 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12530
12531 /* Copy in the KC UUID */
12532 if (!loaded_kcUUID) {
12533 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12534 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12535 } else if (pageable) {
12536 pageablekc_uuid_valid = TRUE;
12537 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12538 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12539 } else {
12540 auxkc_uuid_valid = TRUE;
12541 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12542 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12543 }
12544
12545 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12546
12547 return 0;
12548 }
12549
12550 /*********************************************************************
12551 * Assumes sKextLock is held.
12552 *********************************************************************/
12553 /* static */
12554 OSReturn
12555 OSKext::mapKCTextSegment(
12556 void *control,
12557 kernel_mach_header_t **mhp,
12558 off_t file_offset,
12559 uintptr_t *slidep,
12560 void *map_entry_list)
12561 {
12562 kern_return_t ret;
12563 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12564 PAGE_MASK);
12565 vm_map_offset_t load_command_map_size = 0;
12566 kernel_mach_header_t *base_mh = *mhp;
12567
12568 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12569 ret = vm_map_kcfileset_segment(
12570 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12571 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12572
12573 if (ret != KERN_SUCCESS) {
12574 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12575
12576 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12577 "Failed to map mach header of kc fileset with error %d", ret);
12578 return kOSKextReturnInvalidArgument;
12579 }
12580
12581 if (slidep) {
12582 /* Verify that it's an MH_FILESET */
12583 if (base_mh->filetype != MH_FILESET) {
12584 printf("Kext Log: mapKCTextSegment mach header filetype"
12585 " is not an MH_FILESET, it is %x", base_mh->filetype);
12586
12587 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12588 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12589
12590 /* Unmap the mach header */
12591 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12592 return kOSKextReturnInvalidArgument;
12593 }
12594 }
12595
12596 /* Map the remaining pages of load commands */
12597 if (base_mh->sizeofcmds > mach_header_map_size) {
12598 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12599 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12600
12601 /* Map the load commands */
12602 ret = vm_map_kcfileset_segment(
12603 &load_command_addr, load_command_map_size,
12604 (memory_object_control_t)control, file_offset + mach_header_map_size,
12605 (VM_PROT_READ | VM_PROT_WRITE));
12606
12607 if (ret != KERN_SUCCESS) {
12608 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12609 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12610 "Failed to map load commands of kc fileset with error %d", ret);
12611
12612 /* Unmap the mach header */
12613 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12614 return kOSKextReturnInvalidArgument;
12615 }
12616 }
12617
12618 kernel_segment_command_t *text_seg;
12619 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12620
12621 /* Calculate the slide and vm addr of mach header */
12622 if (slidep) {
12623 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12624 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12625 }
12626
12627 /* Cache the text segment size and file offset before unmapping */
12628 vm_map_offset_t text_segment_size = text_seg->vmsize;
12629 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12630 vm_prot_t text_maxprot = text_seg->maxprot;
12631
12632 /* Unmap the first page and loadcommands and map the text segment */
12633 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12634 assert(ret == KERN_SUCCESS);
12635
12636 if (load_command_map_size) {
12637 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12638 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12639 assert(ret == KERN_SUCCESS);
12640 }
12641
12642 /* Map the text segment at actual vm addr specified in fileset */
12643 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12644 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12645 if (ret != KERN_SUCCESS) {
12646 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12647 "Failed to map Text segment of kc fileset with error %d", ret);
12648 return kOSKextReturnInvalidArgument;
12649 }
12650
12651 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12652 return 0;
12653 }
12654
12655 /*********************************************************************
12656 * Assumes sKextLock is held.
12657 *********************************************************************/
12658 /* static */
12659 OSReturn
12660 OSKext::protectKCFileSet(
12661 kernel_mach_header_t *mh,
12662 kc_kind_t type)
12663 {
12664 vm_map_t kext_map = g_kext_map;
12665 kernel_segment_command_t * seg = NULL;
12666 vm_map_offset_t start = 0;
12667 vm_map_offset_t end = 0;
12668 OSReturn ret = 0;
12669
12670 /* Set VM permissions */
12671 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12672 while (seg) {
12673 start = round_page(seg->vmaddr);
12674 end = trunc_page(seg->vmaddr + seg->vmsize);
12675
12676 /*
12677 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12678 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12679 * for the Aux KC as well.
12680 */
12681 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12682 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12683 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12684 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12685 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12686 ret = OSKext_protect((kernel_mach_header_t *)mh,
12687 kext_map, start, end, seg->maxprot, TRUE, type);
12688 if (ret != KERN_SUCCESS) {
12689 printf("OSKext protect failed with error %d", ret);
12690 return kOSKextReturnInvalidArgument;
12691 }
12692
12693 ret = OSKext_protect((kernel_mach_header_t *)mh,
12694 kext_map, start, end, seg->initprot, FALSE, type);
12695 if (ret != KERN_SUCCESS) {
12696 printf("OSKext protect failed with error %d", ret);
12697 return kOSKextReturnInvalidArgument;
12698 }
12699
12700 ret = OSKext_wire((kernel_mach_header_t *)mh,
12701 kext_map, start, end, seg->initprot, FALSE, type);
12702 if (ret != KERN_SUCCESS) {
12703 printf("OSKext wire failed with error %d", ret);
12704 return kOSKextReturnInvalidArgument;
12705 }
12706 }
12707
12708 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12709 }
12710
12711 return 0;
12712 }
12713
12714 /*********************************************************************
12715 * Assumes sKextLock is held.
12716 *********************************************************************/
12717 /* static */
12718 void
12719 OSKext::freeKCFileSetcontrol(void)
12720 {
12721 PE_reset_all_kc_vp();
12722 }
12723
12724 /*********************************************************************
12725 * Assumes sKextLock is held.
12726 *
12727 * resetKCFileSetSegments: Kext start function expects data segment to
12728 * be pristine on every load, unmap the dirty segments on unload and
12729 * remap them from FileSet on disk. Remap all segments of kext since
12730 * fixups are done per kext and not per segment.
12731 *********************************************************************/
12732 OSReturn
12733 OSKext::resetKCFileSetSegments(void)
12734 {
12735 kernel_segment_command_t *seg = NULL;
12736 kernel_segment_command_t *text_seg;
12737 uint32_t text_fileoff;
12738 kernel_mach_header_t *k_mh = NULL;
12739 uintptr_t slide;
12740 struct vnode *vp = NULL;
12741 void *fileset_control = NULL;
12742 bool pageable = (kc_type == KCKindPageable);
12743 OSReturn err;
12744 kern_return_t kr;
12745
12746 /* Check the vnode reference is still available */
12747 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12748 if (vp == NULL) {
12749 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12750 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12751 return kOSKextReturnInternalError;
12752 }
12753
12754 fileset_control = ubc_getobject(vp, 0);
12755 assert(fileset_control != NULL);
12756
12757 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12758 "Kext %s resetting all segments", getIdentifierCString());
12759
12760 k_mh = (kernel_mach_header_t *)kmod_info->address;
12761 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12762 text_fileoff = text_seg->fileoff;
12763 slide = PE_get_kc_slide(kc_type);
12764
12765 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12766 while (seg) {
12767 if (seg->vmsize == 0) {
12768 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12769 continue;
12770 }
12771
12772 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12773 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12774 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12775 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12776 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12777 continue;
12778 }
12779
12780 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12781 assert(kr == KERN_SUCCESS);
12782 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12783 }
12784
12785 /* Unmap the text segment */
12786 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12787 assert(kr == KERN_SUCCESS);
12788
12789 /* Map all the segments of the kext */
12790 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12791 if (err) {
12792 panic("Could not reset segments of a mapped kext, error %x", err);
12793 }
12794
12795 /* Update address in kmod_info, since it has been reset */
12796 if (kmod_info->address) {
12797 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12798 }
12799
12800 return 0;
12801 }
12802
12803 /*********************************************************************
12804 * Mechanism to track all segment mapping while mapping KC fileset.
12805 *********************************************************************/
12806
12807 struct kcfileset_map_entry {
12808 vm_map_offset_t me_start;
12809 vm_map_offset_t me_size;
12810 };
12811
12812 struct kcfileset_map_entry_list {
12813 int kme_list_count;
12814 int kme_list_index;
12815 struct kcfileset_map_entry kme_list[];
12816 };
12817
12818 #define KCFILESET_MAP_ENTRY_MAX (16380)
12819
12820 static void *
12821 allocate_kcfileset_map_entry_list(void)
12822 {
12823 struct kcfileset_map_entry_list *entry_list;
12824
12825 entry_list = kalloc_type(struct kcfileset_map_entry_list,
12826 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
12827
12828 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12829 entry_list->kme_list_index = 0;
12830 return entry_list;
12831 }
12832
12833 static void
12834 add_kcfileset_map_entry(
12835 void *map_entry_list,
12836 vm_map_offset_t start,
12837 vm_map_offset_t size)
12838 {
12839 if (map_entry_list == NULL) {
12840 return;
12841 }
12842
12843 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12844
12845 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12846 panic("Ran out of map kc fileset list");
12847 }
12848
12849 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12850 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12851
12852 entry_list->kme_list_index++;
12853 }
12854
12855 static void
12856 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12857 void *map_entry_list,
12858 boolean_t unmap_entries,
12859 bool pageable)
12860 {
12861 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12862
12863 if (unmap_entries) {
12864 for (int i = 0; i < entry_list->kme_list_index; i++) {
12865 kern_return_t ret;
12866 ret = vm_unmap_kcfileset_segment(
12867 &(entry_list->kme_list[i].me_start),
12868 entry_list->kme_list[i].me_size);
12869 assert(ret == KERN_SUCCESS);
12870 }
12871
12872 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
12873 }
12874
12875 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
12876 KCFILESET_MAP_ENTRY_MAX, entry_list);
12877 }
12878
12879 /*********************************************************************
12880 * Mechanism to map kext segment.
12881 *********************************************************************/
12882
12883 kern_return_t
12884 vm_map_kcfileset_segment(
12885 vm_map_offset_t *start,
12886 vm_map_offset_t size,
12887 void *control,
12888 vm_object_offset_t fileoffset,
12889 vm_prot_t max_prot)
12890 {
12891 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
12892 vmk_flags.vmkf_no_copy_on_read = 1;
12893 vmk_flags.vmkf_cs_enforcement = 0;
12894 vmk_flags.vmkf_cs_enforcement_override = 1;
12895 kern_return_t ret;
12896
12897 /* Add Write to max prot to allow fixups */
12898 max_prot = max_prot | VM_PROT_WRITE;
12899
12900 /*
12901 * Map the segments from file as COPY mappings to
12902 * make sure changes on disk to the file does not affect
12903 * mapped segments.
12904 */
12905 ret = vm_map_enter_mem_object_control(
12906 g_kext_map,
12907 start,
12908 size,
12909 (mach_vm_offset_t)0,
12910 VM_FLAGS_FIXED,
12911 vmk_flags,
12912 VM_KERN_MEMORY_OSKEXT,
12913 (memory_object_control_t)control,
12914 fileoffset,
12915 TRUE, /* copy */
12916 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12917 VM_INHERIT_NONE);
12918
12919 return ret;
12920 }
12921
12922 kern_return_t
12923 vm_unmap_kcfileset_segment(
12924 vm_map_offset_t *start,
12925 vm_map_offset_t size)
12926 {
12927 return mach_vm_deallocate(g_kext_map, *start, size);
12928 }
12929
12930 #endif //(__x86_64__) || defined(__i386__)
12931
12932 /*********************************************************************
12933 * Assumes sKextLock is held.
12934 *********************************************************************/
12935 /* static */
12936 OSReturn
12937 OSKext::validateKCFileSetUUID(
12938 OSDictionary *infoDict,
12939 kc_kind_t type)
12940 {
12941 OSReturn ret = kOSReturnSuccess;
12942
12943 if (!kernelcache_uuid_valid) {
12944 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12945 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12946 ret = kOSKextReturnInvalidArgument;
12947 goto finish;
12948 }
12949 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12950 if (ret != 0) {
12951 goto finish;
12952 }
12953
12954 #if defined(__x86_64__) || defined(__i386__)
12955 /* Check if the Aux KC is prelinked to correct Pageable KC */
12956 if (type == KCKindAuxiliary) {
12957 if (!pageablekc_uuid_valid) {
12958 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12959 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12960 ret = kOSKextReturnInvalidArgument;
12961 goto finish;
12962 }
12963 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12964 if (ret != 0) {
12965 goto finish;
12966 }
12967 }
12968 #endif //(__x86_64__) || defined(__i386__)
12969
12970 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12971 finish:
12972 return ret;
12973 }
12974
12975 /*********************************************************************
12976 * Assumes sKextLock is held.
12977 *********************************************************************/
12978 /* static */
12979 OSReturn
12980 OSKext::validateKCUUIDfromPrelinkInfo(
12981 uuid_t *loaded_kcuuid,
12982 kc_kind_t type,
12983 OSDictionary *infoDict,
12984 const char *uuid_key)
12985 {
12986 /* extract the UUID from the dictionary */
12987 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12988 if (!prelinkinfoKCUUID) {
12989 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12990 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12991 return kOSKextReturnInvalidArgument;
12992 }
12993
12994 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12995 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12996 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12997 return kOSKextReturnInvalidArgument;
12998 }
12999
13000 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
13001 prelinkinfoKCUUID->getLength())) {
13002 OSData *info_dict_uuid;
13003 uuid_string_t info_dict_uuid_str = {};
13004 uuid_string_t expected_uuid_str = {};
13005 uuid_string_t given_uuid_str = {};
13006 uuid_t given_uuid;
13007
13008 /* extract the KC UUID from the dictionary */
13009 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
13010 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
13011 uuid_t tmp_uuid;
13012 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
13013 uuid_unparse(tmp_uuid, info_dict_uuid_str);
13014 }
13015
13016 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
13017 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
13018 uuid_unparse(given_uuid, given_uuid_str);
13019
13020 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
13021 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
13022 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13023 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
13024 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
13025 if (type == KCKindPageable && sPanicOnKCMismatch) {
13026 panic("System KC UUID %s linked against %s, but %s is loaded",
13027 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
13028 }
13029 return kOSKextReturnInvalidArgument;
13030 }
13031
13032 return 0;
13033 }
13034
13035 /*********************************************************************
13036 * Assumes sKextLock is held.
13037 *********************************************************************/
13038 /* static */
13039 OSReturn
13040 OSKext::dispatchResource(OSDictionary * requestDict)
13041 {
13042 OSReturn result = kOSReturnError;
13043 OSSharedPtr<OSDictionary> callbackRecord;
13044 OSNumber * requestTag = NULL; // do not release
13045 OSNumber * requestResult = NULL; // do not release
13046 OSData * dataObj = NULL; // do not release
13047 uint32_t dataLength = 0;
13048 const void * dataPtr = NULL; // do not free
13049 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
13050 OSKextRequestResourceCallback callback = NULL;
13051 OSValueObject<void *> * contextWrapper = nullptr; // do not release
13052 void * context = NULL; // do not free
13053 OSSharedPtr<OSKext> callbackKext;
13054
13055 /* Get the args from the request. Right now we need the tag
13056 * to look up the callback record, and the result for invoking the callback.
13057 */
13058 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
13059 kKextRequestArgumentRequestTagKey));
13060 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
13061 kKextRequestArgumentResultKey));
13062 if (!requestTag || !requestResult) {
13063 result = kOSKextReturnInvalidArgument;
13064 goto finish;
13065 }
13066
13067 /* Look for a callback record matching this request's tag.
13068 */
13069 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
13070 if (result != kOSReturnSuccess) {
13071 goto finish;
13072 }
13073
13074 /*****
13075 * Get the context pointer of the callback record (if there is one).
13076 */
13077 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
13078 callbackRecord.get(), kKextRequestArgumentContextKey));
13079 context = _OSKextExtractPointer(contextWrapper);
13080 if (contextWrapper && !context) {
13081 goto finish;
13082 }
13083
13084 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
13085 _OSKextGetRequestArgument(callbackRecord.get(),
13086 kKextRequestArgumentCallbackKey));
13087 callback = _OSKextExtractCallbackPointer(callbackWrapper);
13088 if (!callback) {
13089 goto finish;
13090 }
13091
13092 /* Check for a data obj. We might not have one and that's ok, that means
13093 * we didn't find the requested resource, and we still have to tell the
13094 * caller that via the callback.
13095 */
13096 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
13097 kKextRequestArgumentValueKey));
13098 if (dataObj) {
13099 dataPtr = dataObj->getBytesNoCopy();
13100 dataLength = dataObj->getLength();
13101 }
13102
13103 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
13104 if (!callbackKext) {
13105 OSKextLog(/* kext */ NULL,
13106 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13107 "Can't invoke callback for resource request; ");
13108 goto finish;
13109 }
13110 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
13111 OSKextLog(/* kext */ NULL,
13112 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13113 "Can't invoke kext resource callback; ");
13114 goto finish;
13115 }
13116
13117 (void)callback(requestTag->unsigned32BitValue(),
13118 (OSReturn)requestResult->unsigned32BitValue(),
13119 dataPtr, dataLength, context);
13120
13121 result = kOSReturnSuccess;
13122
13123 finish:
13124 return result;
13125 }
13126
13127 /*********************************************************************
13128 * Assumes sKextLock is held.
13129 *********************************************************************/
13130 /* static */
13131 OSReturn
13132 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
13133 {
13134 OSSharedPtr<OSDictionary> missingIDs;
13135 OSArray *bundleIDList = NULL; // do not release
13136
13137 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
13138 requestDict, kKextRequestArgumentMissingBundleIDs));
13139 if (!bundleIDList) {
13140 return kOSKextReturnInvalidArgument;
13141 }
13142
13143 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
13144 if (!missingIDs) {
13145 return kOSKextReturnNoMemory;
13146 }
13147
13148 uint32_t count, i;
13149 count = bundleIDList->getCount();
13150 for (i = 0; i < count; i++) {
13151 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
13152 if (thisID) {
13153 missingIDs->setObject(thisID, kOSBooleanFalse);
13154 }
13155 }
13156
13157 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13158
13159 return kOSReturnSuccess;
13160 }
13161
13162 /*********************************************************************
13163 * Assumes sKextLock is held.
13164 *********************************************************************/
13165 /* static */
13166 OSReturn
13167 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13168 {
13169 bool loadable = true;
13170 if (!kextIdentifier) {
13171 return kOSKextReturnInvalidArgument;
13172 }
13173
13174 if (requestDict) {
13175 OSBoolean *loadableArg;
13176 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13177 requestDict, kKextRequestArgumentBundleAvailability));
13178 /* If we find the "Bundle Available" arg, and it's false, then
13179 * mark the bundle ID as _not_ loadable
13180 */
13181 if (loadableArg && !loadableArg->getValue()) {
13182 loadable = false;
13183 }
13184 }
13185
13186 if (!sNonLoadableKextsByID) {
13187 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13188 }
13189
13190 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13191
13192 OSKextLog(/* kext */ NULL,
13193 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13194 "KextLog: AuxKC bundle %s marked as %s",
13195 kextIdentifier->getCStringNoCopy(),
13196 (loadable ? "loadable" : "NOT loadable"));
13197
13198 return kOSReturnSuccess;
13199 }
13200
13201 /*********************************************************************
13202 *********************************************************************/
13203 /* static */
13204 void
13205 OSKext::invokeRequestCallback(
13206 OSDictionary * callbackRecord,
13207 OSReturn callbackResult)
13208 {
13209 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
13210 OSSharedPtr<OSNumber> resultNum;
13211
13212 if (!predicate) {
13213 goto finish;
13214 }
13215
13216 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13217 8 * sizeof(callbackResult));
13218 if (!resultNum) {
13219 goto finish;
13220 }
13221
13222 /* Insert the result into the callback record and dispatch it as if it
13223 * were the reply coming down from user space.
13224 */
13225 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
13226 resultNum.get());
13227
13228 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13229 /* This removes the pending callback record.
13230 */
13231 OSKext::dispatchResource(callbackRecord);
13232 }
13233
13234 finish:
13235 return;
13236 }
13237
13238 /*********************************************************************
13239 * Assumes sKextLock is held.
13240 *********************************************************************/
13241 /* static */
13242 OSReturn
13243 OSKext::cancelRequest(
13244 OSKextRequestTag requestTag,
13245 void ** contextOut)
13246 {
13247 OSReturn result = kOSKextReturnNoMemory;
13248 OSSharedPtr<OSDictionary> callbackRecord;
13249 OSValueObject<void *> * contextWrapper = nullptr; // do not release
13250
13251 IORecursiveLockLock(sKextLock);
13252 result = OSKext::dequeueCallbackForRequestTag(requestTag,
13253 callbackRecord);
13254 IORecursiveLockUnlock(sKextLock);
13255
13256 if (result == kOSReturnSuccess && contextOut) {
13257 contextWrapper = OSDynamicCast(OSValueObject<void *>,
13258 _OSKextGetRequestArgument(callbackRecord.get(),
13259 kKextRequestArgumentContextKey));
13260 *contextOut = _OSKextExtractPointer(contextWrapper);
13261 }
13262
13263 return result;
13264 }
13265
13266 /*********************************************************************
13267 * Assumes sKextLock is held.
13268 *********************************************************************/
13269 void
13270 OSKext::invokeOrCancelRequestCallbacks(
13271 OSReturn callbackResult,
13272 bool invokeFlag)
13273 {
13274 unsigned int count, i;
13275
13276 count = sRequestCallbackRecords->getCount();
13277 if (!count) {
13278 goto finish;
13279 }
13280
13281 i = count - 1;
13282 do {
13283 OSDictionary * request = OSDynamicCast(OSDictionary,
13284 sRequestCallbackRecords->getObject(i));
13285
13286 if (!request) {
13287 continue;
13288 }
13289 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
13290 _OSKextGetRequestArgument(request,
13291 kKextRequestArgumentCallbackKey));
13292
13293 if (!callbackWrapper) {
13294 sRequestCallbackRecords->removeObject(i);
13295 continue;
13296 }
13297
13298 vm_address_t callbackAddress = (vm_address_t)
13299 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13300
13301 if ((kmod_info->address <= callbackAddress) &&
13302 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13303 if (invokeFlag) {
13304 /* This removes the callback record.
13305 */
13306 invokeRequestCallback(request, callbackResult);
13307 } else {
13308 sRequestCallbackRecords->removeObject(i);
13309 }
13310 }
13311 } while (i--);
13312
13313 finish:
13314 return;
13315 }
13316
13317 /*********************************************************************
13318 * Assumes sKextLock is held.
13319 *********************************************************************/
13320 uint32_t
13321 OSKext::countRequestCallbacks(void)
13322 {
13323 uint32_t result = 0;
13324 unsigned int count, i;
13325
13326 count = sRequestCallbackRecords->getCount();
13327 if (!count) {
13328 goto finish;
13329 }
13330
13331 i = count - 1;
13332 do {
13333 OSDictionary * request = OSDynamicCast(OSDictionary,
13334 sRequestCallbackRecords->getObject(i));
13335
13336 if (!request) {
13337 continue;
13338 }
13339 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
13340 _OSKextGetRequestArgument(request,
13341 kKextRequestArgumentCallbackKey));
13342
13343 if (!callbackWrapper) {
13344 continue;
13345 }
13346
13347 vm_address_t callbackAddress = (vm_address_t)
13348 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13349
13350 if ((kmod_info->address <= callbackAddress) &&
13351 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13352 result++;
13353 }
13354 } while (i--);
13355
13356 finish:
13357 return result;
13358 }
13359
13360 /*********************************************************************
13361 *********************************************************************/
13362 static OSReturn
13363 _OSKextCreateRequest(
13364 const char * predicate,
13365 OSSharedPtr<OSDictionary> & requestR)
13366 {
13367 OSReturn result = kOSKextReturnNoMemory;
13368 OSSharedPtr<OSDictionary> request;
13369
13370 request = OSDictionary::withCapacity(2);
13371 if (!request) {
13372 goto finish;
13373 }
13374 result = _OSDictionarySetCStringValue(request.get(),
13375 kKextRequestPredicateKey, predicate);
13376 if (result != kOSReturnSuccess) {
13377 goto finish;
13378 }
13379 result = kOSReturnSuccess;
13380
13381 finish:
13382 if (result == kOSReturnSuccess) {
13383 requestR = os::move(request);
13384 }
13385
13386 return result;
13387 }
13388
13389 /*********************************************************************
13390 *********************************************************************/
13391 static OSString *
13392 _OSKextGetRequestPredicate(OSDictionary * requestDict)
13393 {
13394 return OSDynamicCast(OSString,
13395 requestDict->getObject(kKextRequestPredicateKey));
13396 }
13397
13398 /*********************************************************************
13399 *********************************************************************/
13400 static OSObject *
13401 _OSKextGetRequestArgument(
13402 OSDictionary * requestDict,
13403 const char * argName)
13404 {
13405 OSDictionary * args = OSDynamicCast(OSDictionary,
13406 requestDict->getObject(kKextRequestArgumentsKey));
13407 if (args) {
13408 return args->getObject(argName);
13409 }
13410 return NULL;
13411 }
13412
13413 /*********************************************************************
13414 *********************************************************************/
13415 static bool
13416 _OSKextSetRequestArgument(
13417 OSDictionary * requestDict,
13418 const char * argName,
13419 OSMetaClassBase * value)
13420 {
13421 OSDictionary * args = OSDynamicCast(OSDictionary,
13422 requestDict->getObject(kKextRequestArgumentsKey));
13423 OSSharedPtr<OSDictionary> newArgs;
13424 if (!args) {
13425 newArgs = OSDictionary::withCapacity(2);
13426 args = newArgs.get();
13427 if (!args) {
13428 goto finish;
13429 }
13430 requestDict->setObject(kKextRequestArgumentsKey, args);
13431 }
13432 if (args) {
13433 return args->setObject(argName, value);
13434 }
13435 finish:
13436 return false;
13437 }
13438
13439 /*********************************************************************
13440 *********************************************************************/
13441 template <typename T>
13442 static T *
13443 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
13444 {
13445 if (!wrapper) {
13446 return nullptr;
13447 }
13448 return wrapper->getRef();
13449 }
13450
13451 /*********************************************************************
13452 *********************************************************************/
13453 static OSKextRequestResourceCallback
13454 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
13455 {
13456 if (!wrapper) {
13457 return nullptr;
13458 }
13459 return wrapper->getRef();
13460 }
13461
13462
13463 /*********************************************************************
13464 *********************************************************************/
13465 static OSReturn
13466 _OSDictionarySetCStringValue(
13467 OSDictionary * dict,
13468 const char * cKey,
13469 const char * cValue)
13470 {
13471 OSReturn result = kOSKextReturnNoMemory;
13472 OSSharedPtr<const OSSymbol> key;
13473 OSSharedPtr<OSString> value;
13474
13475 key = OSSymbol::withCString(cKey);
13476 value = OSString::withCString(cValue);
13477 if (!key || !value) {
13478 goto finish;
13479 }
13480 if (dict->setObject(key.get(), value.get())) {
13481 result = kOSReturnSuccess;
13482 }
13483
13484 finish:
13485 return result;
13486 }
13487
13488 /*********************************************************************
13489 *********************************************************************/
13490 static bool
13491 _OSArrayContainsCString(
13492 OSArray * array,
13493 const char * cString)
13494 {
13495 bool result = false;
13496 OSSharedPtr<const OSSymbol> symbol;
13497 uint32_t count, i;
13498
13499 if (!array || !cString) {
13500 goto finish;
13501 }
13502
13503 symbol = OSSymbol::withCStringNoCopy(cString);
13504 if (!symbol) {
13505 goto finish;
13506 }
13507
13508 count = array->getCount();
13509 for (i = 0; i < count; i++) {
13510 OSObject * thisObject = array->getObject(i);
13511 if (symbol->isEqualTo(thisObject)) {
13512 result = true;
13513 goto finish;
13514 }
13515 }
13516
13517 finish:
13518 return result;
13519 }
13520
13521 #if CONFIG_KXLD
13522 /*********************************************************************
13523 * We really only care about boot / system start up related kexts.
13524 * We return true if we're less than REBUILD_MAX_TIME since start up,
13525 * otherwise return false.
13526 *********************************************************************/
13527 bool
13528 _OSKextInPrelinkRebuildWindow(void)
13529 {
13530 static bool outside_the_window = false;
13531 AbsoluteTime my_abstime;
13532 UInt64 my_ns;
13533 SInt32 my_secs;
13534
13535 if (outside_the_window) {
13536 return false;
13537 }
13538 clock_get_uptime(&my_abstime);
13539 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13540 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13541 if (my_secs > REBUILD_MAX_TIME) {
13542 outside_the_window = true;
13543 return false;
13544 }
13545 return true;
13546 }
13547 #endif /* CONFIG_KXLD */
13548
13549 /*********************************************************************
13550 *********************************************************************/
13551 bool
13552 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13553 {
13554 int unLoadedCount, i;
13555 bool result = false;
13556
13557 IORecursiveLockLock(sKextLock);
13558
13559 if (sUnloadedPrelinkedKexts == NULL) {
13560 goto finish;
13561 }
13562 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13563 if (unLoadedCount == 0) {
13564 goto finish;
13565 }
13566
13567 for (i = 0; i < unLoadedCount; i++) {
13568 const OSSymbol * myBundleID; // do not release
13569
13570 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13571 if (!myBundleID) {
13572 continue;
13573 }
13574 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13575 result = true;
13576 break;
13577 }
13578 }
13579 finish:
13580 IORecursiveLockUnlock(sKextLock);
13581 return result;
13582 }
13583
13584 #if PRAGMA_MARK
13585 #pragma mark Personalities (IOKit Drivers)
13586 #endif
13587 /*********************************************************************
13588 *********************************************************************/
13589 /* static */
13590 OSSharedPtr<OSArray>
13591 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13592 {
13593 OSSharedPtr<OSArray> result;
13594 OSSharedPtr<OSCollectionIterator> kextIterator;
13595 OSSharedPtr<OSArray> personalities;
13596
13597 OSString * kextID = NULL; // do not release
13598 OSKext * theKext = NULL; // do not release
13599
13600 IORecursiveLockLock(sKextLock);
13601
13602 /* Let's conservatively guess that any given kext has around 3
13603 * personalities for now.
13604 */
13605 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13606 if (!result) {
13607 goto finish;
13608 }
13609
13610 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
13611 if (!kextIterator) {
13612 goto finish;
13613 }
13614
13615 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
13616 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
13617 if (theKext->flags.requireExplicitLoad) {
13618 OSKextLog(theKext,
13619 kOSKextLogDebugLevel |
13620 kOSKextLogLoadFlag,
13621 "Kext %s requires an explicit kextload; "
13622 "omitting its personalities.",
13623 theKext->getIdentifierCString());
13624 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
13625 personalities = theKext->copyPersonalitiesArray();
13626 if (!personalities) {
13627 continue;
13628 }
13629 result->merge(personalities.get());
13630 } else {
13631 // xxx - check for better place to put this log msg
13632 OSKextLog(theKext,
13633 kOSKextLogWarningLevel |
13634 kOSKextLogLoadFlag,
13635 "Kext %s is not loadable during safe boot; "
13636 "omitting its personalities.",
13637 theKext->getIdentifierCString());
13638 }
13639 }
13640
13641 finish:
13642 IORecursiveLockUnlock(sKextLock);
13643
13644 return result;
13645 }
13646
13647 /*********************************************************************
13648 *********************************************************************/
13649 /* static */
13650 void
13651 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13652 {
13653 int numPersonalities = 0;
13654
13655 OSKextLog(/* kext */ NULL,
13656 kOSKextLogStepLevel |
13657 kOSKextLogLoadFlag,
13658 "Sending all eligible registered kexts' personalities "
13659 "to the IOCatalogue %s.",
13660 startMatching ? "and starting matching" : "but not starting matching");
13661
13662 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
13663 /* filterSafeBootFlag */ true);
13664
13665 if (personalities) {
13666 gIOCatalogue->addDrivers(personalities.get(), startMatching);
13667 numPersonalities = personalities->getCount();
13668 }
13669
13670 OSKextLog(/* kext */ NULL,
13671 kOSKextLogStepLevel |
13672 kOSKextLogLoadFlag,
13673 "%d kext personalit%s sent to the IOCatalogue; %s.",
13674 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13675 startMatching ? "matching started" : "matching not started");
13676 return;
13677 }
13678
13679 /*********************************************************************
13680 * Do not make a deep copy, just convert the IOKitPersonalities dict
13681 * to an array for sending to the IOCatalogue.
13682 *********************************************************************/
13683 OSSharedPtr<OSArray>
13684 OSKext::copyPersonalitiesArray(void)
13685 {
13686 OSSharedPtr<OSArray> result;
13687 OSDictionary * personalities = NULL; // do not release
13688 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
13689
13690 OSString * personalityName = NULL; // do not release
13691 OSString * personalityBundleIdentifier = NULL; // do not release
13692
13693 personalities = OSDynamicCast(OSDictionary,
13694 getPropertyForHostArch(kIOKitPersonalitiesKey));
13695 if (!personalities) {
13696 goto finish;
13697 }
13698
13699 result = OSArray::withCapacity(personalities->getCount());
13700 if (!result) {
13701 goto finish;
13702 }
13703
13704 personalitiesIterator =
13705 OSCollectionIterator::withCollection(personalities);
13706 if (!personalitiesIterator) {
13707 goto finish;
13708 }
13709 while ((personalityName = OSDynamicCast(OSString,
13710 personalitiesIterator->getNextObject()))) {
13711 OSDictionary * personality = OSDynamicCast(OSDictionary,
13712 personalities->getObject(personalityName));
13713
13714 if (personality) {
13715 /******
13716 * If the personality doesn't have a CFBundleIdentifier, or if it
13717 * differs from the kext's, insert the kext's ID so we can find it.
13718 * The publisher ID is used to remove personalities from bundles
13719 * correctly.
13720 */
13721 personalityBundleIdentifier = OSDynamicCast(OSString,
13722 personality->getObject(kCFBundleIdentifierKey));
13723
13724 if (!personalityBundleIdentifier) {
13725 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13726 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13727 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
13728 }
13729 }
13730
13731 result->setObject(personality);
13732 }
13733
13734 finish:
13735 return result;
13736 }
13737
13738 /*********************************************************************
13739 * Might want to change this to a bool return?
13740 *********************************************************************/
13741 OSReturn
13742 OSKext::sendPersonalitiesToCatalog(
13743 bool startMatching,
13744 OSArray * personalityNames)
13745 {
13746 OSReturn result = kOSReturnSuccess;
13747 OSSharedPtr<OSArray> personalitiesToSend;
13748 OSDictionary * kextPersonalities = NULL; // do not release
13749 int count, i;
13750
13751 if (!sLoadEnabled) {
13752 OSKextLog(this,
13753 kOSKextLogErrorLevel |
13754 kOSKextLogLoadFlag,
13755 "Kext loading is disabled (attempt to start matching for kext %s).",
13756 getIdentifierCString());
13757 result = kOSKextReturnDisabled;
13758 goto finish;
13759 }
13760
13761 if (sSafeBoot && !isLoadableInSafeBoot()) {
13762 OSKextLog(this,
13763 kOSKextLogErrorLevel |
13764 kOSKextLogLoadFlag,
13765 "Kext %s is not loadable during safe boot; "
13766 "not sending personalities to the IOCatalogue.",
13767 getIdentifierCString());
13768 result = kOSKextReturnNotLoadable;
13769 goto finish;
13770 }
13771
13772 if (!personalityNames || !personalityNames->getCount()) {
13773 personalitiesToSend = copyPersonalitiesArray();
13774 } else {
13775 kextPersonalities = OSDynamicCast(OSDictionary,
13776 getPropertyForHostArch(kIOKitPersonalitiesKey));
13777 if (!kextPersonalities || !kextPersonalities->getCount()) {
13778 // not an error
13779 goto finish;
13780 }
13781 personalitiesToSend = OSArray::withCapacity(0);
13782 if (!personalitiesToSend) {
13783 result = kOSKextReturnNoMemory;
13784 goto finish;
13785 }
13786 count = personalityNames->getCount();
13787 for (i = 0; i < count; i++) {
13788 OSString * name = OSDynamicCast(OSString,
13789 personalityNames->getObject(i));
13790 if (!name) {
13791 continue;
13792 }
13793 OSDictionary * personality = OSDynamicCast(OSDictionary,
13794 kextPersonalities->getObject(name));
13795 if (personality) {
13796 personalitiesToSend->setObject(personality);
13797 }
13798 }
13799 }
13800 if (personalitiesToSend) {
13801 unsigned numPersonalities = personalitiesToSend->getCount();
13802 OSKextLog(this,
13803 kOSKextLogStepLevel |
13804 kOSKextLogLoadFlag,
13805 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13806 getIdentifierCString(),
13807 numPersonalities,
13808 numPersonalities > 1 ? "ies" : "y",
13809 startMatching ? " and starting matching" : " but not starting matching");
13810 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
13811 }
13812 finish:
13813 return result;
13814 }
13815
13816 /*********************************************************************
13817 * xxx - We should allow removing the kext's declared personalities,
13818 * xxx - even with other bundle identifiers.
13819 *********************************************************************/
13820 void
13821 OSKext::removePersonalitiesFromCatalog(void)
13822 {
13823 OSSharedPtr<OSDictionary> personality;
13824
13825 personality = OSDictionary::withCapacity(1);
13826 if (!personality) {
13827 goto finish;
13828 }
13829 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
13830
13831 OSKextLog(this,
13832 kOSKextLogStepLevel |
13833 kOSKextLogLoadFlag,
13834 "Kext %s removing all personalities naming it from the IOCatalogue.",
13835 getIdentifierCString());
13836
13837 /* Have the IOCatalog remove all personalities matching this kext's
13838 * bundle ID and trigger matching anew.
13839 */
13840 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
13841
13842 finish:
13843 return;
13844 }
13845
13846
13847 #if PRAGMA_MARK
13848 #pragma mark Logging
13849 #endif
13850 /*********************************************************************
13851 * Do not call any function that takes sKextLock here!
13852 *********************************************************************/
13853 /* static */
13854 OSKextLogSpec
13855 OSKext::setUserSpaceLogFilter(
13856 OSKextLogSpec newUserLogFilter,
13857 bool captureFlag)
13858 {
13859 OSKextLogSpec result;
13860 bool allocError = false;
13861
13862 /* Do not call any function that takes sKextLoggingLock during
13863 * this critical block. That means do logging after.
13864 */
13865 IOLockLock(sKextLoggingLock);
13866
13867 result = sUserSpaceKextLogFilter;
13868 sUserSpaceKextLogFilter = newUserLogFilter;
13869
13870 if (newUserLogFilter && captureFlag &&
13871 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13872 // xxx - do some measurements for a good initial capacity?
13873 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13874 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13875
13876 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
13877 allocError = true;
13878 }
13879 }
13880
13881 IOLockUnlock(sKextLoggingLock);
13882
13883 /* If the config flag itself is changing, log the state change
13884 * going both ways, before setting up the user-space log arrays,
13885 * so that this is only logged in the kernel.
13886 */
13887 if (result != newUserLogFilter) {
13888 OSKextLog(/* kext */ NULL,
13889 kOSKextLogDebugLevel |
13890 kOSKextLogGeneralFlag,
13891 "User-space log flags changed from 0x%x to 0x%x.",
13892 result, newUserLogFilter);
13893 }
13894 if (allocError) {
13895 OSKextLog(/* kext */ NULL,
13896 kOSKextLogErrorLevel |
13897 kOSKextLogGeneralFlag,
13898 "Failed to allocate user-space log message arrays.");
13899 }
13900
13901 return result;
13902 }
13903
13904 /*********************************************************************
13905 * Do not call any function that takes sKextLock here!
13906 *********************************************************************/
13907 /* static */
13908 OSSharedPtr<OSArray>
13909 OSKext::clearUserSpaceLogFilter(void)
13910 {
13911 OSSharedPtr<OSArray> result;
13912 OSKextLogSpec oldLogFilter;
13913 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
13914
13915 /* Do not call any function that takes sKextLoggingLock during
13916 * this critical block. That means do logging after.
13917 */
13918 IOLockLock(sKextLoggingLock);
13919
13920 result = OSArray::withCapacity(2);
13921 if (result) {
13922 result->setObject(sUserSpaceLogSpecArray.get());
13923 result->setObject(sUserSpaceLogMessageArray.get());
13924 }
13925 sUserSpaceLogSpecArray.reset();
13926 sUserSpaceLogMessageArray.reset();
13927
13928 oldLogFilter = sUserSpaceKextLogFilter;
13929 sUserSpaceKextLogFilter = newLogFilter;
13930
13931 IOLockUnlock(sKextLoggingLock);
13932
13933 /* If the config flag itself is changing, log the state change
13934 * going both ways, after tearing down the user-space log
13935 * arrays, so this is only logged within the kernel.
13936 */
13937 if (oldLogFilter != newLogFilter) {
13938 OSKextLog(/* kext */ NULL,
13939 kOSKextLogDebugLevel |
13940 kOSKextLogGeneralFlag,
13941 "User-space log flags changed from 0x%x to 0x%x.",
13942 oldLogFilter, newLogFilter);
13943 }
13944
13945 return result;
13946 }
13947
13948
13949 /*********************************************************************
13950 * Do not call any function that takes sKextLock here!
13951 *********************************************************************/
13952 /* static */
13953 OSKextLogSpec
13954 OSKext::getUserSpaceLogFilter(void)
13955 {
13956 OSKextLogSpec result;
13957
13958 IOLockLock(sKextLoggingLock);
13959 result = sUserSpaceKextLogFilter;
13960 IOLockUnlock(sKextLoggingLock);
13961
13962 return result;
13963 }
13964
13965 /*********************************************************************
13966 * This function is called by OSMetaClass during kernel C++ setup.
13967 * Be careful what you access here; assume only OSKext::initialize()
13968 * has been called.
13969 *
13970 * Do not call any function that takes sKextLock here!
13971 *********************************************************************/
13972 #define VTRESET "\033[0m"
13973
13974 #define VTBOLD "\033[1m"
13975 #define VTUNDER "\033[4m"
13976
13977 #define VTRED "\033[31m"
13978 #define VTGREEN "\033[32m"
13979 #define VTYELLOW "\033[33m"
13980 #define VTBLUE "\033[34m"
13981 #define VTMAGENTA "\033[35m"
13982 #define VTCYAN "\033[36m"
13983
13984 inline const char *
13985 colorForFlags(OSKextLogSpec flags)
13986 {
13987 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13988
13989 switch (logLevel) {
13990 case kOSKextLogErrorLevel:
13991 return VTRED VTBOLD;
13992 case kOSKextLogWarningLevel:
13993 return VTRED;
13994 case kOSKextLogBasicLevel:
13995 return VTYELLOW VTUNDER;
13996 case kOSKextLogProgressLevel:
13997 return VTYELLOW;
13998 case kOSKextLogStepLevel:
13999 return VTGREEN;
14000 case kOSKextLogDetailLevel:
14001 return VTCYAN;
14002 case kOSKextLogDebugLevel:
14003 return VTMAGENTA;
14004 default:
14005 return ""; // white
14006 }
14007 }
14008
14009 inline bool
14010 logSpecMatch(
14011 OSKextLogSpec msgLogSpec,
14012 OSKextLogSpec logFilter)
14013 {
14014 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
14015 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
14016 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
14017
14018 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
14019 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
14020 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
14021
14022 /* Explicit messages always get logged.
14023 */
14024 if (msgLevel == kOSKextLogExplicitLevel) {
14025 return true;
14026 }
14027
14028 /* Warnings and errors are logged regardless of the flags.
14029 */
14030 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
14031 return true;
14032 }
14033
14034 /* A verbose message that isn't for a logging-enabled kext and isn't global
14035 * does *not* get logged.
14036 */
14037 if (!msgKextGlobal && !filterKextGlobal) {
14038 return false;
14039 }
14040
14041 /* Warnings and errors are logged regardless of the flags.
14042 * All other messages must fit the flags and
14043 * have a level at or below the filter.
14044 *
14045 */
14046 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
14047 return true;
14048 }
14049 return false;
14050 }
14051
14052 extern "C" {
14053 void
14054 OSKextLog(
14055 OSKext * aKext,
14056 OSKextLogSpec msgLogSpec,
14057 const char * format, ...)
14058 {
14059 va_list argList;
14060
14061 va_start(argList, format);
14062 OSKextVLog(aKext, msgLogSpec, format, argList);
14063 va_end(argList);
14064 }
14065
14066 void
14067 OSKextVLog(
14068 OSKext * aKext,
14069 OSKextLogSpec msgLogSpec,
14070 const char * format,
14071 va_list srcArgList)
14072 {
14073 extern int disableConsoleOutput;
14074
14075 bool logForKernel = false;
14076 bool logForUser = false;
14077 va_list argList;
14078 char stackBuffer[120];
14079 uint32_t length = 0;
14080 char * allocBuffer = NULL; // must kfree
14081 OSSharedPtr<OSNumber> logSpecNum;
14082 OSSharedPtr<OSString> logString;
14083 char * buffer = stackBuffer; // do not free
14084
14085 IOLockLock(sKextLoggingLock);
14086
14087 /* Set the kext/global bit in the message spec if we have no
14088 * kext or if the kext requests logging.
14089 */
14090 if (!aKext || aKext->flags.loggingEnabled) {
14091 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
14092 }
14093
14094 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
14095 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14096 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
14097 }
14098
14099 if (!(logForKernel || logForUser)) {
14100 goto finish;
14101 }
14102
14103 /* No goto from here until past va_end()!
14104 */
14105 va_copy(argList, srcArgList);
14106 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
14107 va_end(argList);
14108
14109 if (length + 1 >= sizeof(stackBuffer)) {
14110 allocBuffer = (char *)kalloc_data_tag(length + 1,
14111 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14112 if (!allocBuffer) {
14113 goto finish;
14114 }
14115
14116 /* No goto from here until past va_end()!
14117 */
14118 va_copy(argList, srcArgList);
14119 vsnprintf(allocBuffer, length + 1, format, argList);
14120 va_end(argList);
14121
14122 buffer = allocBuffer;
14123 }
14124
14125 /* If user space wants the log message, queue it up.
14126 */
14127 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14128 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
14129 logString = OSString::withCString(buffer);
14130 if (logSpecNum && logString) {
14131 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
14132 sUserSpaceLogMessageArray->setObject(logString.get());
14133 }
14134 }
14135
14136 /* Always log messages from the kernel according to the kernel's
14137 * log flags.
14138 */
14139 if (logForKernel) {
14140 /* If we are in console mode and have a custom log filter,
14141 * colorize the log message.
14142 */
14143 if (!disableConsoleOutput && sBootArgLogFilterFound) {
14144 const char * color = ""; // do not free
14145 color = colorForFlags(msgLogSpec);
14146 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14147 buffer, color[0] ? VTRESET : "");
14148 } else {
14149 printf("%s\n", buffer);
14150 }
14151 }
14152
14153 finish:
14154 IOLockUnlock(sKextLoggingLock);
14155
14156 if (allocBuffer) {
14157 kfree_data(allocBuffer, length + 1);
14158 }
14159 return;
14160 }
14161
14162 #if KASLR_IOREG_DEBUG
14163
14164 #define IOLOG_INDENT( the_indention ) \
14165 { \
14166 int i; \
14167 for ( i = 0; i < (the_indention); i++ ) { \
14168 IOLog(" "); \
14169 } \
14170 }
14171
14172 extern vm_offset_t vm_kernel_stext;
14173 extern vm_offset_t vm_kernel_etext;
14174 extern mach_vm_offset_t kext_alloc_base;
14175 extern mach_vm_offset_t kext_alloc_max;
14176
14177 bool ScanForAddrInObject(OSObject * theObject,
14178 int indent );
14179
14180 bool
14181 ScanForAddrInObject(OSObject * theObject,
14182 int indent)
14183 {
14184 const OSMetaClass * myTypeID;
14185 OSSharedPtr<OSCollectionIterator> myIter;
14186 OSSymbol * myKey;
14187 OSObject * myValue;
14188 bool myResult = false;
14189
14190 if (theObject == NULL) {
14191 IOLog("%s: theObject is NULL \n",
14192 __FUNCTION__);
14193 return myResult;
14194 }
14195
14196 myTypeID = OSTypeIDInst(theObject);
14197
14198 if (myTypeID == OSTypeID(OSDictionary)) {
14199 OSDictionary * myDictionary;
14200
14201 myDictionary = OSDynamicCast(OSDictionary, theObject);
14202 myIter = OSCollectionIterator::withCollection( myDictionary );
14203 if (myIter == NULL) {
14204 return myResult;
14205 }
14206
14207 // !! reset the iterator
14208 myIter->reset();
14209
14210 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14211 bool myTempResult;
14212
14213 myValue = myDictionary->getObject(myKey);
14214 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14215 if (myTempResult) {
14216 // if we ever get a true result return true
14217 myResult = true;
14218 IOLOG_INDENT(indent);
14219 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14220 }
14221 }
14222
14223 // !! release the iterator
14224 myIter.reset();
14225 } else if (myTypeID == OSTypeID(OSArray)) {
14226 OSArray * myArray;
14227
14228 myArray = OSDynamicCast(OSArray, theObject);
14229 myIter = OSCollectionIterator::withCollection(myArray);
14230 if (myIter == NULL) {
14231 return myResult;
14232 }
14233 // !! reset the iterator
14234 myIter->reset();
14235
14236 while ((myValue = myIter->getNextObject())) {
14237 bool myTempResult;
14238 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14239 if (myTempResult) {
14240 // if we ever get a true result return true
14241 myResult = true;
14242 IOLOG_INDENT(indent);
14243 IOLog("OSArray: \n");
14244 }
14245 }
14246 // !! release the iterator
14247 myIter.reset();
14248 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14249 // should we look for addresses in strings?
14250 } else if (myTypeID == OSTypeID(OSData)) {
14251 void * * myPtrPtr;
14252 unsigned int myLen;
14253 OSData * myDataObj;
14254
14255 myDataObj = OSDynamicCast(OSData, theObject);
14256 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14257 myLen = myDataObj->getLength();
14258
14259 if (myPtrPtr && myLen && myLen > 7) {
14260 int i;
14261 int myPtrCount = (myLen / sizeof(void *));
14262
14263 for (i = 0; i < myPtrCount; i++) {
14264 UInt64 numberValue = (UInt64) * (myPtrPtr);
14265
14266 if (kext_alloc_max != 0 &&
14267 numberValue >= kext_alloc_base &&
14268 numberValue < kext_alloc_max) {
14269 OSSharedPtr<OSKext> myKext;
14270 // IOLog("found OSData %p in kext map %p to %p \n",
14271 // *(myPtrPtr),
14272 // (void *) kext_alloc_base,
14273 // (void *) kext_alloc_max);
14274
14275 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14276 if (myKext) {
14277 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14278 *(myPtrPtr),
14279 myKext->getIdentifierCString());
14280 }
14281 myResult = true;
14282 }
14283 if (vm_kernel_etext != 0 &&
14284 numberValue >= vm_kernel_stext &&
14285 numberValue < vm_kernel_etext) {
14286 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14287 *(myPtrPtr),
14288 (void *) vm_kernel_stext,
14289 (void *) vm_kernel_etext);
14290 myResult = true;
14291 }
14292 myPtrPtr++;
14293 }
14294 }
14295 } else if (myTypeID == OSTypeID(OSBoolean)) {
14296 // do nothing here...
14297 } else if (myTypeID == OSTypeID(OSNumber)) {
14298 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14299
14300 UInt64 numberValue = number->unsigned64BitValue();
14301
14302 if (kext_alloc_max != 0 &&
14303 numberValue >= kext_alloc_base &&
14304 numberValue < kext_alloc_max) {
14305 OSSharedPtr<OSKext> myKext;
14306 IOLog("found OSNumber in kext map %p to %p \n",
14307 (void *) kext_alloc_base,
14308 (void *) kext_alloc_max);
14309 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14310
14311 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14312 if (myKext) {
14313 IOLog("found in kext \"%s\" \n",
14314 myKext->getIdentifierCString());
14315 }
14316
14317 myResult = true;
14318 }
14319 if (vm_kernel_etext != 0 &&
14320 numberValue >= vm_kernel_stext &&
14321 numberValue < vm_kernel_etext) {
14322 IOLog("found OSNumber in kernel text segment %p to %p \n",
14323 (void *) vm_kernel_stext,
14324 (void *) vm_kernel_etext);
14325 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14326 myResult = true;
14327 }
14328 }
14329 #if 0
14330 else {
14331 const OSMetaClass* myMetaClass = NULL;
14332
14333 myMetaClass = theObject->getMetaClass();
14334 if (myMetaClass) {
14335 IOLog("class %s \n", myMetaClass->getClassName());
14336 } else {
14337 IOLog("Unknown object \n" );
14338 }
14339 }
14340 #endif
14341
14342 return myResult;
14343 }
14344 #endif // KASLR_KEXT_DEBUG
14345 }; /* extern "C" */
14346
14347 #if PRAGMA_MARK
14348 #pragma mark Backtrace Dump & kmod_get_info() support
14349 #endif
14350 /*********************************************************************
14351 * This function must be safe to call in panic context.
14352 *********************************************************************/
14353 /* static */
14354 void
14355 OSKext::printKextsInBacktrace(
14356 vm_offset_t * addr __unused,
14357 unsigned int cnt __unused,
14358 int (* printf_func)(const char *fmt, ...) __unused,
14359 uint32_t flags __unused)
14360 {
14361 addr64_t summary_page = 0;
14362 addr64_t last_summary_page = 0;
14363 bool found_kmod = false;
14364 u_int i = 0;
14365
14366 if (kPrintKextsLock & flags) {
14367 if (!sKextSummariesLock) {
14368 return;
14369 }
14370 IOLockLock(sKextSummariesLock);
14371 }
14372
14373 if (!gLoadedKextSummaries) {
14374 (*printf_func)(" can't perform kext scan: no kext summary");
14375 goto finish;
14376 }
14377
14378 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14379 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14380 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14381 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14382 (*printf_func)(" can't perform kext scan: "
14383 "missing kext summary page %p", summary_page);
14384 goto finish;
14385 }
14386 }
14387
14388 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14389 OSKextLoadedKextSummary * summary;
14390
14391 summary = gLoadedKextSummaries->summaries + i;
14392 if (!summary->address) {
14393 continue;
14394 }
14395
14396 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14397 continue;
14398 }
14399
14400 if (!found_kmod) {
14401 if (!(kPrintKextsTerse & flags)) {
14402 (*printf_func)(" Kernel Extensions in backtrace:\n");
14403 }
14404 found_kmod = true;
14405 }
14406
14407 printSummary(summary, printf_func, flags);
14408 }
14409
14410 finish:
14411 if (kPrintKextsLock & flags) {
14412 IOLockUnlock(sKextSummariesLock);
14413 }
14414
14415 return;
14416 }
14417
14418 /*********************************************************************
14419 * This function must be safe to call in panic context.
14420 *********************************************************************/
14421 /* static */
14422 boolean_t
14423 OSKext::summaryIsInBacktrace(
14424 OSKextLoadedKextSummary * summary,
14425 vm_offset_t * addr,
14426 unsigned int cnt)
14427 {
14428 u_int i = 0;
14429
14430 for (i = 0; i < cnt; i++) {
14431 vm_offset_t kscan_addr = addr[i];
14432 #if __has_feature(ptrauth_calls)
14433 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14434 #endif /* __has_feature(ptrauth_calls) */
14435 if ((kscan_addr >= summary->text_exec_address) &&
14436 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
14437 return TRUE;
14438 }
14439 }
14440
14441 return FALSE;
14442 }
14443
14444 /*
14445 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14446 * sKextSummariesLock held.
14447 */
14448 OSKextLoadedKextSummary *
14449 OSKext::summaryForAddress(uintptr_t addr)
14450 {
14451 #if __has_feature(ptrauth_calls)
14452 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14453 #endif /* __has_feature(ptrauth_calls) */
14454 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14455 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14456 if (!summary->address) {
14457 continue;
14458 }
14459
14460 #if VM_MAPPED_KEXTS
14461 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14462 * support split kexts, but we also may unmap the kexts, which can
14463 * race with the above codepath (see OSKext::unload). As such,
14464 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14465 */
14466 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14467 return summary;
14468 }
14469 #else
14470 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14471 kernel_segment_command_t *seg;
14472
14473 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14474 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14475 return summary;
14476 }
14477 }
14478 #endif
14479 }
14480
14481 /* addr did not map to any kext */
14482 return NULL;
14483 }
14484
14485 /* static */
14486 void *
14487 OSKext::kextForAddress(const void *address)
14488 {
14489 void * image = NULL;
14490 OSKextActiveAccount * active;
14491 OSKext * kext = NULL;
14492 uint32_t baseIdx;
14493 uint32_t lim;
14494 uintptr_t addr = (uintptr_t) address;
14495 size_t i;
14496
14497 if (!addr) {
14498 return NULL;
14499 }
14500 #if __has_feature(ptrauth_calls)
14501 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14502 #endif /* __has_feature(ptrauth_calls) */
14503
14504 if (sKextAccountsCount) {
14505 IOSimpleLockLock(sKextAccountsLock);
14506 // bsearch sKextAccounts list
14507 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14508 active = &sKextAccounts[baseIdx + (lim >> 1)];
14509 if ((addr >= active->address) && (addr < active->address_end)) {
14510 kext = active->account->kext;
14511 if (kext && kext->kmod_info) {
14512 image = (void *) kext->kmod_info->address;
14513 }
14514 break;
14515 } else if (addr > active->address) {
14516 // move right
14517 baseIdx += (lim >> 1) + 1;
14518 lim--;
14519 }
14520 // else move left
14521 }
14522 IOSimpleLockUnlock(sKextAccountsLock);
14523 }
14524 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14525 image = (void *) &_mh_execute_header;
14526 }
14527 if (!image && gLoadedKextSummaries) {
14528 IOLockLock(sKextSummariesLock);
14529 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14530 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14531 if (addr >= summary->address && addr < summary->address + summary->size) {
14532 image = (void *)summary->address;
14533 }
14534 }
14535 IOLockUnlock(sKextSummariesLock);
14536 }
14537
14538 return image;
14539 }
14540
14541 /*
14542 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14543 * Safe to call in panic context.
14544 */
14545 static OSKextLoadedKextSummary *
14546 findSummary(uint32_t tagID)
14547 {
14548 OSKextLoadedKextSummary * summary;
14549 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14550 summary = gLoadedKextSummaries->summaries + i;
14551 if (summary->loadTag == tagID) {
14552 return summary;
14553 }
14554 }
14555 return NULL;
14556 }
14557
14558 /*********************************************************************
14559 * This function must be safe to call in panic context.
14560 *********************************************************************/
14561 void
14562 OSKext::printSummary(
14563 OSKextLoadedKextSummary * summary,
14564 int (* printf_func)(const char *fmt, ...),
14565 uint32_t flags)
14566 {
14567 kmod_reference_t * kmod_ref = NULL;
14568 uuid_string_t uuid;
14569 char version[kOSKextVersionMaxLength];
14570 uint64_t tmpAddr;
14571 uint64_t tmpSize;
14572 OSKextLoadedKextSummary *dependencySummary;
14573
14574 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14575 strlcpy(version, "unknown version", sizeof(version));
14576 }
14577 (void) uuid_unparse(summary->uuid, uuid);
14578
14579 #if defined(__arm__) || defined(__arm64__)
14580 tmpAddr = summary->text_exec_address;
14581 tmpSize = summary->text_exec_size;
14582 #else
14583 tmpAddr = summary->address;
14584 tmpSize = summary->size;
14585 #endif
14586 if (kPrintKextsUnslide & flags) {
14587 tmpAddr = ml_static_unslide(tmpAddr);
14588 }
14589 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14590 (kPrintKextsTerse & flags) ? "" : " ",
14591 summary->name, version, uuid,
14592 tmpAddr, tmpAddr + tmpSize - 1);
14593
14594 if (kPrintKextsTerse & flags) {
14595 return;
14596 }
14597
14598 /* print dependency info */
14599 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14600 kmod_ref;
14601 kmod_ref = kmod_ref->next) {
14602 kmod_info_t * rinfo;
14603
14604 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14605 (*printf_func)(" kmod dependency scan stopped "
14606 "due to missing dependency page: %p\n",
14607 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14608 break;
14609 }
14610 rinfo = kmod_ref->info;
14611
14612 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14613 (*printf_func)(" kmod dependency scan stopped "
14614 "due to missing kmod page: %p\n",
14615 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14616 break;
14617 }
14618
14619 if (!rinfo->address) {
14620 continue; // skip fake entries for built-ins
14621 }
14622
14623 dependencySummary = findSummary(rinfo->id);
14624 uuid[0] = 0x00;
14625 tmpAddr = rinfo->address;
14626 tmpSize = rinfo->size;
14627 if (dependencySummary) {
14628 (void) uuid_unparse(dependencySummary->uuid, uuid);
14629 #if defined(__arm__) || defined(__arm64__)
14630 tmpAddr = dependencySummary->text_exec_address;
14631 tmpSize = dependencySummary->text_exec_size;
14632 #endif
14633 }
14634
14635 if (kPrintKextsUnslide & flags) {
14636 tmpAddr = ml_static_unslide(tmpAddr);
14637 }
14638 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14639 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
14640 }
14641 return;
14642 }
14643
14644
14645 #if !defined(__arm__) && !defined(__arm64__)
14646 /*******************************************************************************
14647 * substitute() looks at an input string (a pointer within a larger buffer)
14648 * for a match to a substring, and on match it writes the marker & substitution
14649 * character to an output string, updating the scan (from) and
14650 * output (to) indexes as appropriate.
14651 *******************************************************************************/
14652 static int substitute(
14653 const char * scan_string,
14654 char * string_out,
14655 uint32_t * to_index,
14656 uint32_t * from_index,
14657 const char * substring,
14658 char marker,
14659 char substitution);
14660
14661 /* string_out must be at least KMOD_MAX_NAME bytes.
14662 */
14663 static int
14664 substitute(
14665 const char * scan_string,
14666 char * string_out,
14667 uint32_t * to_index,
14668 uint32_t * from_index,
14669 const char * substring,
14670 char marker,
14671 char substitution)
14672 {
14673 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
14674
14675 /* On a substring match, append the marker (if there is one) and then
14676 * the substitution character, updating the output (to) index accordingly.
14677 * Then update the input (from) length by the length of the substring
14678 * that got replaced.
14679 */
14680 if (!strncmp(scan_string, substring, substring_length)) {
14681 if (marker) {
14682 string_out[(*to_index)++] = marker;
14683 }
14684 string_out[(*to_index)++] = substitution;
14685 (*from_index) += substring_length;
14686 return 1;
14687 }
14688 return 0;
14689 }
14690
14691 /*******************************************************************************
14692 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14693 * KMOD_MAX_NAME characters and performs various substitutions of common
14694 * prefixes & substrings as defined by tables in kext_panic_report.h.
14695 *******************************************************************************/
14696 static void compactIdentifier(
14697 const char * identifier,
14698 char * identifier_out,
14699 char ** identifier_out_end);
14700
14701 static void
14702 compactIdentifier(
14703 const char * identifier,
14704 char * identifier_out,
14705 char ** identifier_out_end)
14706 {
14707 uint32_t from_index, to_index;
14708 uint32_t scan_from_index = 0;
14709 uint32_t scan_to_index = 0;
14710 subs_entry_t * subs_entry = NULL;
14711 int did_sub = 0;
14712
14713 from_index = to_index = 0;
14714 identifier_out[0] = '\0';
14715
14716 /* Replace certain identifier prefixes with shorter @+character sequences.
14717 * Check the return value of substitute() so we only replace the prefix.
14718 */
14719 for (subs_entry = &kext_identifier_prefix_subs[0];
14720 subs_entry->substring && !did_sub;
14721 subs_entry++) {
14722 did_sub = substitute(identifier, identifier_out,
14723 &scan_to_index, &scan_from_index,
14724 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14725 }
14726 did_sub = 0;
14727
14728 /* Now scan through the identifier looking for the common substrings
14729 * and replacing them with shorter !+character sequences via substitute().
14730 */
14731 for (/* see above */;
14732 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14733 /* see loop */) {
14734 const char * scan_string = &identifier[scan_from_index];
14735
14736 did_sub = 0;
14737
14738 if (scan_from_index) {
14739 for (subs_entry = &kext_identifier_substring_subs[0];
14740 subs_entry->substring && !did_sub;
14741 subs_entry++) {
14742 did_sub = substitute(scan_string, identifier_out,
14743 &scan_to_index, &scan_from_index,
14744 subs_entry->substring, '!', subs_entry->substitute);
14745 }
14746 }
14747
14748 /* If we didn't substitute, copy the input character to the output.
14749 */
14750 if (!did_sub) {
14751 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14752 }
14753 }
14754
14755 identifier_out[scan_to_index] = '\0';
14756 if (identifier_out_end) {
14757 *identifier_out_end = &identifier_out[scan_to_index];
14758 }
14759
14760 return;
14761 }
14762 #endif /* !defined(__arm__) && !defined(__arm64__) */
14763
14764 /*******************************************************************************
14765 * assemble_identifier_and_version() adds to a string buffer a compacted
14766 * bundle identifier followed by a version string.
14767 *******************************************************************************/
14768
14769 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14770 */
14771 static size_t assemble_identifier_and_version(
14772 kmod_info_t * kmod_info,
14773 char * identPlusVers,
14774 size_t bufSize);
14775
14776 static size_t
14777 assemble_identifier_and_version(
14778 kmod_info_t * kmod_info,
14779 char * identPlusVers,
14780 size_t bufSize)
14781 {
14782 size_t result = 0;
14783
14784 #if defined(__arm__) || defined(__arm64__)
14785 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14786 #else
14787 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14788 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
14789 #endif
14790 identPlusVers[result++] = '\t'; // increment for real char
14791 identPlusVers[result] = '\0'; // don't increment for nul char
14792 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14793 if (result >= bufSize) {
14794 identPlusVers[bufSize - 1] = '\0';
14795 result = bufSize - 1;
14796 }
14797
14798 return result;
14799 }
14800
14801 /*******************************************************************************
14802 * Assumes sKextLock is held.
14803 *******************************************************************************/
14804 /* static */
14805 int
14806 OSKext::saveLoadedKextPanicListTyped(
14807 const char * prefix,
14808 int invertFlag,
14809 int libsFlag,
14810 char * paniclist,
14811 uint32_t list_size)
14812 {
14813 int result = -1;
14814 unsigned int count, i;
14815
14816 count = sLoadedKexts->getCount();
14817 if (!count) {
14818 goto finish;
14819 }
14820
14821 i = count - 1;
14822 do {
14823 OSObject * rawKext = sLoadedKexts->getObject(i);
14824 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14825 int match;
14826 size_t identPlusVersLength;
14827 size_t tempLen;
14828 char identPlusVers[2 * KMOD_MAX_NAME];
14829
14830 if (!rawKext) {
14831 printf("OSKext::saveLoadedKextPanicListTyped - "
14832 "NULL kext in loaded kext list; continuing\n");
14833 continue;
14834 }
14835
14836 if (!theKext) {
14837 printf("OSKext::saveLoadedKextPanicListTyped - "
14838 "Kext type cast failed in loaded kext list; continuing\n");
14839 continue;
14840 }
14841
14842 /* Skip all built-in kexts.
14843 */
14844 if (theKext->isKernelComponent()) {
14845 continue;
14846 }
14847
14848 kmod_info_t * kmod_info = theKext->kmod_info;
14849
14850 /* Filter for kmod name (bundle identifier).
14851 */
14852 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14853 if ((match && invertFlag) || (!match && !invertFlag)) {
14854 continue;
14855 }
14856
14857 /* Filter for libraries (kexts that have a compatible version).
14858 */
14859 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14860 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14861 continue;
14862 }
14863
14864 if (!kmod_info ||
14865 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14866 printf("kext scan stopped due to missing kmod_info page: %p\n",
14867 kmod_info);
14868 goto finish;
14869 }
14870
14871 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14872 identPlusVers,
14873 sizeof(identPlusVers));
14874 if (!identPlusVersLength) {
14875 printf("error saving loaded kext info\n");
14876 goto finish;
14877 }
14878
14879 /* make sure everything fits and we null terminate.
14880 */
14881 tempLen = strlcat(paniclist, identPlusVers, list_size);
14882 if (tempLen >= list_size) {
14883 // panic list is full, keep it and null terminate
14884 paniclist[list_size - 1] = 0x00;
14885 result = 0;
14886 goto finish;
14887 }
14888 tempLen = strlcat(paniclist, "\n", list_size);
14889 if (tempLen >= list_size) {
14890 // panic list is full, keep it and null terminate
14891 paniclist[list_size - 1] = 0x00;
14892 result = 0;
14893 goto finish;
14894 }
14895 } while (i--);
14896
14897 result = 0;
14898 finish:
14899
14900 return result;
14901 }
14902
14903 /*********************************************************************
14904 *********************************************************************/
14905 /* static */
14906 void
14907 OSKext::saveLoadedKextPanicList(void)
14908 {
14909 char * newlist = NULL;
14910 uint32_t newlist_size = 0;
14911
14912 newlist_size = KEXT_PANICLIST_SIZE;
14913 newlist = (char *)kalloc_data_tag(newlist_size,
14914 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14915
14916 if (!newlist) {
14917 OSKextLog(/* kext */ NULL,
14918 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14919 "Couldn't allocate kext panic log buffer.");
14920 goto finish;
14921 }
14922
14923 newlist[0] = '\0';
14924
14925 // non-"com.apple." kexts
14926 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14927 /* libs? */ -1, newlist, newlist_size) != 0) {
14928 goto finish;
14929 }
14930 // "com.apple." nonlibrary kexts
14931 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14932 /* libs? */ 0, newlist, newlist_size) != 0) {
14933 goto finish;
14934 }
14935 // "com.apple." library kexts
14936 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14937 /* libs? */ 1, newlist, newlist_size) != 0) {
14938 goto finish;
14939 }
14940
14941 if (loaded_kext_paniclist) {
14942 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
14943 }
14944 loaded_kext_paniclist = newlist;
14945 newlist = NULL;
14946 loaded_kext_paniclist_size = newlist_size;
14947
14948 finish:
14949 if (newlist) {
14950 kfree_data(newlist, newlist_size);
14951 }
14952 return;
14953 }
14954
14955 /*********************************************************************
14956 * Assumes sKextLock is held.
14957 *********************************************************************/
14958 void
14959 OSKext::savePanicString(bool isLoading)
14960 {
14961 u_long len;
14962
14963 if (!kmod_info) {
14964 return; // do not goto finish here b/c of lock
14965 }
14966
14967 len = assemble_identifier_and_version( kmod_info,
14968 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14969 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14970 if (!len) {
14971 printf("error saving unloaded kext info\n");
14972 goto finish;
14973 }
14974
14975 if (isLoading) {
14976 last_loaded_strlen = len;
14977 last_loaded_address = (void *)kmod_info->address;
14978 last_loaded_size = kmod_info->size;
14979 clock_get_uptime(&last_loaded_timestamp);
14980 } else {
14981 last_unloaded_strlen = len;
14982 last_unloaded_address = (void *)kmod_info->address;
14983 last_unloaded_size = kmod_info->size;
14984 clock_get_uptime(&last_unloaded_timestamp);
14985 }
14986
14987 finish:
14988 return;
14989 }
14990
14991 /*********************************************************************
14992 *********************************************************************/
14993 /* static */
14994 void
14995 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
14996 {
14997 if (last_loaded_strlen) {
14998 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14999 AbsoluteTime_to_scalar(&last_loaded_timestamp),
15000 last_loaded_strlen, last_loaded_str_buf,
15001 last_loaded_address, last_loaded_size);
15002 }
15003
15004 if (last_unloaded_strlen) {
15005 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
15006 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
15007 last_unloaded_strlen, last_unloaded_str_buf,
15008 last_unloaded_address, last_unloaded_size);
15009 }
15010
15011 printf_func("loaded kexts:\n");
15012 if (loaded_kext_paniclist &&
15013 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
15014 loaded_kext_paniclist[0]) {
15015 printf_func("%.*s",
15016 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
15017 loaded_kext_paniclist);
15018 } else {
15019 printf_func("(none)\n");
15020 }
15021 return;
15022 }
15023
15024 /*********************************************************************
15025 * Assumes sKextLock is held.
15026 *********************************************************************/
15027 /* static */
15028 void
15029 OSKext::updateLoadedKextSummaries(void)
15030 {
15031 kern_return_t result = KERN_FAILURE;
15032 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
15033 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
15034 OSKext *aKext;
15035 vm_map_offset_t start, end;
15036 size_t summarySize = 0;
15037 size_t size;
15038 u_int count;
15039 u_int maxKexts;
15040 u_int i, j;
15041 OSKextActiveAccount * accountingList;
15042 OSKextActiveAccount * prevAccountingList;
15043 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
15044
15045 prevAccountingList = NULL;
15046 prevAccountingListCount = 0;
15047
15048 #if DEVELOPMENT || DEBUG
15049 if (IORecursiveLockHaveLock(sKextLock) == false) {
15050 panic("sKextLock must be held");
15051 }
15052 #endif
15053
15054 IOLockLock(sKextSummariesLock);
15055
15056 count = sLoadedKexts->getCount();
15057 for (i = 0, maxKexts = 0; i < count; ++i) {
15058 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15059 maxKexts += (aKext && aKext->isExecutable());
15060 }
15061
15062 if (!maxKexts) {
15063 goto finish;
15064 }
15065 if (maxKexts < kOSKextTypicalLoadCount) {
15066 maxKexts = kOSKextTypicalLoadCount;
15067 }
15068
15069 /* Calculate the size needed for the new summary headers.
15070 */
15071
15072 size = sizeof(*gLoadedKextSummaries);
15073 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
15074 size = round_page(size);
15075
15076 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
15077 if (gLoadedKextSummaries) {
15078 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
15079 gLoadedKextSummaries = NULL;
15080 gLoadedKextSummariesTimestamp = mach_absolute_time();
15081 sLoadedKextSummariesAllocSize = 0;
15082 }
15083 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
15084 if (result != KERN_SUCCESS) {
15085 goto finish;
15086 }
15087 summaryHeader = summaryHeaderAlloc;
15088 summarySize = size;
15089 } else {
15090 summaryHeader = gLoadedKextSummaries;
15091 summarySize = sLoadedKextSummariesAllocSize;
15092
15093 start = (vm_map_offset_t) summaryHeader;
15094 end = start + summarySize;
15095 result = vm_map_protect(kernel_map,
15096 start,
15097 end,
15098 VM_PROT_DEFAULT,
15099 FALSE);
15100 if (result != KERN_SUCCESS) {
15101 goto finish;
15102 }
15103 }
15104
15105 /* Populate the summary header.
15106 */
15107
15108 bzero(summaryHeader, summarySize);
15109 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
15110 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
15111
15112 /* Populate each kext summary.
15113 */
15114
15115 count = sLoadedKexts->getCount();
15116 accountingListAlloc = 0;
15117 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15118 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15119 if (!aKext || !aKext->isExecutable()) {
15120 continue;
15121 }
15122
15123 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
15124 summaryHeader->numSummaries++;
15125 accountingListAlloc++;
15126 }
15127
15128 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
15129 accountingListCount = 0;
15130 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15131 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15132 if (!aKext || !aKext->isExecutable()) {
15133 continue;
15134 }
15135
15136 OSKextActiveAccount activeAccount;
15137 aKext->updateActiveAccount(&activeAccount);
15138 // order by address
15139 for (idx = 0; idx < accountingListCount; idx++) {
15140 if (activeAccount.address < accountingList[idx].address) {
15141 break;
15142 }
15143 }
15144 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
15145 accountingList[idx] = activeAccount;
15146 accountingListCount++;
15147 }
15148 assert(accountingListCount == accountingListAlloc);
15149 /* Write protect the buffer and move it into place.
15150 */
15151
15152 start = (vm_map_offset_t) summaryHeader;
15153 end = start + summarySize;
15154
15155 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15156 if (result != KERN_SUCCESS) {
15157 goto finish;
15158 }
15159
15160 gLoadedKextSummaries = summaryHeader;
15161 gLoadedKextSummariesTimestamp = mach_absolute_time();
15162 sLoadedKextSummariesAllocSize = summarySize;
15163 summaryHeaderAlloc = NULL;
15164
15165 /* Call the magic breakpoint function through a static function pointer so
15166 * the compiler can't optimize the function away.
15167 */
15168 if (sLoadedKextSummariesUpdated) {
15169 (*sLoadedKextSummariesUpdated)();
15170 }
15171
15172 IOSimpleLockLock(sKextAccountsLock);
15173 prevAccountingList = sKextAccounts;
15174 prevAccountingListCount = sKextAccountsCount;
15175 sKextAccounts = accountingList;
15176 sKextAccountsCount = accountingListCount;
15177 IOSimpleLockUnlock(sKextAccountsLock);
15178
15179 finish:
15180 IOLockUnlock(sKextSummariesLock);
15181
15182 /* If we had to allocate a new buffer but failed to generate the summaries,
15183 * free that now.
15184 */
15185 if (summaryHeaderAlloc) {
15186 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15187 }
15188 if (prevAccountingList) {
15189 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15190 }
15191
15192 return;
15193 }
15194
15195 /*********************************************************************
15196 *********************************************************************/
15197 void
15198 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15199 {
15200 OSSharedPtr<OSData> uuid;
15201
15202 strlcpy(summary->name, getIdentifierCString(),
15203 sizeof(summary->name));
15204
15205 uuid = copyUUID();
15206 if (uuid) {
15207 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
15208 }
15209
15210 if (flags.builtin) {
15211 // this value will stop lldb from parsing the mach-o header
15212 // summary->address = UINT64_MAX;
15213 // summary->size = 0;
15214 summary->address = kmod_info->address;
15215 summary->size = kmod_info->size;
15216 } else {
15217 summary->address = kmod_info->address;
15218 summary->size = kmod_info->size;
15219 }
15220 summary->version = getVersion();
15221 summary->loadTag = kmod_info->id;
15222 summary->flags = 0;
15223 summary->reference_list = (uint64_t) kmod_info->reference_list;
15224
15225 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15226 if (summary->text_exec_address == 0) {
15227 // Fallback to __TEXT
15228 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15229 }
15230 return;
15231 }
15232
15233 /*********************************************************************
15234 *********************************************************************/
15235
15236 void
15237 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
15238 {
15239 kernel_mach_header_t *hdr = NULL;
15240 kernel_segment_command_t *seg = NULL;
15241
15242 bzero(accountp, sizeof(*accountp));
15243
15244 hdr = (kernel_mach_header_t *)kmod_info->address;
15245 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15246 /*
15247 * If this kext supports split segments (or is in a new
15248 * MH_FILESET kext collection), use the first
15249 * executable segment as the range for instructions
15250 * (and thus for backtracing.
15251 */
15252 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15253 if (seg->initprot & VM_PROT_EXECUTE) {
15254 break;
15255 }
15256 }
15257 }
15258 if (seg) {
15259 accountp->address = seg->vmaddr;
15260 if (accountp->address) {
15261 accountp->address_end = seg->vmaddr + seg->vmsize;
15262 }
15263 } else {
15264 /* For non-split kexts and for kexts without executable
15265 * segments, just use the kmod_info range (as the kext
15266 * is either all in one range or should not show up in
15267 * instruction backtraces).
15268 */
15269 accountp->address = kmod_info->address;
15270 if (accountp->address) {
15271 accountp->address_end = kmod_info->address + kmod_info->size;
15272 }
15273 }
15274
15275 accountp->account = this->account;
15276 }
15277
15278 bool
15279 OSKext::isDriverKit(void)
15280 {
15281 OSString *bundleType;
15282
15283 if (infoDict) {
15284 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15285 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15286 return TRUE;
15287 }
15288 }
15289 return FALSE;
15290 }
15291
15292 bool
15293 OSKext::isInFileset(void)
15294 {
15295 if (!kmod_info) {
15296 goto check_prelinked;
15297 }
15298
15299 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15300 return true;
15301 }
15302
15303 check_prelinked:
15304 if (isPrelinked()) {
15305 /*
15306 * If we haven't setup kmod_info yet, but we know
15307 * we're loading a prelinked kext in an MH_FILESET KC,
15308 * then return true
15309 */
15310 kc_format_t kc_format;
15311 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15312 return true;
15313 }
15314 }
15315 return false;
15316 }
15317
15318 bool
15319 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15320 {
15321 kern_return_t result;
15322 if (!super::init()) {
15323 return false;
15324 }
15325 if (seg == nullptr) {
15326 return false;
15327 }
15328 result = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&data, seg->vmsize, VM_KERN_MEMORY_KEXT);
15329 if (result != KERN_SUCCESS) {
15330 return false;
15331 }
15332 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15333 savedSegment = seg;
15334 vmsize = seg->vmsize;
15335 vmaddr = seg->vmaddr;
15336 return true;
15337 }
15338
15339 OSSharedPtr<OSKextSavedMutableSegment>
15340 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15341 {
15342 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15343 if (me && !me->initWithSegment(seg)) {
15344 return nullptr;
15345 }
15346 return me;
15347 }
15348
15349 void
15350 OSKextSavedMutableSegment::free(void)
15351 {
15352 if (data) {
15353 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15354 }
15355 }
15356
15357 vm_offset_t
15358 OSKextSavedMutableSegment::getVMAddr() const
15359 {
15360 return vmaddr;
15361 }
15362
15363 vm_offset_t
15364 OSKextSavedMutableSegment::getVMSize() const
15365 {
15366 return vmsize;
15367 }
15368
15369 OSReturn
15370 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15371 {
15372 if (seg != savedSegment) {
15373 return kOSKextReturnInvalidArgument;
15374 }
15375 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15376 return kOSKextReturnInvalidArgument;
15377 }
15378 memcpy((void *)seg->vmaddr, data, vmsize);
15379 return kOSReturnSuccess;
15380 }
15381
15382 extern "C" kern_return_t
15383 OSKextSetReceiptQueried(void)
15384 {
15385 OSKextLog(/* kext */ NULL,
15386 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
15387 "Setting kext receipt as queried");
15388
15389 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
15390 return KERN_SUCCESS;
15391 }
15392
15393 extern "C" const vm_allocation_site_t *
15394 OSKextGetAllocationSiteForCaller(uintptr_t address)
15395 {
15396 OSKextActiveAccount * active;
15397 vm_allocation_site_t * site;
15398 vm_allocation_site_t * releasesite;
15399
15400 uint32_t baseIdx;
15401 uint32_t lim;
15402 #if __has_feature(ptrauth_calls)
15403 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15404 #endif /* __has_feature(ptrauth_calls) */
15405
15406 IOSimpleLockLock(sKextAccountsLock);
15407 site = releasesite = NULL;
15408
15409 // bsearch sKextAccounts list
15410 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15411 active = &sKextAccounts[baseIdx + (lim >> 1)];
15412 if ((address >= active->address) && (address < active->address_end)) {
15413 site = &active->account->site;
15414 if (!site->tag) {
15415 vm_tag_alloc_locked(site, &releasesite);
15416 }
15417 break;
15418 } else if (address > active->address) {
15419 // move right
15420 baseIdx += (lim >> 1) + 1;
15421 lim--;
15422 }
15423 // else move left
15424 }
15425 IOSimpleLockUnlock(sKextAccountsLock);
15426 if (releasesite) {
15427 kern_allocation_name_release(releasesite);
15428 }
15429
15430 return site;
15431 }
15432
15433 #if DEVELOPMENT || DEBUG
15434 extern "C" void
15435 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
15436 {
15437 OSKextActiveAccount * active;
15438
15439 uint32_t baseIdx;
15440 uint32_t lim;
15441 #if __has_feature(ptrauth_calls)
15442 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15443 #endif /* __has_feature(ptrauth_calls) */
15444
15445 IOSimpleLockLock(sKextAccountsLock);
15446
15447 // bsearch sKextAccounts list
15448 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15449 active = &sKextAccounts[baseIdx + (lim >> 1)];
15450 if ((address >= active->address) && (address < active->address_end)) {
15451 cb(&active->account->task_refgrp);
15452 break;
15453 } else if (address > active->address) {
15454 // move right
15455 baseIdx += (lim >> 1) + 1;
15456 lim--;
15457 }
15458 // else move left
15459 }
15460 IOSimpleLockUnlock(sKextAccountsLock);
15461 }
15462 #endif /* DEVELOPMENT || DEBUG */
15463
15464 extern "C" uint32_t
15465 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
15466 {
15467 OSKextAccount * account = (typeof(account))site;
15468 const char * kname;
15469
15470 if (name) {
15471 if (account->kext) {
15472 kname = account->kext->getIdentifierCString();
15473 } else {
15474 kname = "<>";
15475 }
15476 strlcpy(name, kname, namelen);
15477 }
15478
15479 return account->loadTag;
15480 }
15481
15482 extern "C" void
15483 OSKextFreeSite(vm_allocation_site_t * site)
15484 {
15485 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15486 IOFreeType(freeAccount, OSKextAccount);
15487 }
15488
15489 /*********************************************************************
15490 *********************************************************************/
15491
15492 #if CONFIG_IMAGEBOOT
15493 int
15494 OSKextGetUUIDForName(const char *name, uuid_t uuid)
15495 {
15496 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
15497 if (!kext) {
15498 return 1;
15499 }
15500
15501 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
15502 if (uuid_data) {
15503 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
15504 return 0;
15505 }
15506
15507 return 1;
15508 }
15509 #endif
15510
15511 static int
15512 sysctl_willuserspacereboot
15513 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15514 {
15515 int new_value = 0, old_value = 0, changed = 0;
15516 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15517 if (error) {
15518 return error;
15519 }
15520 if (changed) {
15521 OSKext::willUserspaceReboot();
15522 }
15523 return 0;
15524 }
15525
15526 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15527 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15528 NULL, 0, sysctl_willuserspacereboot, "I", "");
15529