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, KMA_ZERO, 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,
3421 KMA_DATA, VM_KERN_MEMORY_OSKEXT)) {
3422 /* How's this for cheesy? The kernel is only asked to extract
3423 * kext plists so we tailor the log messages.
3424 */
3425 if (isKernel()) {
3426 OSKextLog(this,
3427 kOSKextLogErrorLevel |
3428 kOSKextLogArchiveFlag,
3429 "Allocation failure extracting %s from mkext.", name);
3430 } else {
3431 OSKextLog(this,
3432 kOSKextLogErrorLevel |
3433 kOSKextLogArchiveFlag,
3434 "Allocation failure extracting %s from mkext for kext %s.",
3435 name, getIdentifierCString());
3436 }
3437
3438 goto finish;
3439 }
3440 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3441 if (!uncompressedData) {
3442 if (isKernel()) {
3443 OSKextLog(this,
3444 kOSKextLogErrorLevel |
3445 kOSKextLogArchiveFlag,
3446 "Allocation failure extracting %s from mkext.", name);
3447 } else {
3448 OSKextLog(this,
3449 kOSKextLogErrorLevel |
3450 kOSKextLogArchiveFlag,
3451 "Allocation failure extracting %s from mkext for kext %s.",
3452 name, getIdentifierCString());
3453 }
3454 goto finish;
3455 }
3456 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3457
3458 if (isKernel()) {
3459 OSKextLog(this,
3460 kOSKextLogDetailLevel |
3461 kOSKextLogArchiveFlag,
3462 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3463 name, compressedSize, fullSize);
3464 } else {
3465 OSKextLog(this,
3466 kOSKextLogDetailLevel |
3467 kOSKextLogArchiveFlag,
3468 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3469 getIdentifierCString(), name, compressedSize, fullSize);
3470 }
3471
3472 bzero(&zstream, sizeof(zstream));
3473 zstream.next_in = (UInt8 *)data;
3474 zstream.avail_in = compressedSize;
3475
3476 zstream.next_out = uncompressedDataBuffer;
3477 zstream.avail_out = fullSize;
3478
3479 zstream.zalloc = z_alloc;
3480 zstream.zfree = z_free;
3481
3482 zlib_result = inflateInit(&zstream);
3483 if (Z_OK != zlib_result) {
3484 if (isKernel()) {
3485 OSKextLog(this,
3486 kOSKextLogErrorLevel |
3487 kOSKextLogArchiveFlag,
3488 "Mkext error; zlib inflateInit failed (%d) for %s.",
3489 zlib_result, name);
3490 } else {
3491 OSKextLog(this,
3492 kOSKextLogErrorLevel |
3493 kOSKextLogArchiveFlag,
3494 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3495 getIdentifierCString(), zlib_result, name);
3496 }
3497 goto finish;
3498 } else {
3499 zstream_inited = true;
3500 }
3501
3502 zlib_result = inflate(&zstream, Z_FINISH);
3503
3504 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3505 uncompressedSize = zstream.total_out;
3506 } else {
3507 if (isKernel()) {
3508 OSKextLog(this,
3509 kOSKextLogErrorLevel |
3510 kOSKextLogArchiveFlag,
3511 "Mkext error; zlib inflate failed (%d) for %s.",
3512 zlib_result, name);
3513 } else {
3514 OSKextLog(this,
3515 kOSKextLogErrorLevel |
3516 kOSKextLogArchiveFlag,
3517 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3518 getIdentifierCString(), zlib_result, name);
3519 }
3520 if (zstream.msg) {
3521 OSKextLog(this,
3522 kOSKextLogErrorLevel |
3523 kOSKextLogArchiveFlag,
3524 "zlib error: %s.", zstream.msg);
3525 }
3526 goto finish;
3527 }
3528
3529 if (uncompressedSize != fullSize) {
3530 if (isKernel()) {
3531 OSKextLog(this,
3532 kOSKextLogErrorLevel |
3533 kOSKextLogArchiveFlag,
3534 "Mkext error; zlib inflate discrepancy for %s, "
3535 "uncompressed size != original size.", name);
3536 } else {
3537 OSKextLog(this,
3538 kOSKextLogErrorLevel |
3539 kOSKextLogArchiveFlag,
3540 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3541 "uncompressed size != original size.",
3542 getIdentifierCString(), name);
3543 }
3544 goto finish;
3545 }
3546
3547 result = os::move(uncompressedData);
3548
3549 finish:
3550 /* Don't bother checking return, nothing we can do on fail.
3551 */
3552 if (zstream_inited) {
3553 inflateEnd(&zstream);
3554 }
3555
3556 return result;
3557 }
3558
3559 /*********************************************************************
3560 *********************************************************************/
3561 /* static */
3562 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3563 OSKext::loadFromMkext(
3564 OSKextLogSpec clientLogFilter,
3565 char * mkextBuffer,
3566 uint32_t mkextBufferLength,
3567 char ** logInfoOut,
3568 uint32_t * logInfoLengthOut)
3569 {
3570 OSReturn result = kOSReturnError;
3571 OSReturn tempResult = kOSReturnError;
3572
3573 OSSharedPtr<OSData> mkextData;
3574 OSSharedPtr<OSDictionary> mkextPlist;
3575
3576 OSSharedPtr<OSArray> logInfoArray;
3577 OSSharedPtr<OSSerialize> serializer;
3578
3579 OSString * predicate = NULL; // do not release
3580 OSDictionary * requestArgs = NULL; // do not release
3581
3582 OSString * kextIdentifier = NULL; // do not release
3583 OSNumber * startKextExcludeNum = NULL; // do not release
3584 OSNumber * startMatchingExcludeNum = NULL; // do not release
3585 OSBoolean * delayAutounloadBool = NULL; // do not release
3586 OSArray * personalityNames = NULL; // do not release
3587
3588 /* Default values for these two options: regular autounload behavior,
3589 * load all kexts, send no personalities.
3590 */
3591 Boolean delayAutounload = false;
3592 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3593 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3594
3595 IORecursiveLockLock(sKextLock);
3596
3597 if (logInfoOut) {
3598 *logInfoOut = NULL;
3599 *logInfoLengthOut = 0;
3600 }
3601
3602 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3603
3604 OSKextLog(/* kext */ NULL,
3605 kOSKextLogDebugLevel |
3606 kOSKextLogIPCFlag,
3607 "Received kext load request from user space.");
3608
3609 /* Regardless of processing, the fact that we have gotten here means some
3610 * user-space program is up and talking to us, so we'll switch our kext
3611 * registration to reflect that.
3612 */
3613 if (!sUserLoadsActive) {
3614 OSKextLog(/* kext */ NULL,
3615 kOSKextLogProgressLevel |
3616 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3617 "Switching to late startup (user-space) kext loading policy.");
3618
3619 sUserLoadsActive = true;
3620 }
3621
3622 if (!sLoadEnabled) {
3623 OSKextLog(/* kext */ NULL,
3624 kOSKextLogErrorLevel |
3625 kOSKextLogLoadFlag,
3626 "Kext loading is disabled.");
3627 result = kOSKextReturnDisabled;
3628 goto finish;
3629 }
3630
3631 /* Note that we do not set a dealloc function on this OSData
3632 * object! No references to it can remain after the loadFromMkext()
3633 * call since we are in a MIG function, and will vm_deallocate()
3634 * the buffer.
3635 */
3636 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3637 mkextBufferLength);
3638 if (!mkextData) {
3639 OSKextLog(/* kext */ NULL,
3640 kOSKextLogErrorLevel |
3641 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3642 "Failed to create wrapper for kext load request.");
3643 result = kOSKextReturnNoMemory;
3644 goto finish;
3645 }
3646
3647 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3648 if (result != kOSReturnSuccess) {
3649 OSKextLog(/* kext */ NULL,
3650 kOSKextLogErrorLevel |
3651 kOSKextLogLoadFlag,
3652 "Failed to read kext load request.");
3653 goto finish;
3654 }
3655
3656 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3657 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3658 OSKextLog(/* kext */ NULL,
3659 kOSKextLogErrorLevel |
3660 kOSKextLogLoadFlag,
3661 "Received kext load request with no predicate; skipping.");
3662 result = kOSKextReturnInvalidArgument;
3663 goto finish;
3664 }
3665
3666 requestArgs = OSDynamicCast(OSDictionary,
3667 mkextPlist->getObject(kKextRequestArgumentsKey));
3668 if (!requestArgs || !requestArgs->getCount()) {
3669 OSKextLog(/* kext */ NULL,
3670 kOSKextLogErrorLevel |
3671 kOSKextLogLoadFlag,
3672 "Received kext load request with no arguments.");
3673 result = kOSKextReturnInvalidArgument;
3674 goto finish;
3675 }
3676
3677 kextIdentifier = OSDynamicCast(OSString,
3678 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3679
3680 if (!kextIdentifier) {
3681 OSKextLog(/* kext */ NULL,
3682 kOSKextLogErrorLevel |
3683 kOSKextLogLoadFlag,
3684 "Received kext load request with no kext identifier.");
3685 result = kOSKextReturnInvalidArgument;
3686 goto finish;
3687 }
3688
3689 startKextExcludeNum = OSDynamicCast(OSNumber,
3690 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3691 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3692 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3693 delayAutounloadBool = OSDynamicCast(OSBoolean,
3694 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3695 personalityNames = OSDynamicCast(OSArray,
3696 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3697
3698 if (delayAutounloadBool) {
3699 delayAutounload = delayAutounloadBool->getValue();
3700 }
3701 if (startKextExcludeNum) {
3702 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3703 }
3704 if (startMatchingExcludeNum) {
3705 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3706 }
3707
3708 OSKextLog(/* kext */ NULL,
3709 kOSKextLogProgressLevel |
3710 kOSKextLogIPCFlag,
3711 "Received request from user space to load kext %s.",
3712 kextIdentifier->getCStringNoCopy());
3713
3714 /* Load the kext, with no deferral, since this is a load from outside
3715 * the kernel.
3716 * xxx - Would like a better way to handle the default values for the
3717 * xxx - start/match opt args.
3718 */
3719 result = OSKext::loadKextWithIdentifier(
3720 kextIdentifier,
3721 /* kextRef */ NULL,
3722 /* allowDefer */ false,
3723 delayAutounload,
3724 startKextExcludeLevel,
3725 startMatchingExcludeLevel,
3726 personalityNames);
3727 if (result != kOSReturnSuccess) {
3728 goto finish;
3729 }
3730 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3731 * for matching via a separate IOKit calldown.
3732 */
3733
3734 finish:
3735
3736 /* Gather up the collected log messages for user space. Any
3737 * error messages past this call will not make it up as log messages
3738 * but will be in the system log.
3739 */
3740 logInfoArray = OSKext::clearUserSpaceLogFilter();
3741
3742 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3743 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3744 logInfoOut, logInfoLengthOut);
3745 if (tempResult != kOSReturnSuccess) {
3746 result = tempResult;
3747 }
3748 }
3749
3750 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3751
3752 IORecursiveLockUnlock(sKextLock);
3753
3754 /* Note: mkextDataObject will have been retained by every kext w/an
3755 * executable in it. That should all have been flushed out at the
3756 * and of the load operation, but you never know....
3757 */
3758 if (mkextData && mkextData->getRetainCount() > 1) {
3759 OSKextLog(/* kext */ NULL,
3760 kOSKextLogErrorLevel |
3761 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3762 "Kext load request buffer from user space still retained by a kext; "
3763 "probable memory leak.");
3764 }
3765
3766 return result;
3767 }
3768
3769 #endif // CONFIG_KXLD
3770
3771 /*********************************************************************
3772 *********************************************************************/
3773 /* static */
3774 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)3775 OSKext::serializeLogInfo(
3776 OSArray * logInfoArray,
3777 char ** logInfoOut,
3778 uint32_t * logInfoLengthOut)
3779 {
3780 OSReturn result = kOSReturnError;
3781 char * buffer = NULL;
3782 kern_return_t kmem_result = KERN_FAILURE;
3783 OSSharedPtr<OSSerialize> serializer;
3784 char * logInfo = NULL; // returned by reference
3785 uint32_t logInfoLength = 0;
3786
3787 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3788 OSKextLog(/* kext */ NULL,
3789 kOSKextLogErrorLevel |
3790 kOSKextLogIPCFlag,
3791 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3792 /* Bad programmer. */
3793 result = kOSKextReturnInvalidArgument;
3794 goto finish;
3795 }
3796
3797 serializer = OSSerialize::withCapacity(0);
3798 if (!serializer) {
3799 OSKextLog(/* kext */ NULL,
3800 kOSKextLogErrorLevel |
3801 kOSKextLogIPCFlag,
3802 "Failed to create serializer on log info for request from user space.");
3803 /* Incidental error; we're going to (try to) allow the request
3804 * itself to succeed. */
3805 }
3806
3807 if (!logInfoArray->serialize(serializer.get())) {
3808 OSKextLog(/* kext */ NULL,
3809 kOSKextLogErrorLevel |
3810 kOSKextLogIPCFlag,
3811 "Failed to serialize log info for request from user space.");
3812 /* Incidental error; we're going to (try to) allow the request
3813 * itself to succeed. */
3814 } else {
3815 logInfo = serializer->text();
3816 logInfoLength = serializer->getLength();
3817
3818 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength),
3819 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
3820 if (kmem_result != KERN_SUCCESS) {
3821 OSKextLog(/* kext */ NULL,
3822 kOSKextLogErrorLevel |
3823 kOSKextLogIPCFlag,
3824 "Failed to copy log info for request from user space.");
3825 /* Incidental error; we're going to (try to) allow the request
3826 * to succeed. */
3827 } else {
3828 /* 11981737 - clear uninitialized data in last page */
3829 bzero((void *)(buffer + logInfoLength),
3830 (round_page(logInfoLength) - logInfoLength));
3831 memcpy(buffer, logInfo, logInfoLength);
3832 *logInfoOut = buffer;
3833 *logInfoLengthOut = logInfoLength;
3834 }
3835 }
3836
3837 result = kOSReturnSuccess;
3838 finish:
3839 return result;
3840 }
3841
3842 #if PRAGMA_MARK
3843 #pragma mark Instance Management Methods
3844 #endif
3845 /*********************************************************************
3846 *********************************************************************/
3847 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)3848 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3849 {
3850 OSSharedPtr<OSKext> foundKext;
3851
3852 IORecursiveLockLock(sKextLock);
3853 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
3854 IORecursiveLockUnlock(sKextLock);
3855
3856 return foundKext;
3857 }
3858
3859 /*********************************************************************
3860 *********************************************************************/
3861 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)3862 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3863 {
3864 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3865 }
3866
3867 /*********************************************************************
3868 *********************************************************************/
3869 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)3870 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3871 {
3872 OSSharedPtr<OSKext> foundKext; // returned
3873 uint32_t i, j;
3874 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3875 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3876
3877 IORecursiveLockLock(sKextLock);
3878
3879 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3880 for (i = 0; i < count[j]; i++) {
3881 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3882 if (thisKext->getLoadTag() == aTag) {
3883 foundKext.reset(thisKext, OSRetain);
3884 goto finish;
3885 }
3886 }
3887 }
3888
3889 finish:
3890 IORecursiveLockUnlock(sKextLock);
3891
3892 return foundKext;
3893 }
3894
3895 /*********************************************************************
3896 *********************************************************************/
3897 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)3898 OSKext::lookupKextWithAddress(vm_address_t address)
3899 {
3900 OSSharedPtr<OSKext> foundKext; // returned
3901 uint32_t count, i;
3902 kmod_info_t *kmod_info;
3903 vm_address_t originalAddress;
3904 #if defined(__arm64__)
3905 uint64_t textExecBase;
3906 size_t textExecSize;
3907 #endif /* defined(__arm64__) */
3908
3909 originalAddress = address;
3910 #if __has_feature(ptrauth_calls)
3911 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3912 #endif /* __has_feature(ptrauth_calls) */
3913
3914 IORecursiveLockLock(sKextLock);
3915
3916 count = sLoadedKexts->getCount();
3917 for (i = 0; i < count; i++) {
3918 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3919 if (thisKext == sKernelKext) {
3920 continue;
3921 }
3922 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3923 kmod_info = thisKext->kmod_info;
3924 vm_address_t kext_start = kmod_info->address;
3925 vm_address_t kext_end = kext_start + kmod_info->size;
3926 if ((kext_start <= address) && (address < kext_end)) {
3927 foundKext.reset(thisKext, OSRetain);
3928 goto finish;
3929 }
3930 #if defined(__arm64__)
3931 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3932 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3933 foundKext.reset(thisKext, OSRetain);
3934 goto finish;
3935 }
3936 #endif /* defined (__arm64__) */
3937 }
3938 }
3939 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3940 foundKext.reset(sKernelKext, OSRetain);
3941 goto finish;
3942 }
3943 /*
3944 * DriverKit userspace executables do not have a kernel linkedExecutable,
3945 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3946 * here, so use the original address passed to this method.
3947 *
3948 * This is supposed to be used for logging reasons only. When logd
3949 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3950 * remove it here before checking it against the LoadTag.
3951 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3952 */
3953
3954 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
3955 count = sLoadedDriverKitKexts->getCount();
3956 for (i = 0; i < count; i++) {
3957 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
3958 if (thisKext->getLoadTag() == address) {
3959 foundKext.reset(thisKext, OSRetain);
3960 }
3961 }
3962
3963 finish:
3964 IORecursiveLockUnlock(sKextLock);
3965
3966 return foundKext;
3967 }
3968
3969 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)3970 OSKext::copyKextUUIDForAddress(OSNumber *address)
3971 {
3972 OSSharedPtr<OSData> uuid;
3973 OSSharedPtr<OSKext> kext;
3974
3975 if (!address) {
3976 return NULL;
3977 }
3978
3979 #if CONFIG_MACF
3980 /* Is the calling process allowed to query kext info? */
3981 if (current_task() != kernel_task) {
3982 int macCheckResult = 0;
3983 kauth_cred_t cred = NULL;
3984
3985 cred = kauth_cred_get_with_ref();
3986 macCheckResult = mac_kext_check_query(cred);
3987 kauth_cred_unref(&cred);
3988
3989 if (macCheckResult != 0) {
3990 OSKextLog(/* kext */ NULL,
3991 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3992 "Failed to query kext UUID (MAC policy error 0x%x).",
3993 macCheckResult);
3994 return NULL;
3995 }
3996 }
3997 #endif
3998
3999 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4000 if (slidAddress != 0) {
4001 kext = lookupKextWithAddress(slidAddress);
4002 if (kext) {
4003 uuid = kext->copyTextUUID();
4004 }
4005 }
4006
4007 if (!uuid) {
4008 /*
4009 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4010 * a kext. This might have happened because the log message came from a dext.
4011 *
4012 * Try again with the original address.
4013 */
4014 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4015 if (kext && kext->isDriverKit()) {
4016 uuid = kext->copyTextUUID();
4017 }
4018 }
4019
4020 return uuid;
4021 }
4022
4023 /*********************************************************************
4024 *********************************************************************/
4025 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4026 OSKext::lookupKextWithUUID(uuid_t wanted)
4027 {
4028 OSSharedPtr<OSKext> foundKext; // returned
4029 uint32_t j, i;
4030 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4031 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4032
4033
4034 IORecursiveLockLock(sKextLock);
4035
4036 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4037 for (i = 0; i < count[j]; i++) {
4038 OSKext * thisKext = NULL;
4039
4040 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4041 if (!thisKext) {
4042 continue;
4043 }
4044
4045 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4046 if (!uuid_data) {
4047 continue;
4048 }
4049
4050 uuid_t uuid;
4051 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4052
4053 if (0 == uuid_compare(wanted, uuid)) {
4054 foundKext.reset(thisKext, OSRetain);
4055 goto finish;
4056 }
4057 }
4058 }
4059 finish:
4060 IORecursiveLockUnlock(sKextLock);
4061
4062 return foundKext;
4063 }
4064
4065
4066
4067
4068 /*********************************************************************
4069 *********************************************************************/
4070 /* static */
4071 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4072 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4073 {
4074 bool result = false;
4075 OSKext * foundKext = NULL; // returned
4076
4077 IORecursiveLockLock(sKextLock);
4078
4079 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4080 if (foundKext && foundKext->isLoaded()) {
4081 result = true;
4082 }
4083
4084 IORecursiveLockUnlock(sKextLock);
4085
4086 return result;
4087 }
4088
4089 /*********************************************************************
4090 * xxx - should spawn a separate thread so a kext can safely have
4091 * xxx - itself unloaded.
4092 *********************************************************************/
4093 /* static */
4094 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4095 OSKext::removeKext(
4096 OSKext * aKext,
4097 #if CONFIG_EMBEDDED
4098 __unused
4099 #endif
4100 bool terminateServicesAndRemovePersonalitiesFlag)
4101 {
4102 #if CONFIG_EMBEDDED
4103 OSKextLog(aKext,
4104 kOSKextLogErrorLevel |
4105 kOSKextLogKextBookkeepingFlag,
4106 "removeKext() called for %s, not supported on embedded",
4107 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4108
4109 return kOSReturnSuccess;
4110 #else /* CONFIG_EMBEDDED */
4111
4112 OSReturn result = kOSKextReturnInUse;
4113 OSKext * checkKext = NULL; // do not release
4114 #if CONFIG_MACF
4115 int macCheckResult = 0;
4116 kauth_cred_t cred = NULL;
4117 #endif
4118
4119 IORecursiveLockLock(sKextLock);
4120
4121 /* If the kext has no identifier, it failed to init
4122 * so isn't in sKextsByID and it isn't loaded.
4123 */
4124 if (!aKext->getIdentifier()) {
4125 result = kOSReturnSuccess;
4126 goto finish;
4127 }
4128
4129 checkKext = OSDynamicCast(OSKext,
4130 sKextsByID->getObject(aKext->getIdentifier()));
4131 if (checkKext != aKext) {
4132 result = kOSKextReturnNotFound;
4133 goto finish;
4134 }
4135
4136 if (aKext->isLoaded()) {
4137 #if CONFIG_MACF
4138 if (current_task() != kernel_task) {
4139 cred = kauth_cred_get_with_ref();
4140 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4141 kauth_cred_unref(&cred);
4142 }
4143
4144 if (macCheckResult != 0) {
4145 result = kOSReturnError;
4146 OSKextLog(aKext,
4147 kOSKextLogErrorLevel |
4148 kOSKextLogKextBookkeepingFlag,
4149 "Failed to remove kext %s (MAC policy error 0x%x).",
4150 aKext->getIdentifierCString(), macCheckResult);
4151 goto finish;
4152 }
4153 #endif
4154
4155 /* make sure there are no resource requests in flight - 17187548 */
4156 if (aKext->countRequestCallbacks()) {
4157 goto finish;
4158 }
4159 if (aKext->flags.unloadUnsupported) {
4160 result = kOSKextReturnInUse;
4161 OSKextLog(aKext,
4162 kOSKextLogErrorLevel |
4163 kOSKextLogKextBookkeepingFlag,
4164 "Can't remove kext %s; unsupported by cache.",
4165 aKext->getIdentifierCString());
4166 goto finish;
4167 }
4168
4169 /* If we are terminating, send the request to the IOCatalogue
4170 * (which will actually call us right back but that's ok we have
4171 * a recursive lock don't you know) but do not ask the IOCatalogue
4172 * to call back with an unload, we'll do that right here.
4173 */
4174 if (terminateServicesAndRemovePersonalitiesFlag) {
4175 result = gIOCatalogue->terminateDriversForModule(
4176 aKext->getIdentifierCString(), /* unload */ false);
4177 if (result != kOSReturnSuccess) {
4178 OSKextLog(aKext,
4179 kOSKextLogErrorLevel |
4180 kOSKextLogKextBookkeepingFlag,
4181 "Can't remove kext %s; services failed to terminate - 0x%x.",
4182 aKext->getIdentifierCString(), result);
4183 goto finish;
4184 }
4185 }
4186
4187 result = aKext->unload();
4188 if (result != kOSReturnSuccess) {
4189 goto finish;
4190 }
4191 }
4192
4193 /* Remove personalities as requested. This is a bit redundant for a loaded
4194 * kext as IOCatalogue::terminateDriversForModule() removes driver
4195 * personalities, but it doesn't restart matching, which we always want
4196 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4197 * that happens.
4198 */
4199 if (terminateServicesAndRemovePersonalitiesFlag) {
4200 aKext->removePersonalitiesFromCatalog();
4201 }
4202
4203 if (aKext->isInFileset()) {
4204 OSKextLog(aKext,
4205 kOSKextLogProgressLevel |
4206 kOSKextLogKextBookkeepingFlag,
4207 "Fileset kext %s unloaded.",
4208 aKext->getIdentifierCString());
4209 } else {
4210 OSKextLog(aKext,
4211 kOSKextLogProgressLevel |
4212 kOSKextLogKextBookkeepingFlag,
4213 "Removing kext %s.",
4214 aKext->getIdentifierCString());
4215
4216 sKextsByID->removeObject(aKext->getIdentifier());
4217 }
4218 result = kOSReturnSuccess;
4219
4220 finish:
4221 IORecursiveLockUnlock(sKextLock);
4222 return result;
4223 #endif /* CONFIG_EMBEDDED */
4224 }
4225
4226 /*********************************************************************
4227 *********************************************************************/
4228 /* static */
4229 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4230 OSKext::removeKextWithIdentifier(
4231 const char * kextIdentifier,
4232 bool terminateServicesAndRemovePersonalitiesFlag)
4233 {
4234 OSReturn result = kOSReturnError;
4235
4236 IORecursiveLockLock(sKextLock);
4237
4238 OSKext * aKext = OSDynamicCast(OSKext,
4239 sKextsByID->getObject(kextIdentifier));
4240 if (!aKext) {
4241 result = kOSKextReturnNotFound;
4242 OSKextLog(/* kext */ NULL,
4243 kOSKextLogErrorLevel |
4244 kOSKextLogKextBookkeepingFlag,
4245 "Can't remove kext %s - not found.",
4246 kextIdentifier);
4247 goto finish;
4248 }
4249
4250 result = OSKext::removeKext(aKext,
4251 terminateServicesAndRemovePersonalitiesFlag);
4252
4253 finish:
4254 IORecursiveLockUnlock(sKextLock);
4255
4256 return result;
4257 }
4258
4259 /*********************************************************************
4260 *********************************************************************/
4261 /* static */
4262 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4263 OSKext::removeKextWithLoadTag(
4264 OSKextLoadTag loadTag,
4265 bool terminateServicesAndRemovePersonalitiesFlag)
4266 {
4267 OSReturn result = kOSReturnError;
4268 OSKext * foundKext = NULL;
4269 uint32_t i, j;
4270 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4271 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4272
4273
4274 IORecursiveLockLock(sKextLock);
4275
4276 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4277 for (i = 0; i < count[j]; i++) {
4278 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4279 if (thisKext->loadTag == loadTag) {
4280 foundKext = thisKext;
4281 break;
4282 }
4283 }
4284 }
4285
4286 if (!foundKext) {
4287 result = kOSKextReturnNotFound;
4288 OSKextLog(/* kext */ NULL,
4289 kOSKextLogErrorLevel |
4290 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4291 "Can't remove kext with load tag %d - not found.",
4292 loadTag);
4293 goto finish;
4294 }
4295
4296 result = OSKext::removeKext(foundKext,
4297 terminateServicesAndRemovePersonalitiesFlag);
4298
4299 finish:
4300 IORecursiveLockUnlock(sKextLock);
4301
4302 return result;
4303 }
4304
4305 /*********************************************************************
4306 *********************************************************************/
4307 OSSharedPtr<OSDictionary>
copyKexts(void)4308 OSKext::copyKexts(void)
4309 {
4310 OSSharedPtr<OSDictionary> result;
4311
4312 IORecursiveLockLock(sKextLock);
4313 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4314 IORecursiveLockUnlock(sKextLock);
4315
4316 return result;
4317 }
4318
4319 /*********************************************************************
4320 *********************************************************************/
4321 #define BOOTER_KEXT_PREFIX "Driver-"
4322
4323 typedef struct _DeviceTreeBuffer {
4324 uint32_t paddr;
4325 uint32_t length;
4326 } _DeviceTreeBuffer;
4327
4328 /*********************************************************************
4329 * Create a dictionary of excluded kexts from the given booter data.
4330 *********************************************************************/
4331 /* static */
4332 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4333 OSKext::createExcludeListFromBooterData(
4334 OSDictionary * theDictionary,
4335 OSCollectionIterator * theIterator )
4336 {
4337 OSString * deviceTreeName = NULL; // do not release
4338 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4339 char * booterDataPtr = NULL; // do not release
4340 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4341 char * infoDictAddr = NULL; // do not release
4342 OSSharedPtr<OSObject> parsedXML;
4343 OSDictionary * theInfoDict = NULL; // do not release
4344
4345 theIterator->reset();
4346
4347 /* look for AppleKextExcludeList.kext */
4348 while ((deviceTreeName =
4349 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4350 const char * devTreeNameCString;
4351 OSData * deviceTreeEntry; // do not release
4352 OSString * myBundleID; // do not release
4353
4354 deviceTreeEntry =
4355 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4356 if (!deviceTreeEntry) {
4357 continue;
4358 }
4359
4360 /* Make sure it is a kext */
4361 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4362 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4363 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4364 OSKextLog(NULL,
4365 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4366 "\"%s\" not a kext",
4367 devTreeNameCString);
4368 continue;
4369 }
4370
4371 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4372 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4373 if (!deviceTreeBuffer) {
4374 continue;
4375 }
4376
4377 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4378 if (!booterDataPtr) {
4379 continue;
4380 }
4381
4382 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4383 if (!kextFileInfo->infoDictPhysAddr ||
4384 !kextFileInfo->infoDictLength) {
4385 continue;
4386 }
4387
4388 infoDictAddr = (char *)
4389 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4390 if (!infoDictAddr) {
4391 continue;
4392 }
4393
4394 parsedXML = OSUnserializeXML(infoDictAddr);
4395 if (!parsedXML) {
4396 continue;
4397 }
4398
4399 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4400 if (!theInfoDict) {
4401 continue;
4402 }
4403
4404 myBundleID =
4405 OSDynamicCast(OSString,
4406 theInfoDict->getObject(kCFBundleIdentifierKey));
4407 if (myBundleID &&
4408 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4409 boolean_t updated = updateExcludeList(theInfoDict);
4410 if (!updated) {
4411 /* 25322874 */
4412 panic("Missing OSKextExcludeList dictionary");
4413 }
4414 break;
4415 }
4416 } // while ( (deviceTreeName = ...) )
4417
4418 return;
4419 }
4420
4421 /*********************************************************************
4422 * Create a dictionary of excluded kexts from the given prelink
4423 * info (kernelcache).
4424 *********************************************************************/
4425 /* static */
4426 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4427 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4428 {
4429 OSDictionary * myInfoDict = NULL; // do not release
4430 OSString * myBundleID; // do not release
4431 u_int i;
4432
4433 /* Find the Apple Kext Exclude List. */
4434 for (i = 0; i < theInfoArray->getCount(); i++) {
4435 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4436 if (!myInfoDict) {
4437 continue;
4438 }
4439 myBundleID =
4440 OSDynamicCast(OSString,
4441 myInfoDict->getObject(kCFBundleIdentifierKey));
4442 if (myBundleID &&
4443 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4444 boolean_t updated = updateExcludeList(myInfoDict);
4445 if (!updated) {
4446 /* 25322874 */
4447 panic("Missing OSKextExcludeList dictionary");
4448 }
4449 break;
4450 }
4451 } // for (i = 0; i < theInfoArray->getCount()...
4452
4453 return;
4454 }
4455
4456 /* static */
4457 boolean_t
updateExcludeList(OSDictionary * infoDict)4458 OSKext::updateExcludeList(OSDictionary *infoDict)
4459 {
4460 OSDictionary *myTempDict = NULL; // do not free
4461 OSString *myTempString = NULL; // do not free
4462 OSKextVersion newVersion = 0;
4463 boolean_t updated = false;
4464
4465 if (!infoDict) {
4466 return false;
4467 }
4468
4469 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4470 if (!myTempDict) {
4471 return false;
4472 }
4473
4474 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4475 if (!myTempString) {
4476 return false;
4477 }
4478
4479 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4480 if (newVersion == 0) {
4481 return false;
4482 }
4483
4484 IORecursiveLockLock(sKextLock);
4485
4486 if (newVersion > sExcludeListVersion) {
4487 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4488 sExcludeListVersion = newVersion;
4489 updated = true;
4490 }
4491
4492 IORecursiveLockUnlock(sKextLock);
4493 return updated;
4494 }
4495
4496 #if PRAGMA_MARK
4497 #pragma mark Accessors
4498 #endif
4499 /*********************************************************************
4500 *********************************************************************/
4501 const OSSymbol *
getIdentifier(void)4502 OSKext::getIdentifier(void)
4503 {
4504 return bundleID.get();
4505 }
4506
4507 /*********************************************************************
4508 * A kext must have a bundle identifier to even survive initialization;
4509 * this is guaranteed to exist past then.
4510 *********************************************************************/
4511 const char *
getIdentifierCString(void)4512 OSKext::getIdentifierCString(void)
4513 {
4514 return bundleID->getCStringNoCopy();
4515 }
4516
4517 /*********************************************************************
4518 *********************************************************************/
4519 OSKextVersion
getVersion(void)4520 OSKext::getVersion(void)
4521 {
4522 return version;
4523 }
4524
4525 /*********************************************************************
4526 *********************************************************************/
4527 OSKextVersion
getCompatibleVersion(void)4528 OSKext::getCompatibleVersion(void)
4529 {
4530 return compatibleVersion;
4531 }
4532
4533 /*********************************************************************
4534 *********************************************************************/
4535 bool
isLibrary(void)4536 OSKext::isLibrary(void)
4537 {
4538 return getCompatibleVersion() > 0;
4539 }
4540
4541 /*********************************************************************
4542 *********************************************************************/
4543 bool
isCompatibleWithVersion(OSKextVersion aVersion)4544 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4545 {
4546 if ((compatibleVersion > -1 && version > -1) &&
4547 (compatibleVersion <= version && aVersion <= version)) {
4548 return true;
4549 }
4550 return false;
4551 }
4552
4553 /*********************************************************************
4554 *********************************************************************/
4555 bool
declaresExecutable(void)4556 OSKext::declaresExecutable(void)
4557 {
4558 if (isDriverKit()) {
4559 return false;
4560 }
4561 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4562 }
4563
4564 /*********************************************************************
4565 *********************************************************************/
4566 OSData *
getExecutable(void)4567 OSKext::getExecutable(void)
4568 {
4569 OSData * result = NULL;
4570 OSSharedPtr<OSData> extractedExecutable;
4571
4572 if (flags.builtin) {
4573 return sKernelKext->linkedExecutable.get();
4574 }
4575
4576 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4577 if (result) {
4578 return result;
4579 }
4580
4581 #if CONFIG_KXLD
4582 OSData * mkextExecutableRef = NULL; // do not release
4583 mkextExecutableRef = OSDynamicCast(OSData,
4584 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4585
4586 if (mkextExecutableRef) {
4587 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4588 mkextExecutableRef->getBytesNoCopy();
4589 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4590 if (mkextVersion == MKEXT_VERS_2) {
4591 mkext2_file_entry * fileinfo =
4592 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4593 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4594 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4595 extractedExecutable = extractMkext2FileData(
4596 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4597 compressedSize, fullSize);
4598 } else {
4599 OSKextLog(this, kOSKextLogErrorLevel |
4600 kOSKextLogArchiveFlag,
4601 "Kext %s - unknown mkext version 0x%x for executable.",
4602 getIdentifierCString(), mkextVersion);
4603 }
4604
4605 /* Regardless of success, remove the mkext executable,
4606 * and drop one reference on the mkext. (setExecutable() does not
4607 * replace, it removes, or panics if asked to replace.)
4608 */
4609 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4610 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4611
4612 if (extractedExecutable && extractedExecutable->getLength()) {
4613 if (!setExecutable(extractedExecutable.get())) {
4614 goto finish;
4615 }
4616 result = extractedExecutable.get();
4617 } else {
4618 goto finish;
4619 }
4620 }
4621
4622 finish:
4623 #endif // CONFIG_KXLD
4624 return result;
4625 }
4626
4627 /*********************************************************************
4628 *********************************************************************/
4629 bool
isInterface(void)4630 OSKext::isInterface(void)
4631 {
4632 return flags.interface;
4633 }
4634
4635 /*********************************************************************
4636 *********************************************************************/
4637 bool
isKernel(void)4638 OSKext::isKernel(void)
4639 {
4640 return this == sKernelKext;
4641 }
4642
4643 /*********************************************************************
4644 *********************************************************************/
4645 bool
isKernelComponent(void)4646 OSKext::isKernelComponent(void)
4647 {
4648 return flags.kernelComponent ? true : false;
4649 }
4650
4651 /*********************************************************************
4652 *********************************************************************/
4653 bool
isExecutable(void)4654 OSKext::isExecutable(void)
4655 {
4656 return !isKernel() && !isInterface() && declaresExecutable();
4657 }
4658
4659 /*********************************************************************
4660 * We might want to check this recursively for all dependencies,
4661 * since a subtree of dependencies could get loaded before we hit
4662 * a dependency that isn't safe-boot-loadable.
4663 *
4664 * xxx - Might want to return false if OSBundleEnableKextLogging or
4665 * OSBundleDebugLevel
4666 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4667 * the point except it's usually development drivers, which might
4668 * cause panics on startup, that have those properties). Heh; could
4669 * use a "kx" boot-arg!
4670 *********************************************************************/
4671 bool
isLoadableInSafeBoot(void)4672 OSKext::isLoadableInSafeBoot(void)
4673 {
4674 bool result = false;
4675 OSString * required = NULL; // do not release
4676
4677 if (isKernel()) {
4678 result = true;
4679 goto finish;
4680 }
4681
4682 if (isDriverKit()) {
4683 result = true;
4684 goto finish;
4685 }
4686
4687 required = OSDynamicCast(OSString,
4688 getPropertyForHostArch(kOSBundleRequiredKey));
4689 if (!required) {
4690 goto finish;
4691 }
4692 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4693 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4694 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4695 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4696 required->isEqualTo(kOSBundleRequiredConsole)) {
4697 result = true;
4698 }
4699
4700 finish:
4701 return result;
4702 }
4703
4704 /*********************************************************************
4705 *********************************************************************/
4706 bool
isPrelinked(void)4707 OSKext::isPrelinked(void)
4708 {
4709 return flags.prelinked ? true : false;
4710 }
4711
4712 /*********************************************************************
4713 *********************************************************************/
4714 bool
isLoaded(void)4715 OSKext::isLoaded(void)
4716 {
4717 return flags.loaded ? true : false;
4718 }
4719
4720 /*********************************************************************
4721 *********************************************************************/
4722 bool
isStarted(void)4723 OSKext::isStarted(void)
4724 {
4725 return flags.started ? true : false;
4726 }
4727
4728 /*********************************************************************
4729 *********************************************************************/
4730 bool
isCPPInitialized(void)4731 OSKext::isCPPInitialized(void)
4732 {
4733 return flags.CPPInitialized;
4734 }
4735
4736 /*********************************************************************
4737 *********************************************************************/
4738 void
setCPPInitialized(bool initialized)4739 OSKext::setCPPInitialized(bool initialized)
4740 {
4741 flags.CPPInitialized = initialized;
4742 }
4743
4744 /*********************************************************************
4745 *********************************************************************/
4746 uint32_t
getLoadTag(void)4747 OSKext::getLoadTag(void)
4748 {
4749 return loadTag;
4750 }
4751
4752 /*********************************************************************
4753 *********************************************************************/
4754 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)4755 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4756 {
4757 if (linkedExecutable) {
4758 *loadSize = linkedExecutable->getLength();
4759
4760 /* If we have a kmod_info struct, calculated the wired size
4761 * from that. Otherwise it's the full load size.
4762 */
4763 if (kmod_info) {
4764 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
4765 } else {
4766 *wiredSize = *loadSize;
4767 }
4768 } else {
4769 *wiredSize = 0;
4770 *loadSize = 0;
4771 }
4772 }
4773
4774 /*********************************************************************
4775 *********************************************************************/
4776 OSSharedPtr<OSData>
copyUUID(void)4777 OSKext::copyUUID(void)
4778 {
4779 OSSharedPtr<OSData> result;
4780 OSData * theExecutable = NULL; // do not release
4781 const kernel_mach_header_t * header;
4782
4783 /* An interface kext doesn't have a linked executable with an LC_UUID,
4784 * we create one when it's linked.
4785 */
4786 if (interfaceUUID) {
4787 result = interfaceUUID;
4788 goto finish;
4789 }
4790
4791 if (flags.builtin || isInterface()) {
4792 return sKernelKext->copyUUID();
4793 }
4794
4795 if (isDriverKit() && infoDict) {
4796 return driverKitUUID;
4797 }
4798
4799 /* For real kexts, try to get the UUID from the linked executable,
4800 * or if is hasn't been linked yet, the unrelocated executable.
4801 */
4802 theExecutable = linkedExecutable.get();
4803 if (!theExecutable) {
4804 theExecutable = getExecutable();
4805 }
4806
4807 if (!theExecutable) {
4808 goto finish;
4809 }
4810
4811 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4812 result = copyMachoUUID(header);
4813
4814 finish:
4815 return result;
4816 }
4817
4818 /*********************************************************************
4819 *********************************************************************/
4820 OSSharedPtr<OSData>
copyTextUUID(void)4821 OSKext::copyTextUUID(void)
4822 {
4823 if (flags.builtin) {
4824 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4825 }
4826 return copyUUID();
4827 }
4828
4829 /*********************************************************************
4830 *********************************************************************/
4831 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)4832 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4833 {
4834 OSSharedPtr<OSData> result;
4835 const struct load_command * load_cmd = NULL;
4836 const struct uuid_command * uuid_cmd = NULL;
4837 uint32_t i;
4838
4839 load_cmd = (const struct load_command *)&header[1];
4840
4841 if (header->magic != MH_MAGIC_KERNEL) {
4842 OSKextLog(NULL,
4843 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4844 "%s: bad header %p",
4845 __func__,
4846 header);
4847 goto finish;
4848 }
4849
4850 for (i = 0; i < header->ncmds; i++) {
4851 if (load_cmd->cmd == LC_UUID) {
4852 uuid_cmd = (struct uuid_command *)load_cmd;
4853 result = OSData::withValue(uuid_cmd->uuid);
4854 goto finish;
4855 }
4856 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4857 }
4858
4859 finish:
4860 return result;
4861 }
4862
4863 void
setDriverKitUUID(OSData * uuid)4864 OSKext::setDriverKitUUID(OSData *uuid)
4865 {
4866 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4867 OSSafeReleaseNULL(uuid);
4868 }
4869 }
4870
4871 /*********************************************************************
4872 *********************************************************************/
4873 #if defined (__arm__)
4874 #include <arm/arch.h>
4875 #endif
4876
4877 #if defined (__x86_64__)
4878 #define ARCHNAME "x86_64"
4879 #elif defined (__arm64__)
4880 #define ARCHNAME "arm64"
4881 #elif defined (__arm__)
4882
4883 #if defined (__ARM_ARCH_7S__)
4884 #define ARCHNAME "armv7s"
4885 #elif defined (__ARM_ARCH_7F__)
4886 #define ARCHNAME "armv7f"
4887 #elif defined (__ARM_ARCH_7K__)
4888 #define ARCHNAME "armv7k"
4889 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4890 #define ARCHNAME "armv7"
4891 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4892 #define ARCHNAME "armv6"
4893 #endif
4894
4895 #elif defined (__arm64__)
4896 #define ARCHNAME "arm64"
4897 #else
4898 #error architecture not supported
4899 #endif
4900
4901 #define ARCH_SEPARATOR_CHAR '_'
4902
4903 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)4904 makeHostArchKey(const char * key, size_t * keySizeOut)
4905 {
4906 char * result = NULL;
4907 size_t keyLength = strlen(key);
4908 size_t keySize;
4909
4910 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4911 */
4912 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4913 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4914
4915 if (!result) {
4916 goto finish;
4917 }
4918 strlcpy(result, key, keySize);
4919 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4920 result[keyLength] = '\0';
4921 strlcat(result, ARCHNAME, keySize);
4922 *keySizeOut = keySize;
4923
4924 finish:
4925 return result;
4926 }
4927
4928 /*********************************************************************
4929 *********************************************************************/
4930 OSObject *
getPropertyForHostArch(const char * key)4931 OSKext::getPropertyForHostArch(const char * key)
4932 {
4933 OSObject * result = NULL;// do not release
4934 size_t hostArchKeySize = 0;
4935 char * hostArchKey = NULL;// must kfree
4936
4937 if (!key || !infoDict) {
4938 goto finish;
4939 }
4940
4941 /* Some properties are not allowed to be arch-variant:
4942 * - Any CFBundle... property.
4943 * - OSBundleIsInterface.
4944 * - OSKernelResource.
4945 */
4946 if (STRING_HAS_PREFIX(key, "OS") ||
4947 STRING_HAS_PREFIX(key, "IO")) {
4948 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4949 if (!hostArchKey) {
4950 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4951 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4952 "Allocation failure.");
4953 goto finish;
4954 }
4955 result = infoDict->getObject(hostArchKey);
4956 }
4957
4958 if (!result) {
4959 result = infoDict->getObject(key);
4960 }
4961
4962 finish:
4963 if (hostArchKey) {
4964 kfree_data(hostArchKey, hostArchKeySize);
4965 }
4966 return result;
4967 }
4968
4969 #if PRAGMA_MARK
4970 #pragma mark Load/Start/Stop/Unload
4971 #endif
4972
4973 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4974
4975 /*********************************************************************
4976 * sExcludeListByID is a dictionary with keys / values of:
4977 * key = bundleID string of kext we will not allow to load
4978 * value = version string(s) of the kext that is to be denied loading.
4979 * The version strings can be comma delimited. For example if kext
4980 * com.foocompany.fookext has two versions that we want to deny
4981 * loading then the version strings might look like:
4982 * 1.0.0, 1.0.1
4983 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4984 * not load the kext.
4985 *
4986 * Value may also be in the form of "LE 2.0.0" (version numbers
4987 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4988 * number less than 2.0.0 will not load)
4989 *
4990 * NOTE - we cannot use the characters "<=" or "<" because we have code
4991 * that serializes plists and treats '<' as a special character.
4992 *********************************************************************/
4993 bool
isInExcludeList(void)4994 OSKext::isInExcludeList(void)
4995 {
4996 OSString * versionString = NULL; // do not release
4997 char * versionCString = NULL; // do not free
4998 size_t i;
4999 boolean_t wantLessThan = false;
5000 boolean_t wantLessThanEqualTo = false;
5001 boolean_t isInExcludeList = true;
5002 char myBuffer[32];
5003
5004 IORecursiveLockLock(sKextLock);
5005
5006 if (!sExcludeListByID) {
5007 isInExcludeList = false;
5008 } else {
5009 /* look up by bundleID in our exclude list and if found get version
5010 * string (or strings) that we will not allow to load
5011 */
5012 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5013 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5014 isInExcludeList = false;
5015 }
5016 }
5017
5018 IORecursiveLockUnlock(sKextLock);
5019
5020 if (!isInExcludeList) {
5021 return false;
5022 }
5023
5024 /* parse version strings */
5025 versionCString = (char *) versionString->getCStringNoCopy();
5026
5027 /* look for "LT" or "LE" form of version string, must be in first two
5028 * positions.
5029 */
5030 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5031 wantLessThan = true;
5032 versionCString += 2;
5033 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5034 wantLessThanEqualTo = true;
5035 versionCString += 2;
5036 }
5037
5038 for (i = 0; *versionCString != 0x00; versionCString++) {
5039 /* skip whitespace */
5040 if (isWhiteSpace(*versionCString)) {
5041 continue;
5042 }
5043
5044 /* peek ahead for version string separator or null terminator */
5045 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5046 /* OK, we have a version string */
5047 myBuffer[i++] = *versionCString;
5048 myBuffer[i] = 0x00;
5049
5050 OSKextVersion excludeVers;
5051 excludeVers = OSKextParseVersionString(myBuffer);
5052
5053 if (wantLessThanEqualTo) {
5054 if (version <= excludeVers) {
5055 return true;
5056 }
5057 } else if (wantLessThan) {
5058 if (version < excludeVers) {
5059 return true;
5060 }
5061 } else if (version == excludeVers) {
5062 return true;
5063 }
5064
5065 /* reset for the next (if any) version string */
5066 i = 0;
5067 wantLessThan = false;
5068 wantLessThanEqualTo = false;
5069 } else {
5070 /* save valid version character */
5071 myBuffer[i++] = *versionCString;
5072
5073 /* make sure bogus version string doesn't overrun local buffer */
5074 if (i >= sizeof(myBuffer)) {
5075 break;
5076 }
5077 }
5078 }
5079
5080 return false;
5081 }
5082
5083 /*********************************************************************
5084 * sNonLoadableKextsByID is a dictionary with keys / values of:
5085 * key = bundleID string of kext we will not allow to load
5086 * value = boolean (true == loadable, false == not loadable)
5087 *
5088 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5089 * i.e., the value for the kext's bundleID will be false. All kexts in
5090 * the primary and system KCs will always be marked as "loadable."
5091 *
5092 * This list ultimately comes from kexts which have been uninstalled
5093 * in user space by deleting the kext from disk, but which have not
5094 * yet been removed from the AuxKC. Because the user could choose to
5095 * re-install the exact same version of the kext, we need to keep
5096 * a dictionary of boolean values so that user space only needs to
5097 * keep a simple list of "uninstalled" or "missing" bundles. When
5098 * a bundle is re-installed, the iokit daemon can use the
5099 * AucKCBundleAvailable predicate to set the individual kext's
5100 * availability to true.
5101 *********************************************************************/
5102 bool
isLoadable(void)5103 OSKext::isLoadable(void)
5104 {
5105 bool isLoadable = true;
5106
5107 if (kc_type != KCKindAuxiliary) {
5108 /* this filtering only applies to kexts in the auxkc */
5109 return true;
5110 }
5111
5112 IORecursiveLockLock(sKextLock);
5113
5114 if (sNonLoadableKextsByID) {
5115 /* look up by bundleID in our exclude list and if found get version
5116 * string (or strings) that we will not allow to load
5117 */
5118 OSBoolean *loadableVal;
5119 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5120 if (loadableVal && !loadableVal->getValue()) {
5121 isLoadable = false;
5122 }
5123 }
5124 IORecursiveLockUnlock(sKextLock);
5125
5126 return isLoadable;
5127 }
5128
5129 /*********************************************************************
5130 *********************************************************************/
5131 /* static */
5132 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5133 OSKext::loadKextWithIdentifier(
5134 const char * kextIdentifierCString,
5135 Boolean allowDeferFlag,
5136 Boolean delayAutounloadFlag,
5137 OSKextExcludeLevel startOpt,
5138 OSKextExcludeLevel startMatchingOpt,
5139 OSArray * personalityNames)
5140 {
5141 OSReturn result = kOSReturnError;
5142 OSSharedPtr<OSString> kextIdentifier;
5143
5144 kextIdentifier = OSString::withCString(kextIdentifierCString);
5145 if (!kextIdentifier) {
5146 result = kOSKextReturnNoMemory;
5147 goto finish;
5148 }
5149 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5150 NULL /* kextRef */,
5151 allowDeferFlag, delayAutounloadFlag,
5152 startOpt, startMatchingOpt, personalityNames);
5153
5154 finish:
5155 return result;
5156 }
5157
5158 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5159 OSKext::loadKextWithIdentifier(
5160 OSString * kextIdentifier,
5161 OSSharedPtr<OSObject> &kextRef,
5162 Boolean allowDeferFlag,
5163 Boolean delayAutounloadFlag,
5164 OSKextExcludeLevel startOpt,
5165 OSKextExcludeLevel startMatchingOpt,
5166 OSArray * personalityNames)
5167 {
5168 OSObject * kextRefRaw = NULL;
5169 OSReturn result;
5170
5171 result = loadKextWithIdentifier(kextIdentifier,
5172 &kextRefRaw,
5173 allowDeferFlag,
5174 delayAutounloadFlag,
5175 startOpt,
5176 startMatchingOpt,
5177 personalityNames);
5178 if ((kOSReturnSuccess == result) && kextRefRaw) {
5179 kextRef.reset(kextRefRaw, OSNoRetain);
5180 }
5181 return result;
5182 }
5183
5184 /*********************************************************************
5185 *********************************************************************/
5186 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5187 OSKext::loadKextWithIdentifier(
5188 OSString * kextIdentifier,
5189 OSObject ** kextRef,
5190 Boolean allowDeferFlag,
5191 Boolean delayAutounloadFlag,
5192 OSKextExcludeLevel startOpt,
5193 OSKextExcludeLevel startMatchingOpt,
5194 OSArray * personalityNames)
5195 {
5196 OSReturn result = kOSReturnError;
5197 OSReturn pingResult = kOSReturnError;
5198 OSKext * theKext = NULL; // do not release
5199 OSSharedPtr<OSDictionary> loadRequest;
5200 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5201
5202 if (kextRef) {
5203 *kextRef = NULL;
5204 }
5205
5206 IORecursiveLockLock(sKextLock);
5207
5208 if (!kextIdentifier) {
5209 result = kOSKextReturnInvalidArgument;
5210 goto finish;
5211 }
5212
5213 OSKext::recordIdentifierRequest(kextIdentifier);
5214
5215 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5216 if (!theKext) {
5217 if (!allowDeferFlag) {
5218 OSKextLog(/* kext */ NULL,
5219 kOSKextLogErrorLevel |
5220 kOSKextLogLoadFlag,
5221 "Can't load kext %s - not found.",
5222 kextIdentifier->getCStringNoCopy());
5223 goto finish;
5224 }
5225
5226 if (!sKernelRequestsEnabled) {
5227 OSKextLog(theKext,
5228 kOSKextLogErrorLevel |
5229 kOSKextLogLoadFlag,
5230 "Can't load kext %s - requests to user space are disabled.",
5231 kextIdentifier->getCStringNoCopy());
5232 result = kOSKextReturnDisabled;
5233 goto finish;
5234 }
5235
5236 /* Create a new request unless one is already sitting
5237 * in sKernelRequests for this bundle identifier
5238 */
5239 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5240 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5241 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5242 loadRequest);
5243 if (result != kOSReturnSuccess) {
5244 goto finish;
5245 }
5246 if (!_OSKextSetRequestArgument(loadRequest.get(),
5247 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5248 result = kOSKextReturnNoMemory;
5249 goto finish;
5250 }
5251 if (!sKernelRequests->setObject(loadRequest.get())) {
5252 result = kOSKextReturnNoMemory;
5253 goto finish;
5254 }
5255
5256 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5257 result = kOSKextReturnNoMemory;
5258 goto finish;
5259 }
5260
5261 OSKextLog(theKext,
5262 kOSKextLogDebugLevel |
5263 kOSKextLogLoadFlag,
5264 "Kext %s not found; queued load request to user space.",
5265 kextIdentifier->getCStringNoCopy());
5266 }
5267
5268 pingResult = OSKext::pingIOKitDaemon();
5269 if (pingResult == kOSKextReturnDisabled) {
5270 OSKextLog(/* kext */ NULL,
5271 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5272 kOSKextLogLoadFlag,
5273 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5274 kextIdentifier->getCStringNoCopy());
5275 }
5276
5277 result = kOSKextReturnDeferred;
5278 goto finish;
5279 }
5280
5281 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5282
5283 if (result != kOSReturnSuccess) {
5284 OSKextLog(theKext,
5285 kOSKextLogErrorLevel |
5286 kOSKextLogLoadFlag,
5287 "Failed to load kext %s (error 0x%x).",
5288 kextIdentifier->getCStringNoCopy(), (int)result);
5289
5290 if (theKext->kc_type == KCKindUnknown) {
5291 OSKext::removeKext(theKext,
5292 /* terminateService/removePersonalities */ true);
5293 }
5294 goto finish;
5295 }
5296
5297 if (delayAutounloadFlag) {
5298 OSKextLog(theKext,
5299 kOSKextLogProgressLevel |
5300 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5301 "Setting delayed autounload for %s.",
5302 kextIdentifier->getCStringNoCopy());
5303 theKext->flags.delayAutounload = 1;
5304 }
5305
5306 finish:
5307 if ((kOSReturnSuccess == result) && kextRef) {
5308 *kextRef = theKext;
5309 theKext->matchingRefCount++;
5310 theKext->retain();
5311 }
5312
5313 IORecursiveLockUnlock(sKextLock);
5314
5315 return result;
5316 }
5317
5318 /*********************************************************************
5319 *********************************************************************/
5320 /* static */
5321 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)5322 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5323 {
5324 OSReturn result = kOSReturnError;
5325
5326 OSBoolean *delayAutounloadBool = NULL; // do not release
5327 OSNumber *startKextExcludeNum = NULL; // do not release
5328 OSNumber *startMatchingExcludeNum = NULL; // do not release
5329 OSArray *personalityNames = NULL; // do not release
5330
5331 /*
5332 * Default values for these options:
5333 * regular autounload behavior
5334 * start the kext
5335 * send all personalities to the catalog
5336 */
5337 Boolean delayAutounload = false;
5338 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5339 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5340
5341 IORecursiveLockLock(sKextLock);
5342
5343 OSKextLog(/* kext */ NULL,
5344 kOSKextLogDebugLevel |
5345 kOSKextLogIPCFlag,
5346 "Received kext KC load request from user space.");
5347
5348 /* Regardless of processing, the fact that we have gotten here means some
5349 * user-space program is up and talking to us, so we'll switch our kext
5350 * registration to reflect that.
5351 */
5352 if (!sUserLoadsActive) {
5353 OSKextLog(/* kext */ NULL,
5354 kOSKextLogProgressLevel |
5355 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5356 "Switching to late startup (user-space) kext loading policy.");
5357 sUserLoadsActive = true;
5358 }
5359
5360 delayAutounloadBool = OSDynamicCast(OSBoolean,
5361 _OSKextGetRequestArgument(requestDict,
5362 kKextRequestArgumentDelayAutounloadKey));
5363 startKextExcludeNum = OSDynamicCast(OSNumber,
5364 _OSKextGetRequestArgument(requestDict,
5365 kKextRequestArgumentStartExcludeKey));
5366 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5367 _OSKextGetRequestArgument(requestDict,
5368 kKextRequestArgumentStartMatchingExcludeKey));
5369 personalityNames = OSDynamicCast(OSArray,
5370 _OSKextGetRequestArgument(requestDict,
5371 kKextRequestArgumentPersonalityNamesKey));
5372
5373 if (delayAutounloadBool) {
5374 delayAutounload = delayAutounloadBool->getValue();
5375 }
5376 if (startKextExcludeNum) {
5377 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5378 }
5379 if (startMatchingExcludeNum) {
5380 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5381 }
5382
5383 OSKextLog(/* kext */ NULL,
5384 kOSKextLogProgressLevel |
5385 kOSKextLogIPCFlag,
5386 "Received request from user space to load KC kext %s.",
5387 theKext->getIdentifierCString());
5388
5389 /* this could be in the Auxiliary KC, so record the load request */
5390 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5391
5392 /*
5393 * Load the kext
5394 */
5395 result = theKext->load(startKextExcludeLevel,
5396 startMatchingExcludeLevel, personalityNames);
5397
5398 if (result != kOSReturnSuccess) {
5399 OSKextLog(theKext,
5400 kOSKextLogErrorLevel |
5401 kOSKextLogLoadFlag,
5402 "Failed to load kext %s (error 0x%x).",
5403 theKext->getIdentifierCString(), (int)result);
5404
5405 OSKext::removeKext(theKext,
5406 /* terminateService/removePersonalities */ true);
5407 goto finish;
5408 } else {
5409 OSKextLog(theKext,
5410 kOSKextLogProgressLevel |
5411 kOSKextLogLoadFlag,
5412 "Kext %s Loaded successfully from %s KC",
5413 theKext->getIdentifierCString(), theKext->getKCTypeString());
5414 }
5415
5416 if (delayAutounload) {
5417 OSKextLog(theKext,
5418 kOSKextLogProgressLevel |
5419 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5420 "Setting delayed autounload for %s.",
5421 theKext->getIdentifierCString());
5422 theKext->flags.delayAutounload = 1;
5423 }
5424
5425 finish:
5426 IORecursiveLockUnlock(sKextLock);
5427
5428 return result;
5429 }
5430
5431 /*********************************************************************
5432 *********************************************************************/
5433 /* static */
5434 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)5435 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5436 {
5437 OSReturn result = kOSReturnError;
5438 OSDictionary *anInfoDict = NULL; // do not release
5439
5440 anInfoDict = OSDynamicCast(OSDictionary,
5441 _OSKextGetRequestArgument(requestDict,
5442 kKextRequestArgumentCodelessInfoKey));
5443 if (anInfoDict == NULL) {
5444 OSKextLog(/* kext */ NULL,
5445 kOSKextLogErrorLevel |
5446 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5447 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5448 kextIdentifier->getCStringNoCopy());
5449 return kOSKextReturnInvalidArgument;
5450 }
5451
5452 IORecursiveLockLock(sKextLock);
5453
5454 OSKextLog(/* kext */ NULL,
5455 kOSKextLogProgressLevel |
5456 kOSKextLogIPCFlag,
5457 "Received request from user space to load codeless kext %s.",
5458 kextIdentifier->getCStringNoCopy());
5459
5460 {
5461 // instantiate a new kext, and don't hold a reference
5462 // (the kext subsystem will hold one implicitly)
5463 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5464 if (!newKext) {
5465 OSKextLog(/* kext */ NULL,
5466 kOSKextLogErrorLevel |
5467 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5468 "Could not instantiate codeless kext.");
5469 result = kOSKextReturnNotLoadable;
5470 goto finish;
5471 }
5472 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5473 OSKextLog(/* kext */ NULL,
5474 kOSKextLogErrorLevel |
5475 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5476 "Codeless kext identifiers don't match '%s' != '%s'",
5477 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5478
5479 OSKext::removeKext(newKext.get(), false);
5480 result = kOSKextReturnInvalidArgument;
5481 goto finish;
5482 }
5483
5484 /* Record the request for the codeless kext */
5485 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5486
5487 result = kOSReturnSuccess;
5488 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5489 result = newKext->sendPersonalitiesToCatalog(true, NULL);
5490 }
5491
5492 finish:
5493 IORecursiveLockUnlock(sKextLock);
5494
5495 return result;
5496 }
5497
5498 /*********************************************************************
5499 *********************************************************************/
5500 /* static */
5501 void
dropMatchingReferences(OSSet * kexts)5502 OSKext::dropMatchingReferences(
5503 OSSet * kexts)
5504 {
5505 IORecursiveLockLock(sKextLock);
5506 kexts->iterateObjects(^bool (OSObject * obj) {
5507 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5508 if (!thisKext) {
5509 return false;
5510 }
5511 thisKext->matchingRefCount--;
5512 return false;
5513 });
5514 IORecursiveLockUnlock(sKextLock);
5515 }
5516
5517 /*********************************************************************
5518 *********************************************************************/
5519 /* static */
5520 void
recordIdentifierRequest(OSString * kextIdentifier)5521 OSKext::recordIdentifierRequest(
5522 OSString * kextIdentifier)
5523 {
5524 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5525 bool fail = false;
5526
5527 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5528 goto finish;
5529 }
5530
5531 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5532 if (!kextIdentifierSymbol) {
5533 // xxx - this is really a basic alloc failure
5534 fail = true;
5535 goto finish;
5536 }
5537
5538 IORecursiveLockLock(sKextLock);
5539 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5540 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5541 fail = true;
5542 } else {
5543 // xxx - need to find a way to associate this whole func w/the kext
5544 OSKextLog(/* kext */ NULL,
5545 // xxx - check level
5546 kOSKextLogStepLevel |
5547 kOSKextLogArchiveFlag,
5548 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5549 kextIdentifier->getCStringNoCopy());
5550 }
5551 }
5552 IORecursiveLockUnlock(sKextLock);
5553
5554 finish:
5555
5556 if (fail) {
5557 OSKextLog(/* kext */ NULL,
5558 kOSKextLogErrorLevel |
5559 kOSKextLogArchiveFlag,
5560 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5561 kextIdentifier->getCStringNoCopy());
5562 }
5563 return;
5564 }
5565
5566 /*********************************************************************
5567 *********************************************************************/
5568 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5569 OSKext::load(
5570 OSKextExcludeLevel startOpt,
5571 OSKextExcludeLevel startMatchingOpt,
5572 OSArray * personalityNames)
5573 {
5574 OSReturn result = kOSReturnError;
5575 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5576 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5577 unsigned int i, count;
5578 Boolean alreadyLoaded = false;
5579 OSKext * lastLoadedKext = NULL; // do not release
5580
5581 if (isInExcludeList()) {
5582 OSKextLog(this,
5583 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5584 kOSKextLogLoadFlag,
5585 "Kext %s is in exclude list, not loadable",
5586 getIdentifierCString());
5587
5588 result = kOSKextReturnNotLoadable;
5589 goto finish;
5590 }
5591 if (!isLoadable()) {
5592 OSKextLog(this,
5593 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5594 kOSKextLogLoadFlag,
5595 "Kext %s is not loadable",
5596 getIdentifierCString());
5597
5598 result = kOSKextReturnNotLoadable;
5599 goto finish;
5600 }
5601
5602 if (isLoaded()) {
5603 alreadyLoaded = true;
5604 result = kOSReturnSuccess;
5605
5606 OSKextLog(this,
5607 kOSKextLogDebugLevel |
5608 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5609 "Kext %s is already loaded.",
5610 getIdentifierCString());
5611 goto loaded;
5612 }
5613
5614 #if CONFIG_MACF
5615 /*
5616 * On kxld and on embedded, only call into the MAC hook when on a
5617 * user thread, for access control over userspace kextloads.
5618 *
5619 * On non-kxld systems, additionally check the MAC hook for kexts in
5620 * the Pageable and Aux KCs, regardless of whether we are on a user
5621 * thread or not. This means on Apple silicon devices that the MAC
5622 * hook will only be useful to block 3rd party kexts loaded via
5623 * matching, and any kexts loaded from userspace kextloads.
5624 *
5625 * Note that this should _not_ be called on kexts loaded from the
5626 * kernel bootstrap thread as the kernel proc's cred struct is not
5627 * yet initialized! This won't happen on macOS because all the kexts
5628 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5629 */
5630 if (current_task() != kernel_task
5631 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
5632 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
5633 #endif
5634 ) {
5635 int macCheckResult = 0;
5636 kauth_cred_t cred = NULL;
5637
5638 cred = kauth_cred_get_with_ref();
5639 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5640 kauth_cred_unref(&cred);
5641
5642 if (macCheckResult != 0) {
5643 result = kOSReturnError;
5644 OSKextLog(this,
5645 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5646 "Failed to load kext %s (MAC policy error 0x%x).",
5647 getIdentifierCString(), macCheckResult);
5648 goto finish;
5649 }
5650 }
5651 #endif /* CONFIG_MACF */
5652
5653 if (!sLoadEnabled) {
5654 OSKextLog(this,
5655 kOSKextLogErrorLevel |
5656 kOSKextLogLoadFlag,
5657 "Kext loading is disabled (attempt to load kext %s).",
5658 getIdentifierCString());
5659 result = kOSKextReturnDisabled;
5660 goto finish;
5661 }
5662
5663 /* If we've pushed the next available load tag to the invalid value,
5664 * we can't load any more kexts.
5665 */
5666 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5667 OSKextLog(this,
5668 kOSKextLogErrorLevel |
5669 kOSKextLogLoadFlag,
5670 "Can't load kext %s - no more load tags to assign.",
5671 getIdentifierCString());
5672 result = kOSKextReturnNoResources;
5673 goto finish;
5674 }
5675
5676 /* This is a bit of a hack, because we shouldn't be handling
5677 * personalities within the load function.
5678 */
5679 if (!declaresExecutable()) {
5680 /* There is a special case where a non-executable kext can be loaded: the
5681 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5682 * load its metadata into the global data structures, if appropriate
5683 */
5684 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5685 boolean_t updated = updateExcludeList(infoDict.get());
5686 if (updated) {
5687 OSKextLog(this,
5688 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5689 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5690 }
5691 }
5692
5693 if (isDriverKit()) {
5694 if (loadTag == 0) {
5695 sLoadedDriverKitKexts->setObject(this);
5696 loadTag = sNextLoadTag++;
5697 }
5698 }
5699 result = kOSReturnSuccess;
5700 goto loaded;
5701 }
5702
5703 /* Are we in safe boot?
5704 */
5705 if (sSafeBoot && !isLoadableInSafeBoot()) {
5706 OSKextLog(this,
5707 kOSKextLogErrorLevel |
5708 kOSKextLogLoadFlag,
5709 "Can't load kext %s - not loadable during safe boot.",
5710 getIdentifierCString());
5711 result = kOSKextReturnBootLevel;
5712 goto finish;
5713 }
5714
5715 OSKextLog(this,
5716 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5717 "Loading kext %s.",
5718 getIdentifierCString());
5719
5720 #if !VM_MAPPED_KEXTS
5721 if (isPrelinked() == false) {
5722 OSKextLog(this,
5723 kOSKextLogErrorLevel |
5724 kOSKextLogLoadFlag,
5725 "Can't load kext %s - not in a kext collection.",
5726 getIdentifierCString());
5727 result = kOSKextReturnDisabled;
5728 goto finish;
5729 }
5730 #endif /* defined(__x86_64__) */
5731
5732 #if CONFIG_KXLD
5733 if (!sKxldContext) {
5734 kern_return_t kxldResult;
5735 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5736 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5737 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5738 if (kxldResult) {
5739 OSKextLog(this,
5740 kOSKextLogErrorLevel |
5741 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5742 "Can't load kext %s - failed to create link context.",
5743 getIdentifierCString());
5744 result = kOSKextReturnNoMemory;
5745 goto finish;
5746 }
5747 }
5748 #endif // CONFIG_KXLD
5749
5750 /* We only need to resolve dependencies once for the whole graph, but
5751 * resolveDependencies will just return if there's no work to do, so it's
5752 * safe to call it more than once.
5753 */
5754 if (!resolveDependencies()) {
5755 // xxx - check resolveDependencies() for log msg
5756 OSKextLog(this,
5757 kOSKextLogErrorLevel |
5758 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5759 "Can't load kext %s - failed to resolve library dependencies.",
5760 getIdentifierCString());
5761 result = kOSKextReturnDependencies;
5762 goto finish;
5763 }
5764
5765 /* If we are excluding just the kext being loaded now (and not its
5766 * dependencies), drop the exclusion level to none so dependencies
5767 * start and/or add their personalities.
5768 */
5769 if (dependenciesStartOpt == kOSKextExcludeKext) {
5770 dependenciesStartOpt = kOSKextExcludeNone;
5771 }
5772
5773 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5774 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5775 }
5776
5777 /* Load the dependencies, recursively.
5778 */
5779 count = getNumDependencies();
5780 for (i = 0; i < count; i++) {
5781 OSKext * dependency = OSDynamicCast(OSKext,
5782 dependencies->getObject(i));
5783 if (dependency == NULL) {
5784 OSKextLog(this,
5785 kOSKextLogErrorLevel |
5786 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5787 "Internal error loading kext %s; dependency disappeared.",
5788 getIdentifierCString());
5789 result = kOSKextReturnInternalError;
5790 goto finish;
5791 }
5792
5793 /* Dependencies must be started accorting to the opt,
5794 * but not given the personality names of the main kext.
5795 */
5796 result = dependency->load(dependenciesStartOpt,
5797 dependenciesStartMatchingOpt,
5798 /* personalityNames */ NULL);
5799 if (result != KERN_SUCCESS) {
5800 OSKextLog(this,
5801 kOSKextLogErrorLevel |
5802 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5803 "Dependency %s of kext %s failed to load.",
5804 dependency->getIdentifierCString(),
5805 getIdentifierCString());
5806
5807 OSKext::removeKext(dependency,
5808 /* terminateService/removePersonalities */ true);
5809 result = kOSKextReturnDependencyLoadError;
5810
5811 goto finish;
5812 }
5813 }
5814
5815 result = loadExecutable();
5816 if (result != KERN_SUCCESS) {
5817 goto finish;
5818 }
5819
5820 pendingPgoHead.next = &pendingPgoHead;
5821 pendingPgoHead.prev = &pendingPgoHead;
5822
5823 // The kernel PRNG is not initialized when the first kext is
5824 // loaded, so use early random
5825 uuid_generate_early_random(instance_uuid);
5826 account = IOMallocType(OSKextAccount);
5827
5828 account->loadTag = kmod_info->id;
5829 account->site.refcount = 0;
5830 account->site.flags = VM_TAG_KMOD;
5831
5832 #if DEVELOPMENT || DEBUG
5833 /* Setup the task reference group. */
5834 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
5835 "task_%s", getIdentifierCString());
5836 account->task_refgrp.grp_name = account->task_refgrp_name;
5837 account->task_refgrp.grp_parent = &task_external_refgrp;
5838 os_ref_log_init(&account->task_refgrp);
5839 #endif /* DEVELOPMENT || DEBUG */
5840
5841 account->kext = this;
5842 if (gIOSurfaceIdentifier == bundleID) {
5843 vm_tag_alloc(&account->site);
5844 gIOSurfaceTag = account->site.tag;
5845 }
5846
5847 flags.loaded = true;
5848
5849 /* Add the kext to the list of loaded kexts and update the kmod_info
5850 * struct to point to that of the last loaded kext (which is the way
5851 * it's always been done, though I'd rather do them in order now).
5852 */
5853 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5854 sLoadedKexts->setObject(this);
5855
5856 /* Keep the kernel itself out of the kmod list.
5857 */
5858 if (lastLoadedKext->isKernel()) {
5859 lastLoadedKext = NULL;
5860 }
5861
5862 if (lastLoadedKext) {
5863 kmod_info->next = lastLoadedKext->kmod_info;
5864 }
5865
5866 notifyKextLoadObservers(this, kmod_info);
5867
5868 /* Make the global kmod list point at the just-loaded kext. Note that the
5869 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5870 * although we do report it in kextstat these days by using the newer
5871 * OSArray of loaded kexts, which does contain it.
5872 *
5873 * (The OSKext object representing the kernel doesn't even have a kmod_info
5874 * struct, though I suppose we could stick a pointer to it from the
5875 * static struct in OSRuntime.cpp.)
5876 */
5877 kmod = kmod_info;
5878
5879 /* Save the list of loaded kexts in case we panic.
5880 */
5881 OSKext::saveLoadedKextPanicList();
5882
5883 if (isExecutable()) {
5884 OSKext::updateLoadedKextSummaries();
5885 savePanicString(/* isLoading */ true);
5886
5887 #if CONFIG_DTRACE
5888 registerWithDTrace();
5889 #else
5890 jettisonLinkeditSegment();
5891 #endif /* CONFIG_DTRACE */
5892
5893 #if !VM_MAPPED_KEXTS
5894 /* If there is a page (or more) worth of padding after the end
5895 * of the last data section but before the end of the data segment
5896 * then free it in the same manner the LinkeditSegment is freed
5897 */
5898 jettisonDATASegmentPadding();
5899 #endif
5900 }
5901
5902 loaded:
5903 if (isExecutable() && !flags.started) {
5904 if (startOpt == kOSKextExcludeNone) {
5905 result = start();
5906 if (result != kOSReturnSuccess) {
5907 OSKextLog(this,
5908 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5909 "Kext %s start failed (result 0x%x).",
5910 getIdentifierCString(), result);
5911 result = kOSKextReturnStartStopError;
5912 }
5913 }
5914 }
5915
5916 /* If not excluding matching, send the personalities to the kernel.
5917 * This never affects the result of the load operation.
5918 * This is a bit of a hack, because we shouldn't be handling
5919 * personalities within the load function.
5920 */
5921 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5922 result = sendPersonalitiesToCatalog(true, personalityNames);
5923 }
5924
5925 finish:
5926
5927 if (result != kOSReturnSuccess) {
5928 OSKextLog(this,
5929 kOSKextLogErrorLevel |
5930 kOSKextLogLoadFlag,
5931 "Kext %s failed to load (0x%x).",
5932 getIdentifierCString(), (int)result);
5933 } else if (!alreadyLoaded) {
5934 OSKextLog(this,
5935 kOSKextLogProgressLevel |
5936 kOSKextLogLoadFlag,
5937 "Kext %s loaded.",
5938 getIdentifierCString());
5939
5940 queueKextNotification(kKextRequestPredicateLoadNotification,
5941 OSDynamicCast(OSString, bundleID.get()));
5942 }
5943 return result;
5944 }
5945
5946 #if CONFIG_KXLD
5947 /*********************************************************************
5948 *
5949 *********************************************************************/
5950 static char *
strdup(const char * string)5951 strdup(const char * string)
5952 {
5953 char * result = NULL;
5954 size_t size;
5955
5956 if (!string) {
5957 goto finish;
5958 }
5959
5960 size = 1 + strlen(string);
5961 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5962 if (!result) {
5963 goto finish;
5964 }
5965
5966 memcpy(result, string, size);
5967
5968 finish:
5969 return result;
5970 }
5971 #endif // CONFIG_KXLD
5972
5973 /*********************************************************************
5974 *
5975 *********************************************************************/
5976
5977 kernel_section_t *
lookupSection(const char * segname,const char * secname)5978 OSKext::lookupSection(const char *segname, const char *secname)
5979 {
5980 kernel_section_t * found_section = NULL;
5981 kernel_mach_header_t * mh = NULL;
5982 kernel_segment_command_t * seg = NULL;
5983 kernel_section_t * sec = NULL;
5984
5985 if (!linkedExecutable) {
5986 return NULL;
5987 }
5988
5989 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5990
5991 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5992 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
5993 continue;
5994 }
5995
5996 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5997 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
5998 found_section = sec;
5999 goto out;
6000 }
6001 }
6002 }
6003
6004 out:
6005 return found_section;
6006 }
6007
6008 /*********************************************************************
6009 *
6010 *********************************************************************/
6011
6012 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6013 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6014 {
6015 OSReturn result = kOSKextReturnBadData;
6016 kernel_mach_header_t * mh = NULL;
6017 kernel_segment_command_t * seg = NULL;
6018 kernel_segment_command_t * linkeditSeg = NULL;
6019 kernel_section_t * sec = NULL;
6020 char * linkeditBase = NULL;
6021 bool haveLinkeditBase = false;
6022 char * relocBase = NULL;
6023 bool haveRelocBase = false;
6024 struct dysymtab_command * dysymtab = NULL;
6025 struct linkedit_data_command * segmentSplitInfo = NULL;
6026 struct symtab_command * symtab = NULL;
6027 kernel_nlist_t * sym = NULL;
6028 struct relocation_info * reloc = NULL;
6029 uint32_t i = 0;
6030 int reloc_size;
6031 vm_offset_t new_kextsize;
6032
6033 if (linkedExecutable == NULL || flags.builtin) {
6034 result = kOSReturnSuccess;
6035 goto finish;
6036 }
6037
6038 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6039 if (kernel_mach_header_is_in_fileset(mh)) {
6040 // kexts in filesets are slid as part of collection sliding
6041 result = kOSReturnSuccess;
6042 goto finish;
6043 }
6044
6045 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6046
6047 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6048 if (!seg->vmaddr) {
6049 continue;
6050 }
6051
6052 seg->vmaddr = ml_static_slide(seg->vmaddr);
6053
6054 #if KASLR_KEXT_DEBUG
6055 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6056 seg->segname,
6057 (unsigned long)ml_static_unslide(seg->vmaddr),
6058 (unsigned long)seg->vmaddr);
6059 #endif
6060
6061 if (!haveRelocBase) {
6062 relocBase = (char *) seg->vmaddr;
6063 haveRelocBase = true;
6064 }
6065 if (!strcmp(seg->segname, "__LINKEDIT")) {
6066 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6067 haveLinkeditBase = true;
6068 linkeditSeg = seg;
6069 }
6070 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6071 sec->addr = ml_static_slide(sec->addr);
6072
6073 #if KASLR_KEXT_DEBUG
6074 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6075 sec->sectname,
6076 (unsigned long)ml_static_unslide(sec->addr),
6077 (unsigned long)sec->addr);
6078 #endif
6079 }
6080 }
6081
6082 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6083
6084 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6085
6086 if (symtab != NULL && doCoalescedSlides == false) {
6087 /* Some pseudo-kexts have symbol tables without segments.
6088 * Ignore them. */
6089 if (symtab->nsyms > 0 && haveLinkeditBase) {
6090 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6091 for (i = 0; i < symtab->nsyms; i++) {
6092 if (sym[i].n_type & N_STAB) {
6093 continue;
6094 }
6095 sym[i].n_value = ml_static_slide(sym[i].n_value);
6096
6097 #if KASLR_KEXT_DEBUG
6098 #define MAX_SYMS_TO_LOG 5
6099 if (i < MAX_SYMS_TO_LOG) {
6100 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6101 (unsigned long)ml_static_unslide(sym[i].n_value),
6102 (unsigned long)sym[i].n_value);
6103 }
6104 #endif
6105 }
6106 }
6107 }
6108
6109 if (dysymtab != NULL && doCoalescedSlides == false) {
6110 if (dysymtab->nextrel > 0) {
6111 OSKextLog(this,
6112 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6113 kOSKextLogLinkFlag,
6114 "Sliding kext %s: External relocations found.",
6115 getIdentifierCString());
6116 goto finish;
6117 }
6118
6119 if (dysymtab->nlocrel > 0) {
6120 if (!haveLinkeditBase) {
6121 OSKextLog(this,
6122 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6123 kOSKextLogLinkFlag,
6124 "Sliding kext %s: No linkedit segment.",
6125 getIdentifierCString());
6126 goto finish;
6127 }
6128
6129 if (!haveRelocBase) {
6130 OSKextLog(this,
6131 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6132 kOSKextLogLinkFlag,
6133 #if __x86_64__
6134 "Sliding kext %s: No writable segments.",
6135 #else
6136 "Sliding kext %s: No segments.",
6137 #endif
6138 getIdentifierCString());
6139 goto finish;
6140 }
6141
6142 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6143 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6144
6145 for (i = 0; i < dysymtab->nlocrel; i++) {
6146 if (reloc[i].r_extern != 0
6147 || reloc[i].r_type != 0
6148 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6149 ) {
6150 OSKextLog(this,
6151 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6152 kOSKextLogLinkFlag,
6153 "Sliding kext %s: Unexpected relocation found.",
6154 getIdentifierCString());
6155 goto finish;
6156 }
6157 if (reloc[i].r_pcrel != 0) {
6158 continue;
6159 }
6160 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6161 *relocAddr = ml_static_slide(*relocAddr);
6162
6163 #if KASLR_KEXT_DEBUG
6164 #define MAX_DYSYMS_TO_LOG 5
6165 if (i < MAX_DYSYMS_TO_LOG) {
6166 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6167 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6168 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6169 }
6170 #endif
6171 }
6172
6173 /* We should free these relocations, not just delete the reference to them.
6174 * <rdar://problem/10535549> Free relocations from PIE kexts.
6175 *
6176 * For now, we do not free LINKEDIT for kexts with split segments.
6177 */
6178 new_kextsize = round_page(kmod_info->size - reloc_size);
6179 if (new_kextsize > UINT_MAX) {
6180 OSKextLog(this,
6181 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6182 kOSKextLogLinkFlag,
6183 "Kext %s: new kext size is too large.",
6184 getIdentifierCString());
6185 goto finish;
6186 }
6187 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6188 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6189 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6190 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6191 size_t bytes_remaining = endofkext - endofrelocInfo;
6192 OSSharedPtr<OSData> new_osdata;
6193
6194 /* fix up symbol offsets if they are after the dsymtab local relocs */
6195 if (symtab) {
6196 if (dysymtab->locreloff < symtab->symoff) {
6197 symtab->symoff -= reloc_size;
6198 }
6199 if (dysymtab->locreloff < symtab->stroff) {
6200 symtab->stroff -= reloc_size;
6201 }
6202 }
6203 if (dysymtab->locreloff < dysymtab->extreloff) {
6204 dysymtab->extreloff -= reloc_size;
6205 }
6206
6207 /* move data behind reloc info down to new offset */
6208 if (endofrelocInfo < endofkext) {
6209 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6210 }
6211
6212 /* Create a new OSData for the smaller kext object and reflect
6213 * new linkedit segment size.
6214 */
6215 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6216 linkeditSeg->filesize = linkeditSeg->vmsize;
6217
6218 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6219 if (new_osdata) {
6220 /* Fix up kmod info and linkedExecutable.
6221 */
6222 kmod_info->size = new_kextsize;
6223 #if VM_MAPPED_KEXTS
6224 new_osdata->setDeallocFunction(osdata_kext_free);
6225 #else
6226 new_osdata->setDeallocFunction(osdata_phys_free);
6227 #endif
6228 linkedExecutable->setDeallocFunction(NULL);
6229 linkedExecutable = os::move(new_osdata);
6230
6231 #if VM_MAPPED_KEXTS
6232 kext_free(new_endofkext, (endofkext - new_endofkext));
6233 #else
6234 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6235 #endif
6236 }
6237 }
6238 dysymtab->nlocrel = 0;
6239 dysymtab->locreloff = 0;
6240 }
6241 }
6242
6243 result = kOSReturnSuccess;
6244 finish:
6245 return result;
6246 }
6247
6248 /*********************************************************************
6249 * called only by load()
6250 *********************************************************************/
6251 OSReturn
loadExecutable()6252 OSKext::loadExecutable()
6253 {
6254 OSReturn result = kOSReturnError;
6255 OSSharedPtr<OSArray> linkDependencies;
6256 uint32_t num_kmod_refs = 0;
6257 OSData * theExecutable = NULL; // do not release
6258 OSString * versString = NULL; // do not release
6259 const char * versCString = NULL; // do not free
6260 const char * string = NULL; // do not free
6261
6262 #if CONFIG_KXLD
6263 unsigned int i;
6264 uint32_t numDirectDependencies = 0;
6265 kern_return_t kxldResult;
6266 KXLDDependency * kxlddeps = NULL; // must kfree
6267 uint32_t num_kxlddeps = 0;
6268 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6269 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6270 #endif // CONFIG_KXLD
6271
6272 /* We need the version string for a variety of bits below.
6273 */
6274 versString = OSDynamicCast(OSString,
6275 getPropertyForHostArch(kCFBundleVersionKey));
6276 if (!versString) {
6277 goto finish;
6278 }
6279 versCString = versString->getCStringNoCopy();
6280
6281 if (isKernelComponent()) {
6282 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6283 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6284 OSKextLog(this,
6285 kOSKextLogErrorLevel |
6286 kOSKextLogLoadFlag,
6287 "Kernel component %s has incorrect version %s; "
6288 "expected %s.",
6289 getIdentifierCString(),
6290 versCString, KERNEL6_VERSION);
6291 result = kOSKextReturnInternalError;
6292 goto finish;
6293 } else if (strcmp(versCString, osrelease)) {
6294 OSKextLog(this,
6295 kOSKextLogErrorLevel |
6296 kOSKextLogLoadFlag,
6297 "Kernel component %s has incorrect version %s; "
6298 "expected %s.",
6299 getIdentifierCString(),
6300 versCString, osrelease);
6301 result = kOSKextReturnInternalError;
6302 goto finish;
6303 }
6304 }
6305 }
6306
6307 #if defined(__x86_64__) || defined(__i386__)
6308 if (flags.resetSegmentsFromVnode) {
6309 /* Fixup the chains and slide the mach headers */
6310 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6311
6312 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6313 result = kOSKextReturnValidation;
6314 goto finish;
6315 }
6316 }
6317 #endif //(__x86_64__) || defined(__i386__)
6318
6319 if (isPrelinked()) {
6320 goto register_kmod;
6321 }
6322
6323 /* <rdar://problem/21444003> all callers must be entitled */
6324 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
6325 OSKextLog(this,
6326 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6327 "Not entitled to link kext '%s'",
6328 getIdentifierCString());
6329 result = kOSKextReturnNotPrivileged;
6330 goto finish;
6331 }
6332
6333 theExecutable = getExecutable();
6334 if (!theExecutable) {
6335 if (declaresExecutable()) {
6336 OSKextLog(this,
6337 kOSKextLogErrorLevel |
6338 kOSKextLogLoadFlag,
6339 "Can't load kext %s - executable is missing.",
6340 getIdentifierCString());
6341 result = kOSKextReturnValidation;
6342 goto finish;
6343 }
6344 goto register_kmod;
6345 }
6346
6347 if (isInterface()) {
6348 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6349 if (executableCopy) {
6350 setLinkedExecutable(executableCopy.get());
6351 }
6352 goto register_kmod;
6353 }
6354
6355 #if CONFIG_KXLD
6356 numDirectDependencies = getNumDependencies();
6357
6358 if (flags.hasBleedthrough) {
6359 linkDependencies = dependencies;
6360 } else {
6361 linkDependencies = OSArray::withArray(dependencies.get());
6362 if (!linkDependencies) {
6363 OSKextLog(this,
6364 kOSKextLogErrorLevel |
6365 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6366 "Can't allocate link dependencies to load kext %s.",
6367 getIdentifierCString());
6368 goto finish;
6369 }
6370
6371 for (i = 0; i < numDirectDependencies; ++i) {
6372 OSKext * dependencyKext = OSDynamicCast(OSKext,
6373 dependencies->getObject(i));
6374 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
6375 }
6376 }
6377
6378 num_kxlddeps = linkDependencies->getCount();
6379 if (!num_kxlddeps) {
6380 OSKextLog(this,
6381 kOSKextLogErrorLevel |
6382 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6383 "Can't load kext %s - it has no library dependencies.",
6384 getIdentifierCString());
6385 goto finish;
6386 }
6387
6388 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6389 if (!kxlddeps) {
6390 OSKextLog(this,
6391 kOSKextLogErrorLevel |
6392 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6393 "Can't allocate link context to load kext %s.",
6394 getIdentifierCString());
6395 goto finish;
6396 }
6397 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6398
6399 for (i = 0; i < num_kxlddeps; ++i) {
6400 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6401
6402 if (dependency->isInterface()) {
6403 OSKext *interfaceTargetKext = NULL; //do not release
6404 OSData * interfaceTarget = NULL; //do not release
6405
6406 if (dependency->isKernelComponent()) {
6407 interfaceTargetKext = sKernelKext;
6408 interfaceTarget = sKernelKext->linkedExecutable.get();
6409 } else {
6410 interfaceTargetKext = OSDynamicCast(OSKext,
6411 dependency->dependencies->getObject(0));
6412
6413 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
6414 }
6415
6416 if (!interfaceTarget) {
6417 // panic?
6418 goto finish;
6419 }
6420
6421 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6422 * it will be useful to have them in the debugger.
6423 * strdup() failing isn't critical right here so we don't check that.
6424 */
6425 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6426 kxlddeps[i].kext_size = interfaceTarget->getLength();
6427 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6428
6429 if (dependency->linkedExecutable != NULL) {
6430 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6431 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6432 } else {
6433 kxlddeps[i].interface = (u_char *) NULL;
6434 kxlddeps[i].interface_size = 0;
6435 }
6436 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6437 } else {
6438 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6439 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6440 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6441 }
6442
6443 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6444 }
6445
6446 kxldHeaderPtr = &kxld_header;
6447
6448 #if DEBUG
6449 OSKextLog(this,
6450 kOSKextLogExplicitLevel |
6451 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6452 "Kext %s - calling kxld_link_file:\n"
6453 " kxld_context: %p\n"
6454 " executable: %p executable_length: %d\n"
6455 " user_data: %p\n"
6456 " kxld_dependencies: %p num_dependencies: %d\n"
6457 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6458 getIdentifierCString(), sKxldContext,
6459 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6460 this, kxlddeps, num_kxlddeps,
6461 kxldHeaderPtr, &kmod_info);
6462 #endif
6463
6464 /* After this call, the linkedExecutable instance variable
6465 * should exist.
6466 */
6467 kxldResult = kxld_link_file(sKxldContext,
6468 (u_char *)theExecutable->getBytesNoCopy(),
6469 theExecutable->getLength(),
6470 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6471 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6472
6473 if (kxldResult != KERN_SUCCESS) {
6474 // xxx - add kxldResult here?
6475 OSKextLog(this,
6476 kOSKextLogErrorLevel |
6477 kOSKextLogLoadFlag,
6478 "Can't load kext %s - link failed.",
6479 getIdentifierCString());
6480 result = kOSKextReturnLinkError;
6481 goto finish;
6482 }
6483
6484 /* We've written data & instructions into kernel memory, so flush the data
6485 * cache and invalidate the instruction cache.
6486 * I/D caches are coherent on x86
6487 */
6488 #if !defined(__i386__) && !defined(__x86_64__)
6489 flush_dcache(kmod_info->address, kmod_info->size, false);
6490 invalidate_icache(kmod_info->address, kmod_info->size, false);
6491 #endif
6492
6493 #else // !CONFIG_KXLD
6494 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6495 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6496 result = kOSKextReturnLinkError;
6497 goto finish;
6498 #endif // CONFIG_KXLD
6499
6500 register_kmod:
6501
6502 if (isInterface()) {
6503 /* Whip up a fake kmod_info entry for the interface kext.
6504 */
6505 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
6506 if (!kmod_info) {
6507 result = KERN_MEMORY_ERROR;
6508 goto finish;
6509 }
6510
6511 /* A pseudokext has almost nothing in its kmod_info struct.
6512 */
6513 kmod_info->info_version = KMOD_INFO_VERSION;
6514
6515 /* An interface kext doesn't have a linkedExecutable, so save a
6516 * copy of the UUID out of the original executable via copyUUID()
6517 * while we still have the original executable.
6518 */
6519 interfaceUUID = copyUUID();
6520 }
6521
6522 kmod_info->id = loadTag = sNextLoadTag++;
6523 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
6524
6525 /* Stamp the bundle ID and version from the OSKext over anything
6526 * resident inside the kmod_info.
6527 */
6528 string = getIdentifierCString();
6529 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6530
6531 string = versCString;
6532 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6533
6534 /* Add the dependencies' kmod_info structs as kmod_references.
6535 */
6536 num_kmod_refs = getNumDependencies();
6537 if (num_kmod_refs) {
6538 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
6539 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
6540 if (!kmod_info->reference_list) {
6541 result = KERN_MEMORY_ERROR;
6542 goto finish;
6543 }
6544 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6545 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6546 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6547 ref->info = refKext->kmod_info;
6548 ref->info->reference_count++;
6549
6550 if (refIndex + 1 < num_kmod_refs) {
6551 ref->next = kmod_info->reference_list + refIndex + 1;
6552 }
6553 }
6554 }
6555
6556 if (kmod_info->hdr_size > UINT32_MAX) {
6557 OSKextLog(this,
6558 kOSKextLogErrorLevel |
6559 kOSKextLogLoadFlag,
6560 #if __LP64__
6561 "Kext %s header size is too large (%lu > UINT32_MAX).",
6562 #else
6563 "Kext %s header size is too large (%u > UINT32_MAX).",
6564 #endif
6565 kmod_info->name,
6566 kmod_info->hdr_size);
6567 result = KERN_FAILURE;
6568 goto finish;
6569 }
6570
6571 if (kmod_info->size > UINT32_MAX) {
6572 OSKextLog(this,
6573 kOSKextLogErrorLevel |
6574 kOSKextLogLoadFlag,
6575 #if __LP64__
6576 "Kext %s size is too large (%lu > UINT32_MAX).",
6577 #else
6578 "Kext %s size is too large (%u > UINT32_MAX).",
6579 #endif
6580 kmod_info->name,
6581 kmod_info->size);
6582 result = KERN_FAILURE;
6583 goto finish;
6584 }
6585
6586 if (!isInterface() && linkedExecutable) {
6587 OSKextLog(this,
6588 kOSKextLogProgressLevel |
6589 kOSKextLogLoadFlag,
6590 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6591 kmod_info->name,
6592 (unsigned)kmod_info->size / PAGE_SIZE,
6593 (unsigned long)ml_static_unslide(kmod_info->address),
6594 (unsigned)kmod_info->id);
6595 }
6596
6597 /* VM protections and wiring for the Aux KC are done at collection loading time */
6598 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6599 /* if prelinked and primary KC, VM protections are already set */
6600 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6601 if (result != KERN_SUCCESS) {
6602 goto finish;
6603 }
6604 }
6605
6606 #if KASAN
6607 if (linkedExecutable) {
6608 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6609 linkedExecutable->getLength(), getIdentifierCString());
6610 }
6611 #else
6612 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6613 OSKextLog(this,
6614 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6615 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6616 getIdentifierCString()
6617 );
6618 result = KERN_FAILURE;
6619 goto finish;
6620 }
6621 #endif
6622
6623 result = kOSReturnSuccess;
6624
6625 finish:
6626
6627 #if CONFIG_KXLD
6628 /* Clear up locally allocated dependency info.
6629 */
6630 for (i = 0; i < num_kxlddeps; ++i) {
6631 size_t size;
6632
6633 if (kxlddeps[i].kext_name) {
6634 size = 1 + strlen(kxlddeps[i].kext_name);
6635 kfree_data(kxlddeps[i].kext_name, size);
6636 }
6637 if (kxlddeps[i].interface_name) {
6638 size = 1 + strlen(kxlddeps[i].interface_name);
6639 kfree_data(kxlddeps[i].interface_name, size);
6640 }
6641 }
6642 if (kxlddeps) {
6643 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
6644 }
6645 #endif // CONFIG_KXLD
6646
6647 /* We no longer need the unrelocated executable (which the linker
6648 * has altered anyhow).
6649 */
6650 setExecutable(NULL);
6651
6652 if (result != kOSReturnSuccess) {
6653 OSKextLog(this,
6654 kOSKextLogErrorLevel |
6655 kOSKextLogLoadFlag,
6656 "Failed to load executable for kext %s.",
6657 getIdentifierCString());
6658
6659 if (kmod_info && kmod_info->reference_list) {
6660 kfree_type(kmod_reference_t, num_kmod_refs,
6661 kmod_info->reference_list);
6662 }
6663 if (isInterface()) {
6664 kfree_type(kmod_info_t, kmod_info);
6665 kmod_info = NULL;
6666 }
6667 if (kc_type == KCKindUnknown) {
6668 kmod_info = NULL;
6669 if (linkedExecutable) {
6670 linkedExecutable.reset();
6671 }
6672 }
6673 }
6674
6675 return result;
6676 }
6677
6678 /* static */
6679 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)6680 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6681 {
6682 kernel_segment_command_t *linkeditseg = NULL;
6683
6684 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6685 if (linkeditseg == NULL) {
6686 panic("FileSet booted with no Linkedit segment");
6687 }
6688
6689 #if VM_MAPPED_KEXTS
6690 /* BootKC on x86_64 is not vm mapped */
6691 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6692
6693 OSKextLog(/* kext */ NULL,
6694 kOSKextLogProgressLevel |
6695 kOSKextLogGeneralFlag,
6696 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6697 linkeditseg->vmaddr, linkeditseg->vmsize);
6698 #else
6699 /* BootKC on arm64 is not vm mapped, but is slid */
6700 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
6701
6702 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
6703
6704 OSKextLog(/* kext */ NULL,
6705 kOSKextLogProgressLevel |
6706 kOSKextLogGeneralFlag,
6707 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6708 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
6709 #endif /* VM_MAPPED_KEXTS */
6710 }
6711
6712 /*********************************************************************
6713 * The linkedit segment is used by the kext linker for dependency
6714 * resolution, and by dtrace for probe initialization. We can free it
6715 * for non-library kexts, since no kexts depend on non-library kexts
6716 * by definition, once dtrace has been initialized.
6717 *********************************************************************/
6718 void
jettisonLinkeditSegment(void)6719 OSKext::jettisonLinkeditSegment(void)
6720 {
6721 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6722 kernel_segment_command_t * linkedit = NULL;
6723 vm_offset_t start;
6724 vm_size_t linkeditsize, kextsize;
6725 OSSharedPtr<OSData> data;
6726
6727 if (isInFileset()) {
6728 return;
6729 }
6730
6731 #if NO_KEXTD
6732 /* We can free symbol tables for all embedded kexts because we don't
6733 * support runtime kext linking.
6734 */
6735 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6736 #else
6737 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6738 #endif
6739 goto finish;
6740 }
6741
6742 /* Find the linkedit segment. If it's not the last segment, then freeing
6743 * it will fragment the kext into multiple VM regions, which OSKext is not
6744 * designed to handle, so we'll have to skip it.
6745 */
6746 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6747 if (!linkedit) {
6748 goto finish;
6749 }
6750
6751 if (round_page(kmod_info->address + kmod_info->size) !=
6752 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6753 goto finish;
6754 }
6755
6756 /* Create a new OSData for the smaller kext object.
6757 */
6758 linkeditsize = round_page(linkedit->vmsize);
6759 kextsize = kmod_info->size - linkeditsize;
6760 start = linkedit->vmaddr;
6761
6762 if (kextsize > UINT_MAX) {
6763 goto finish;
6764 }
6765 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6766 if (!data) {
6767 goto finish;
6768 }
6769
6770 /* Fix the kmod info and linkedExecutable.
6771 */
6772 kmod_info->size = kextsize;
6773
6774 #if VM_MAPPED_KEXTS
6775 data->setDeallocFunction(osdata_kext_free);
6776 #else
6777 data->setDeallocFunction(osdata_phys_free);
6778 #endif
6779 linkedExecutable->setDeallocFunction(NULL);
6780 linkedExecutable = os::move(data);
6781 flags.jettisonLinkeditSeg = 1;
6782
6783 /* Free the linkedit segment.
6784 */
6785 #if VM_MAPPED_KEXTS
6786 kext_free(start, linkeditsize);
6787 #else
6788 ml_static_mfree(start, linkeditsize);
6789 #endif
6790
6791 finish:
6792 return;
6793 }
6794
6795 /*********************************************************************
6796 * If there are whole pages that are unused betweem the last section
6797 * of the DATA segment and the end of the DATA segment then we can free
6798 * them
6799 *********************************************************************/
6800 void
6801 OSKext::jettisonDATASegmentPadding(void)
6802 {
6803 kernel_mach_header_t * mh;
6804 kernel_segment_command_t * dataSeg;
6805 kernel_section_t * sec, * lastSec;
6806 vm_offset_t dataSegEnd, lastSecEnd;
6807 vm_size_t padSize;
6808
6809 if (flags.builtin) {
6810 return;
6811 }
6812 mh = (kernel_mach_header_t *)kmod_info->address;
6813
6814 if (isInFileset()) {
6815 return;
6816 }
6817
6818 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6819 if (dataSeg == NULL) {
6820 return;
6821 }
6822
6823 lastSec = NULL;
6824 sec = firstsect(dataSeg);
6825 while (sec != NULL) {
6826 lastSec = sec;
6827 sec = nextsect(dataSeg, sec);
6828 }
6829
6830 if (lastSec == NULL) {
6831 return;
6832 }
6833
6834 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6835 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6836 return;
6837 }
6838
6839 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6840 lastSecEnd = round_page(lastSec->addr + lastSec->size);
6841
6842 if (dataSegEnd <= lastSecEnd) {
6843 return;
6844 }
6845
6846 padSize = dataSegEnd - lastSecEnd;
6847
6848 if (padSize >= PAGE_SIZE) {
6849 #if VM_MAPPED_KEXTS
6850 kext_free(lastSecEnd, padSize);
6851 #else
6852 ml_static_mfree(lastSecEnd, padSize);
6853 #endif
6854 }
6855 }
6856
6857 /*********************************************************************
6858 *********************************************************************/
6859 void
6860 OSKext::setLinkedExecutable(OSData * anExecutable)
6861 {
6862 if (linkedExecutable) {
6863 panic("Attempt to set linked executable on kext "
6864 "that already has one (%s).\n",
6865 getIdentifierCString());
6866 }
6867 linkedExecutable.reset(anExecutable, OSRetain);
6868 return;
6869 }
6870
6871 #if CONFIG_DTRACE
6872 /*********************************************************************
6873 * Go through all loaded kexts and tell them to register with dtrace.
6874 * The instance method only registers if necessary.
6875 *********************************************************************/
6876 /* static */
6877 void
6878 OSKext::registerKextsWithDTrace(void)
6879 {
6880 uint32_t count = sLoadedKexts->getCount();
6881 uint32_t i;
6882
6883 IORecursiveLockLock(sKextLock);
6884
6885 for (i = 0; i < count; i++) {
6886 OSKext * thisKext = NULL; // do not release
6887
6888 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6889 if (!thisKext || !thisKext->isExecutable()) {
6890 continue;
6891 }
6892
6893 thisKext->registerWithDTrace();
6894 }
6895
6896 IORecursiveLockUnlock(sKextLock);
6897
6898 return;
6899 }
6900
6901 extern "C" {
6902 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6903 extern int (*dtrace_modunload)(struct kmod_info *);
6904 };
6905
6906 /*********************************************************************
6907 *********************************************************************/
6908 void
6909 OSKext::registerWithDTrace(void)
6910 {
6911 /* Register kext with dtrace. A dtrace_modload failure should not
6912 * prevent a kext from loading, so we ignore the return code.
6913 */
6914 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6915 uint32_t modflag = 0;
6916 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
6917
6918 #if XNU_TARGET_OS_OSX
6919 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6920 if (forceInit == kOSBooleanTrue) {
6921 OSKextLog(this,
6922 kOSKextLogBasicLevel |
6923 kOSKextLogGeneralFlag,
6924 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
6925 getIdentifierCString());
6926 forceInit = kOSBooleanFalse;
6927 }
6928 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6929 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6930 }
6931 #endif /* XNU_TARGET_OS_OSX */
6932 if (forceInit == kOSBooleanTrue) {
6933 modflag |= KMOD_DTRACE_FORCE_INIT;
6934 }
6935 if (flags.builtin) {
6936 modflag |= KMOD_DTRACE_STATIC_KEXT;
6937 }
6938
6939 (void)(*dtrace_modload)(kmod_info, modflag);
6940 flags.dtraceInitialized = true;
6941 jettisonLinkeditSegment();
6942 }
6943 return;
6944 }
6945 /*********************************************************************
6946 *********************************************************************/
6947 void
6948 OSKext::unregisterWithDTrace(void)
6949 {
6950 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6951 * prevent a kext from loading, so we ignore the return code.
6952 */
6953 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6954 (void)(*dtrace_modunload)(kmod_info);
6955 flags.dtraceInitialized = false;
6956 }
6957 return;
6958 }
6959 #endif /* CONFIG_DTRACE */
6960
6961
6962 /*********************************************************************
6963 * called only by loadExecutable()
6964 *********************************************************************/
6965 #if !VM_MAPPED_KEXTS
6966 #if defined(__arm__) || defined(__arm64__)
6967 static inline kern_return_t
6968 OSKext_protect(
6969 kernel_mach_header_t *kext_mh,
6970 vm_map_t map,
6971 vm_map_offset_t start,
6972 vm_map_offset_t end,
6973 vm_prot_t new_prot,
6974 boolean_t set_max,
6975 kc_kind_t kc_type)
6976 {
6977 #pragma unused(kext_mh,map,kc_type)
6978 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
6979 assert(start <= end);
6980 if (start >= end) {
6981 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6982 } else if (set_max) {
6983 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
6984 } else {
6985 return ml_static_protect(start, end - start, new_prot);
6986 }
6987 }
6988
6989 static inline kern_return_t
6990 OSKext_wire(
6991 kernel_mach_header_t *kext_mh,
6992 vm_map_t map,
6993 vm_map_offset_t start,
6994 vm_map_offset_t end,
6995 vm_prot_t access_type,
6996 boolean_t user_wire,
6997 kc_kind_t kc_type)
6998 {
6999 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7000 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7001 }
7002 #else
7003 #error Unrecognized architecture
7004 #endif
7005 #else
7006 static inline kern_return_t
7007 OSKext_protect(
7008 kernel_mach_header_t *kext_mh,
7009 vm_map_t map,
7010 vm_map_offset_t start,
7011 vm_map_offset_t end,
7012 vm_prot_t new_prot,
7013 boolean_t set_max,
7014 kc_kind_t kc_type)
7015 {
7016 if (start == end) { // 10538581
7017 return KERN_SUCCESS;
7018 }
7019 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7020 /*
7021 * XXX: This will probably need to be different for AuxKC and
7022 * pageableKC!
7023 */
7024 return ml_static_protect(start, end - start, new_prot);
7025 }
7026 return vm_map_protect(map, start, end, new_prot, set_max);
7027 }
7028
7029 static inline kern_return_t
7030 OSKext_wire(
7031 kernel_mach_header_t *kext_mh,
7032 vm_map_t map,
7033 vm_map_offset_t start,
7034 vm_map_offset_t end,
7035 vm_prot_t access_type,
7036 boolean_t user_wire,
7037 kc_kind_t kc_type)
7038 {
7039 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7040 /* TODO: we may need to hook this for the pageableKC */
7041 return KERN_SUCCESS;
7042 }
7043 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7044 }
7045 #endif
7046
7047 OSReturn
7048 OSKext::setVMAttributes(bool protect, bool wire)
7049 {
7050 vm_map_t kext_map = NULL;
7051 kernel_segment_command_t * seg = NULL;
7052 vm_map_offset_t start_protect = 0;
7053 vm_map_offset_t start_wire = 0;
7054 vm_map_offset_t end_protect = 0;
7055 vm_map_offset_t end_wire = 0;
7056 OSReturn result = kOSReturnError;
7057
7058 if (isInterface() || !declaresExecutable() || flags.builtin) {
7059 result = kOSReturnSuccess;
7060 goto finish;
7061 }
7062
7063 /* Get the kext's vm map */
7064 kext_map = kext_get_vm_map(kmod_info);
7065 if (!kext_map) {
7066 result = KERN_MEMORY_ERROR;
7067 goto finish;
7068 }
7069
7070 #if !VM_MAPPED_KEXTS
7071 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7072 /* This is a split kext in a prelinked kernelcache; we'll let the
7073 * platform code take care of protecting it. It is already wired.
7074 */
7075 /* TODO: Should this still allow protections for the first segment
7076 * to go through, in the event that we have a mix of split and
7077 * unsplit kexts?
7078 */
7079 result = KERN_SUCCESS;
7080 goto finish;
7081 }
7082
7083 if (isInFileset() && kc_type != KCKindPageable) {
7084 // kexts in filesets have protections setup as part of collection loading
7085 result = KERN_SUCCESS;
7086 goto finish;
7087 }
7088 #endif
7089
7090 /* Protect the headers as read-only; they do not need to be wired */
7091 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7092 kext_map, kmod_info->address,
7093 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7094 : KERN_SUCCESS;
7095 if (result != KERN_SUCCESS) {
7096 goto finish;
7097 }
7098
7099 /* Set the VM protections and wire down each of the segments */
7100 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7101 while (seg) {
7102 #if __arm__
7103 /* We build all ARM kexts, so we can ensure they are aligned */
7104 assert((seg->vmaddr & PAGE_MASK) == 0);
7105 assert((seg->vmsize & PAGE_MASK) == 0);
7106 #endif
7107
7108 /*
7109 * For the non page aligned segments, the range calculation for protection
7110 * and wiring differ as follows:
7111 *
7112 * Protection: The non page aligned data at the start or at the end of the
7113 * segment is excluded from the protection. This exclusion is needed to make
7114 * sure OSKext_protect is not called twice on same page, if the page is shared
7115 * between two segments.
7116 *
7117 * Wiring: The non page aligned data at the start or at the end of the
7118 * segment is included in the wiring range, this inclusion is needed to make sure
7119 * all the data of the segment is wired.
7120 */
7121 start_protect = round_page(seg->vmaddr);
7122 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7123
7124 start_wire = trunc_page(seg->vmaddr);
7125 end_wire = round_page(seg->vmaddr + seg->vmsize);
7126
7127 /*
7128 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7129 * across kexts and data from kexts is not page aligned
7130 */
7131 if (protect && (end_protect > start_protect) &&
7132 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7133 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7134 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7135 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7136 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7137 if (result != KERN_SUCCESS) {
7138 OSKextLog(this,
7139 kOSKextLogErrorLevel |
7140 kOSKextLogLoadFlag,
7141 "Kext %s failed to set maximum VM protections "
7142 "for segment %s - 0x%x.",
7143 getIdentifierCString(), seg->segname, (int)result);
7144 goto finish;
7145 }
7146
7147 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7148 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7149 if (result != KERN_SUCCESS) {
7150 OSKextLog(this,
7151 kOSKextLogErrorLevel |
7152 kOSKextLogLoadFlag,
7153 "Kext %s failed to set initial VM protections "
7154 "for segment %s - 0x%x.",
7155 getIdentifierCString(), seg->segname, (int)result);
7156 goto finish;
7157 }
7158 }
7159
7160 if (segmentShouldBeWired(seg) && wire) {
7161 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7162 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7163 if (result != KERN_SUCCESS) {
7164 goto finish;
7165 }
7166 }
7167
7168 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7169 }
7170
7171 finish:
7172 return result;
7173 }
7174
7175 /*********************************************************************
7176 *********************************************************************/
7177 boolean_t
7178 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7179 {
7180 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7181 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7182 }
7183
7184 /*********************************************************************
7185 *********************************************************************/
7186 OSReturn
7187 OSKext::validateKextMapping(bool startFlag)
7188 {
7189 OSReturn result = kOSReturnError;
7190 const char * whichOp = startFlag ? "start" : "stop";
7191 kern_return_t kern_result = 0;
7192 vm_map_t kext_map = NULL;
7193 kernel_segment_command_t * seg = NULL;
7194 mach_vm_address_t address = 0;
7195 mach_vm_size_t size = 0;
7196 uint32_t depth = 0;
7197 uint64_t kext_segbase = 0;
7198 uint64_t kext_segsize = 0;
7199 mach_msg_type_number_t count;
7200 vm_region_submap_short_info_data_64_t info;
7201 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7202
7203 if (flags.builtin) {
7204 return kOSReturnSuccess;
7205 }
7206
7207 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7208 bzero(&info, sizeof(info));
7209
7210 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7211 // xxx - sufficient?
7212
7213 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7214 */
7215 if (!kmod_info) {
7216 OSKextLog(this,
7217 kOSKextLogErrorLevel |
7218 kOSKextLogLoadFlag,
7219 "Kext %s - NULL kmod_info pointer.",
7220 getIdentifierCString());
7221 result = kOSKextReturnBadData;
7222 goto finish;
7223 }
7224
7225 if (startFlag) {
7226 address = (mach_vm_address_t)kmod_info->start;
7227 } else {
7228 address = (mach_vm_address_t)kmod_info->stop;
7229 }
7230
7231 if (!address) {
7232 OSKextLog(this,
7233 kOSKextLogErrorLevel |
7234 kOSKextLogLoadFlag,
7235 "Kext %s - NULL module %s pointer.",
7236 getIdentifierCString(), whichOp);
7237 result = kOSKextReturnBadData;
7238 goto finish;
7239 }
7240
7241 kext_map = kext_get_vm_map(kmod_info);
7242 depth = (kernel_map == kext_map) ? 1 : 2;
7243 if (isInFileset()) {
7244 #if defined(HAS_APPLE_PAC)
7245 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7246 #endif /* defined(HAS_APPLE_PAC) */
7247 }
7248
7249 /* Verify that the start/stop function lies within the kext's address range.
7250 */
7251 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7252 isInFileset()) {
7253 /* This will likely be how we deal with split kexts; walk the segments to
7254 * check that the function lies inside one of the segments of this kext.
7255 */
7256 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7257 seg != NULL;
7258 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7259 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7260 kext_segbase = seg->vmaddr;
7261 kext_segsize = seg->vmsize;
7262 break;
7263 }
7264 }
7265
7266 if (!seg) {
7267 OSKextLog(this,
7268 kOSKextLogErrorLevel |
7269 kOSKextLogLoadFlag,
7270 "Kext %s module %s pointer is outside of kext range "
7271 "(%s %p - kext starts at %p).",
7272 getIdentifierCString(),
7273 whichOp,
7274 whichOp,
7275 (void *)(((uintptr_t)address) - kext_slide),
7276 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7277 result = kOSKextReturnBadData;
7278 goto finish;
7279 }
7280
7281 seg = NULL;
7282 } else {
7283 if (address < kmod_info->address + kmod_info->hdr_size ||
7284 kmod_info->address + kmod_info->size <= address) {
7285 OSKextLog(this,
7286 kOSKextLogErrorLevel |
7287 kOSKextLogLoadFlag,
7288 "Kext %s module %s pointer is outside of kext range "
7289 "(%s %p - kext at %p-%p).",
7290 getIdentifierCString(),
7291 whichOp,
7292 whichOp,
7293 (void *)(((uintptr_t)address) - kext_slide),
7294 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7295 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7296 result = kOSKextReturnBadData;
7297 goto finish;
7298 }
7299 }
7300
7301 /* Only do these checks before calling the start function;
7302 * If anything goes wrong with the mapping while the kext is running,
7303 * we'll likely have panicked well before any attempt to stop the kext.
7304 */
7305 if (startFlag) {
7306 if (!isInFileset() || kc_type != KCKindPrimary) {
7307 /*
7308 * Verify that the start/stop function is executable.
7309 */
7310 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7311 (vm_region_recurse_info_t)&info, &count);
7312 if (kern_result != KERN_SUCCESS) {
7313 OSKextLog(this,
7314 kOSKextLogErrorLevel |
7315 kOSKextLogLoadFlag,
7316 "Kext %s - bad %s pointer %p.",
7317 getIdentifierCString(),
7318 whichOp, (void *)ml_static_unslide(address));
7319 result = kOSKextReturnBadData;
7320 goto finish;
7321 }
7322 } else {
7323 /*
7324 * Since kexts loaded from the primary KC are held in memory
7325 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7326 * discover that memory's protection flags. Instead, we need to
7327 * get that information from the kernel pmap itself. Above, we
7328 * (potentially) saved the size of the segment in which the address
7329 * in question was located. If we have a non-zero size, verify
7330 * that all pages in the (address, address + kext_segsize) range
7331 * are marked executable. If we somehow did not record the size
7332 * (or the base) just verify the single page that includes the address.
7333 */
7334 if (kext_segbase == 0 || kext_segsize == 0) {
7335 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7336 kext_segsize = PAGE_SIZE;
7337 }
7338 }
7339
7340 #if VM_MAPPED_KEXTS
7341 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7342 ((isInFileset() && kc_type == KCKindPrimary) &&
7343 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
7344 OSKextLog(this,
7345 kOSKextLogErrorLevel |
7346 kOSKextLogLoadFlag,
7347 "Kext %s - memory region containing module %s function "
7348 "is not executable.",
7349 getIdentifierCString(), whichOp);
7350 result = kOSKextReturnBadData;
7351 goto finish;
7352 }
7353 #endif
7354
7355 /* Verify that the kext's segments are backed by physical memory.
7356 */
7357 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7358 while (seg) {
7359 if (!verifySegmentMapping(seg)) {
7360 result = kOSKextReturnBadData;
7361 goto finish;
7362 }
7363
7364 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7365 }
7366 }
7367
7368 result = kOSReturnSuccess;
7369 finish:
7370 return result;
7371 }
7372
7373 /*********************************************************************
7374 *********************************************************************/
7375 boolean_t
7376 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7377 {
7378 mach_vm_address_t address = 0;
7379
7380 if (seg->vmsize > UINT32_MAX) {
7381 return false;
7382 }
7383
7384 if (!segmentShouldBeWired(seg)) {
7385 return true;
7386 }
7387
7388 for (address = seg->vmaddr;
7389 address < round_page(seg->vmaddr + seg->vmsize);
7390 address += PAGE_SIZE) {
7391 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7392 OSKextLog(this,
7393 kOSKextLogErrorLevel |
7394 kOSKextLogLoadFlag,
7395 "Kext %s - page %p is not backed by physical memory.",
7396 getIdentifierCString(),
7397 (void *)address);
7398 return false;
7399 }
7400 }
7401
7402 return true;
7403 }
7404
7405 /*********************************************************************
7406 *********************************************************************/
7407 static void
7408 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7409 {
7410 uint64_t stamp = 0;
7411 firehose_tracepoint_id_u trace_id;
7412 struct firehose_trace_uuid_info_s uuid_info_s;
7413 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7414 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
7415 OSSharedPtr<OSData> uuid_data;
7416
7417 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7418 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
7419
7420 uuid_data = aKext->copyTextUUID();
7421 if (uuid_data) {
7422 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
7423 }
7424
7425 uuid_info->ftui_size = size;
7426 if (aKext->isDriverKit()) {
7427 uuid_info->ftui_address = address;
7428 } else {
7429 uuid_info->ftui_address = ml_static_unslide(address);
7430 }
7431 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7432 return;
7433 }
7434
7435 void
7436 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7437 {
7438 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7439 }
7440
7441 /*********************************************************************
7442 *********************************************************************/
7443 OSReturn
7444 OSKext::start(bool startDependenciesFlag)
7445 {
7446 OSReturn result = kOSReturnError;
7447 kern_return_t (* startfunc)(kmod_info_t *, void *);
7448 unsigned int i, count;
7449 void * kmodStartData = NULL;
7450
7451 if (isStarted() || isInterface() || isKernelComponent()) {
7452 result = kOSReturnSuccess;
7453 goto finish;
7454 }
7455
7456 if (!isLoaded()) {
7457 OSKextLog(this,
7458 kOSKextLogErrorLevel |
7459 kOSKextLogLoadFlag,
7460 "Attempt to start nonloaded kext %s.",
7461 getIdentifierCString());
7462 result = kOSKextReturnInvalidArgument;
7463 goto finish;
7464 }
7465
7466 if (!sLoadEnabled) {
7467 OSKextLog(this,
7468 kOSKextLogErrorLevel |
7469 kOSKextLogLoadFlag,
7470 "Kext loading is disabled (attempt to start kext %s).",
7471 getIdentifierCString());
7472 result = kOSKextReturnDisabled;
7473 goto finish;
7474 }
7475
7476 result = validateKextMapping(/* start? */ true);
7477 if (result != kOSReturnSuccess) {
7478 goto finish;
7479 }
7480
7481 startfunc = kmod_info->start;
7482
7483 count = getNumDependencies();
7484 for (i = 0; i < count; i++) {
7485 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7486 if (dependency == NULL) {
7487 OSKextLog(this,
7488 kOSKextLogErrorLevel |
7489 kOSKextLogLoadFlag,
7490 "Kext %s start - internal error, dependency disappeared.",
7491 getIdentifierCString());
7492 goto finish;
7493 }
7494 if (!dependency->isStarted()) {
7495 if (startDependenciesFlag) {
7496 OSReturn dependencyResult =
7497 dependency->start(startDependenciesFlag);
7498 if (dependencyResult != KERN_SUCCESS) {
7499 OSKextLog(this,
7500 kOSKextLogErrorLevel |
7501 kOSKextLogLoadFlag,
7502 "Kext %s start - dependency %s failed to start (error 0x%x).",
7503 getIdentifierCString(),
7504 dependency->getIdentifierCString(),
7505 dependencyResult);
7506 goto finish;
7507 }
7508 } else {
7509 OSKextLog(this,
7510 kOSKextLogErrorLevel |
7511 kOSKextLogLoadFlag,
7512 "Not starting %s - dependency %s not started yet.",
7513 getIdentifierCString(),
7514 dependency->getIdentifierCString());
7515 result = kOSKextReturnStartStopError; // xxx - make new return?
7516 goto finish;
7517 }
7518 }
7519 }
7520
7521 OSKextLog(this,
7522 kOSKextLogDetailLevel |
7523 kOSKextLogLoadFlag,
7524 "Kext %s calling module start function.",
7525 getIdentifierCString());
7526
7527 flags.starting = 1;
7528
7529 // Drop a log message so logd can grab the needed information to decode this kext
7530 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7531 result = OSRuntimeInitializeCPP(this);
7532 if (result == KERN_SUCCESS) {
7533 result = startfunc(kmod_info, kmodStartData);
7534 }
7535
7536 flags.starting = 0;
7537
7538 /* On success overlap the setting of started/starting. On failure just
7539 * clear starting.
7540 */
7541 if (result == KERN_SUCCESS) {
7542 flags.started = 1;
7543
7544 // xxx - log start error from kernel?
7545 OSKextLog(this,
7546 kOSKextLogProgressLevel |
7547 kOSKextLogLoadFlag,
7548 "Kext %s is now started.",
7549 getIdentifierCString());
7550 } else {
7551 invokeOrCancelRequestCallbacks(
7552 /* result not actually used */ kOSKextReturnStartStopError,
7553 /* invokeFlag */ false);
7554 OSKextLog(this,
7555 kOSKextLogWarningLevel |
7556 kOSKextLogLoadFlag,
7557 "Kext %s did not start (return code 0x%x).",
7558 getIdentifierCString(), result);
7559 }
7560
7561 finish:
7562 return result;
7563 }
7564
7565 /*********************************************************************
7566 *********************************************************************/
7567 /* static */
7568 bool
7569 OSKext::canUnloadKextWithIdentifier(
7570 OSString * kextIdentifier,
7571 bool checkClassesFlag)
7572 {
7573 bool result = false;
7574 OSKext * aKext = NULL; // do not release
7575
7576 IORecursiveLockLock(sKextLock);
7577
7578 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7579
7580 if (!aKext) {
7581 goto finish; // can't unload what's not loaded
7582 }
7583
7584 if (aKext->isLoaded()) {
7585 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7586 goto finish;
7587 }
7588 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7589 goto finish;
7590 }
7591 }
7592
7593 result = true;
7594
7595 finish:
7596 IORecursiveLockUnlock(sKextLock);
7597 return result;
7598 }
7599
7600 /*********************************************************************
7601 *********************************************************************/
7602 OSReturn
7603 OSKext::stop(void)
7604 {
7605 OSReturn result = kOSReturnError;
7606 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7607
7608 if (!isStarted() || isInterface()) {
7609 result = kOSReturnSuccess;
7610 goto finish;
7611 }
7612
7613 if (!isLoaded()) {
7614 OSKextLog(this,
7615 kOSKextLogErrorLevel |
7616 kOSKextLogLoadFlag,
7617 "Attempt to stop nonloaded kext %s.",
7618 getIdentifierCString());
7619 result = kOSKextReturnInvalidArgument;
7620 goto finish;
7621 }
7622
7623 /* Refuse to stop if we have clients or instances. It is up to
7624 * the caller to make sure those aren't true.
7625 */
7626 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7627 OSKextLog(this,
7628 kOSKextLogErrorLevel |
7629 kOSKextLogLoadFlag,
7630 "Kext %s - C++ instances; can't stop.",
7631 getIdentifierCString());
7632 result = kOSKextReturnInUse;
7633 goto finish;
7634 }
7635
7636 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7637 OSKextLog(this,
7638 kOSKextLogErrorLevel |
7639 kOSKextLogLoadFlag,
7640 "Kext %s - has references (linkage or tracking object); "
7641 "can't stop.",
7642 getIdentifierCString());
7643 result = kOSKextReturnInUse;
7644 goto finish;
7645 }
7646
7647 /* Note: If validateKextMapping fails on the stop & unload path,
7648 * we are in serious trouble and a kernel panic is likely whether
7649 * we stop & unload the kext or not.
7650 */
7651 result = validateKextMapping(/* start? */ false);
7652 if (result != kOSReturnSuccess) {
7653 goto finish;
7654 }
7655
7656 stopfunc = kmod_info->stop;
7657 if (stopfunc) {
7658 OSKextLog(this,
7659 kOSKextLogDetailLevel |
7660 kOSKextLogLoadFlag,
7661 "Kext %s calling module stop function.",
7662 getIdentifierCString());
7663
7664 flags.stopping = 1;
7665
7666 result = stopfunc(kmod_info, /* userData */ NULL);
7667 if (result == KERN_SUCCESS) {
7668 result = OSRuntimeFinalizeCPP(this);
7669 }
7670
7671 flags.stopping = 0;
7672
7673 if (result == KERN_SUCCESS) {
7674 flags.started = 0;
7675
7676 OSKextLog(this,
7677 kOSKextLogDetailLevel |
7678 kOSKextLogLoadFlag,
7679 "Kext %s is now stopped and ready to unload.",
7680 getIdentifierCString());
7681 } else {
7682 OSKextLog(this,
7683 kOSKextLogErrorLevel |
7684 kOSKextLogLoadFlag,
7685 "Kext %s did not stop (return code 0x%x).",
7686 getIdentifierCString(), result);
7687 result = kOSKextReturnStartStopError;
7688 }
7689 }
7690
7691 finish:
7692 // Drop a log message so logd can update this kext's metadata
7693 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7694 return result;
7695 }
7696
7697 /*********************************************************************
7698 *********************************************************************/
7699 OSReturn
7700 OSKext::unload(void)
7701 {
7702 OSReturn result = kOSReturnError;
7703 unsigned int index;
7704 uint32_t num_kmod_refs = 0;
7705 OSKextAccount * freeAccount;
7706 bool in_fileset = false;
7707
7708 if (!sUnloadEnabled) {
7709 OSKextLog(this,
7710 kOSKextLogErrorLevel |
7711 kOSKextLogLoadFlag,
7712 "Kext unloading is disabled (%s).",
7713 this->getIdentifierCString());
7714
7715 result = kOSKextReturnDisabled;
7716 goto finish;
7717 }
7718
7719 // cache this result so we don't need to access the kmod_info after
7720 // it's been potentially free'd
7721 in_fileset = isInFileset();
7722
7723 /* Refuse to unload if we have clients or instances. It is up to
7724 * the caller to make sure those aren't true.
7725 */
7726 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7727 // xxx - Don't log under errors? this is more of an info thing
7728 OSKextLog(this,
7729 kOSKextLogErrorLevel |
7730 kOSKextLogKextBookkeepingFlag,
7731 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7732 getIdentifierCString());
7733 result = kOSKextReturnInUse;
7734 goto finish;
7735 }
7736
7737 if (isDriverKit()) {
7738 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7739 if (index != (unsigned int)-1) {
7740 sLoadedDriverKitKexts->removeObject(index);
7741 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7742 loadTag = 0;
7743 }
7744 }
7745
7746 if (!isLoaded()) {
7747 result = kOSReturnSuccess;
7748 goto finish;
7749 }
7750
7751 if (isKernelComponent()) {
7752 result = kOSKextReturnInvalidArgument;
7753 goto finish;
7754 }
7755
7756 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
7757 OSKextLog(this,
7758 kOSKextLogErrorLevel |
7759 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7760 "Can't unload kext %s; classes have instances:",
7761 getIdentifierCString());
7762 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7763 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7764 result = kOSKextReturnInUse;
7765 goto finish;
7766 }
7767
7768 /* Note that the kext is unloading before running any code that
7769 * might be in the kext (request callbacks, module stop function).
7770 * We will deny certain requests made against a kext in the process
7771 * of unloading.
7772 */
7773 flags.unloading = 1;
7774
7775 /* Update the string describing the last kext to unload in case we panic.
7776 */
7777 savePanicString(/* isLoading */ false);
7778
7779 if (isStarted()) {
7780 result = stop();
7781 if (result != KERN_SUCCESS) {
7782 OSKextLog(this,
7783 kOSKextLogErrorLevel |
7784 kOSKextLogLoadFlag,
7785 "Kext %s can't unload - module stop returned 0x%x.",
7786 getIdentifierCString(), (unsigned)result);
7787 result = kOSKextReturnStartStopError;
7788 goto finish;
7789 }
7790 }
7791
7792 OSKextLog(this,
7793 kOSKextLogProgressLevel |
7794 kOSKextLogLoadFlag,
7795 "Kext %s unloading.",
7796 getIdentifierCString());
7797
7798 {
7799 struct list_head *p;
7800 struct list_head *prev;
7801 struct list_head *next;
7802 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7803 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7804 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7805 prev = p->prev;
7806 next = p->next;
7807 prev->next = next;
7808 next->prev = prev;
7809 p->prev = p;
7810 p->next = p;
7811 IORecursiveLockWakeup(sKextLock, s, false);
7812 }
7813 }
7814
7815
7816 /* Even if we don't call the stop function, we want to be sure we
7817 * have no OSMetaClass references before unloading the kext executable
7818 * from memory. OSMetaClasses may have pointers into the kext executable
7819 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7820 */
7821 if (metaClasses) {
7822 metaClasses->flushCollection();
7823 }
7824 (void) OSRuntimeFinalizeCPP(this);
7825
7826 /* Remove the kext from the list of loaded kexts, patch the gap
7827 * in the kmod_info_t linked list, and reset "kmod" to point to the
7828 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7829 */
7830 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7831 if (index != (unsigned int)-1) {
7832 sLoadedKexts->removeObject(index);
7833
7834 OSKext * nextKext = OSDynamicCast(OSKext,
7835 sLoadedKexts->getObject(index));
7836
7837 if (nextKext) {
7838 if (index > 0) {
7839 OSKext * gapKext = OSDynamicCast(OSKext,
7840 sLoadedKexts->getObject(index - 1));
7841
7842 nextKext->kmod_info->next = gapKext->kmod_info;
7843 } else { /* index == 0 */
7844 nextKext->kmod_info->next = NULL;
7845 }
7846 }
7847
7848 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7849 if (lastKext && !lastKext->isKernel()) {
7850 kmod = lastKext->kmod_info;
7851 } else {
7852 kmod = NULL; // clear the global kmod variable
7853 }
7854 }
7855
7856 /* Clear out the kmod references that we're keeping for compatibility
7857 * with current panic backtrace code & kgmacros.
7858 * xxx - will want to update those bits sometime and remove this.
7859 */
7860 num_kmod_refs = getNumDependencies();
7861 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7862 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7863 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7864 ref->info->reference_count--;
7865 }
7866 kfree_type(kmod_reference_t, num_kmod_refs,
7867 kmod_info->reference_list);
7868 }
7869
7870 #if CONFIG_DTRACE
7871 unregisterWithDTrace();
7872 #endif /* CONFIG_DTRACE */
7873
7874 notifyKextUnloadObservers(this);
7875
7876 freeAccount = NULL;
7877 IOSimpleLockLock(sKextAccountsLock);
7878 account->kext = NULL;
7879 if (account->site.tag) {
7880 account->site.flags |= VM_TAG_UNLOAD;
7881 } else {
7882 freeAccount = account;
7883 }
7884
7885 #if DEVELOPMENT || DEBUG
7886 assertf(account->task_refgrp.grp_count == 0,
7887 "unloading a kext with active task references");
7888 #endif /* DEVELOPMENT || DEBUG */
7889
7890 IOSimpleLockUnlock(sKextAccountsLock);
7891 if (freeAccount) {
7892 IOFreeType(freeAccount, OSKextAccount);
7893 }
7894
7895 /* Unwire and free the linked executable.
7896 */
7897 if (linkedExecutable) {
7898 #if KASAN
7899 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
7900 #endif
7901
7902 #if VM_MAPPED_KEXTS
7903 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
7904 kernel_segment_command_t *seg = NULL;
7905 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7906
7907 if (!kext_map) {
7908 OSKextLog(this,
7909 kOSKextLogErrorLevel |
7910 kOSKextLogLoadFlag,
7911 "Failed to free kext %s; couldn't find the kext map.",
7912 getIdentifierCString());
7913 result = kOSKextReturnInternalError;
7914 goto finish;
7915 }
7916
7917 OSKextLog(this,
7918 kOSKextLogProgressLevel |
7919 kOSKextLogLoadFlag,
7920 "Kext %s unwiring and unmapping linked executable.",
7921 getIdentifierCString());
7922
7923 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7924 while (seg) {
7925 if (segmentShouldBeWired(seg)) {
7926 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7927 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7928
7929 result = vm_map_unwire(kext_map, start_wire,
7930 end_wire, FALSE);
7931 if (result != KERN_SUCCESS) {
7932 OSKextLog(this,
7933 kOSKextLogErrorLevel |
7934 kOSKextLogLoadFlag,
7935 "Failed to unwire kext %s.",
7936 getIdentifierCString());
7937 result = kOSKextReturnInternalError;
7938 goto finish;
7939 }
7940 }
7941
7942 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7943 }
7944 #if defined(__x86_64__) || defined(__i386__)
7945 if (in_fileset && flags.resetSegmentsFromVnode) {
7946 IORecursiveLockLock(sKextLock);
7947 resetKCFileSetSegments();
7948 IORecursiveLockUnlock(sKextLock);
7949 }
7950 #endif // (__x86_64__) || defined(__i386__)
7951 }
7952 #endif /* VM_MAPPED_KEXTS */
7953 if (flags.resetSegmentsFromImmutableCopy) {
7954 result = resetMutableSegments();
7955 if (result != kOSReturnSuccess) {
7956 OSKextLog(this,
7957 kOSKextLogErrorLevel |
7958 kOSKextLogLoadFlag,
7959 "Failed to reset kext %s.",
7960 getIdentifierCString());
7961 result = kOSKextReturnInternalError;
7962 goto finish;
7963 }
7964 }
7965 if (kc_type == KCKindUnknown) {
7966 linkedExecutable.reset();
7967 }
7968 }
7969
7970 /* An interface kext has a fake kmod_info that was allocated,
7971 * so we have to free it.
7972 */
7973 if (isInterface()) {
7974 kfree_type(kmod_info_t, kmod_info);
7975 kmod_info = NULL;
7976 }
7977
7978 if (!in_fileset) {
7979 kmod_info = NULL;
7980 }
7981
7982 flags.loaded = false;
7983 flushDependencies();
7984
7985 /* save a copy of the bundle ID for us to check when deciding to
7986 * rebuild the kernel cache file. If a kext was already in the kernel
7987 * cache and unloaded then later loaded we do not need to rebuild the
7988 * kernel cache. 9055303
7989 */
7990 if (isPrelinked()) {
7991 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
7992 IORecursiveLockLock(sKextLock);
7993 if (sUnloadedPrelinkedKexts) {
7994 sUnloadedPrelinkedKexts->setObject(bundleID.get());
7995 }
7996 IORecursiveLockUnlock(sKextLock);
7997 }
7998 }
7999
8000 OSKextLog(this,
8001 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8002 "Kext %s unloaded.", getIdentifierCString());
8003
8004 queueKextNotification(kKextRequestPredicateUnloadNotification,
8005 OSDynamicCast(OSString, bundleID.get()));
8006
8007 finish:
8008 OSKext::saveLoadedKextPanicList();
8009 OSKext::updateLoadedKextSummaries();
8010
8011 flags.unloading = 0;
8012 return result;
8013 }
8014
8015 /*********************************************************************
8016 * Assumes sKextLock is held.
8017 *********************************************************************/
8018 /* static */
8019 OSReturn
8020 OSKext::queueKextNotification(
8021 const char * notificationName,
8022 OSString * kextIdentifier)
8023 {
8024 OSReturn result = kOSReturnError;
8025 OSSharedPtr<OSDictionary> loadRequest;
8026
8027 if (!kextIdentifier) {
8028 result = kOSKextReturnInvalidArgument;
8029 goto finish;
8030 }
8031
8032 /* Create a new request unless one is already sitting
8033 * in sKernelRequests for this bundle identifier
8034 */
8035 result = _OSKextCreateRequest(notificationName, loadRequest);
8036 if (result != kOSReturnSuccess) {
8037 goto finish;
8038 }
8039 if (!_OSKextSetRequestArgument(loadRequest.get(),
8040 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8041 result = kOSKextReturnNoMemory;
8042 goto finish;
8043 }
8044 if (!sKernelRequests->setObject(loadRequest.get())) {
8045 result = kOSKextReturnNoMemory;
8046 goto finish;
8047 }
8048
8049 /* We might want to only queue the notification if the IOKit daemon is active,
8050 * but that wouldn't work for embedded. Note that we don't care if
8051 * the ping immediately succeeds here so don't do anything with the
8052 * result of this call.
8053 */
8054 OSKext::pingIOKitDaemon();
8055
8056 result = kOSReturnSuccess;
8057
8058 finish:
8059 return result;
8060 }
8061
8062
8063 #if CONFIG_KXLD
8064 /*********************************************************************
8065 *********************************************************************/
8066 static void
8067 _OSKextConsiderDestroyingLinkContext(
8068 __unused thread_call_param_t p0,
8069 __unused thread_call_param_t p1)
8070 {
8071 /* Take multiple locks in the correct order.
8072 */
8073 IORecursiveLockLock(sKextLock);
8074 IORecursiveLockLock(sKextInnerLock);
8075
8076 /* The first time we destroy the kxldContext is in the first
8077 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8078 * before calling this function. Thereafter any call to this function
8079 * will actually destroy the context.
8080 */
8081 if (sConsiderUnloadsCalled && sKxldContext) {
8082 kxld_destroy_context(sKxldContext);
8083 sKxldContext = NULL;
8084 }
8085
8086 /* Free the thread_call that was allocated to execute this function.
8087 */
8088 if (sDestroyLinkContextThread) {
8089 if (!thread_call_free(sDestroyLinkContextThread)) {
8090 OSKextLog(/* kext */ NULL,
8091 kOSKextLogErrorLevel |
8092 kOSKextLogGeneralFlag,
8093 "thread_call_free() failed for kext link context.");
8094 }
8095 sDestroyLinkContextThread = NULL;
8096 }
8097
8098 IORecursiveLockUnlock(sKextInnerLock);
8099 IORecursiveLockUnlock(sKextLock);
8100
8101 return;
8102 }
8103
8104 /*********************************************************************
8105 * Destroying the kxldContext requires checking variables under both
8106 * sKextInnerLock and sKextLock, so we do it on a separate thread
8107 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8108 * call relationship.
8109 *
8110 * This function must be invoked with sKextInnerLock held.
8111 * Do not call any function that takes sKextLock here!
8112 *********************************************************************/
8113 /* static */
8114 void
8115 OSKext::considerDestroyingLinkContext(void)
8116 {
8117 IORecursiveLockLock(sKextInnerLock);
8118
8119 /* If we have already queued a thread to destroy the link context,
8120 * don't bother resetting; that thread will take care of it.
8121 */
8122 if (sDestroyLinkContextThread) {
8123 goto finish;
8124 }
8125
8126 /* The function to be invoked in the thread will deallocate
8127 * this thread_call, so don't share it around.
8128 */
8129 sDestroyLinkContextThread = thread_call_allocate(
8130 &_OSKextConsiderDestroyingLinkContext, NULL);
8131 if (!sDestroyLinkContextThread) {
8132 OSKextLog(/* kext */ NULL,
8133 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8134 "Can't create thread to destroy kext link context.");
8135 goto finish;
8136 }
8137
8138 thread_call_enter(sDestroyLinkContextThread);
8139
8140 finish:
8141 IORecursiveLockUnlock(sKextInnerLock);
8142 return;
8143 }
8144
8145 #else // !CONFIG_KXLD
8146
8147 /* static */
8148 void
8149 OSKext::considerDestroyingLinkContext(void)
8150 {
8151 return;
8152 }
8153
8154 #endif // CONFIG_KXLD
8155
8156 #if PRAGMA_MARK
8157 #pragma mark Autounload
8158 #endif
8159 /*********************************************************************
8160 * This is a static method because the kext will be deallocated if it
8161 * does unload!
8162 *********************************************************************/
8163 /* static */
8164 OSReturn
8165 OSKext::autounloadKext(OSKext * aKext)
8166 {
8167 OSReturn result = kOSKextReturnInUse;
8168
8169 #if NO_KEXTD
8170 /*
8171 * Do not unload prelinked kexts on platforms that do not have an
8172 * IOKit daemon as there is no way to reload the kext or restart
8173 * matching.
8174 */
8175 if (aKext->isPrelinked()) {
8176 goto finish;
8177 }
8178 #endif /* defined(__x86_64__) */
8179
8180 /* Check for external references to this kext (usu. dependents),
8181 * instances of defined classes (or classes derived from them),
8182 * outstanding requests.
8183 */
8184 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8185 !aKext->flags.autounloadEnabled ||
8186 aKext->isKernelComponent()) {
8187 goto finish;
8188 }
8189
8190 /* Skip a delay-autounload kext, once.
8191 */
8192 if (aKext->flags.delayAutounload) {
8193 OSKextLog(aKext,
8194 kOSKextLogProgressLevel |
8195 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8196 "Kext %s has delayed autounload set; skipping and clearing flag.",
8197 aKext->getIdentifierCString());
8198 aKext->flags.delayAutounload = 0;
8199 goto finish;
8200 }
8201
8202 if (aKext->hasOSMetaClassInstances() ||
8203 aKext->countRequestCallbacks()) {
8204 goto finish;
8205 }
8206
8207 result = OSKext::removeKext(aKext);
8208
8209 finish:
8210 return result;
8211 }
8212
8213 /*********************************************************************
8214 *********************************************************************/
8215 void
8216 _OSKextConsiderUnloads(
8217 __unused thread_call_param_t p0,
8218 __unused thread_call_param_t p1)
8219 {
8220 bool didUnload = false;
8221 unsigned int count, i;
8222
8223 /* Take multiple locks in the correct order
8224 * (note also sKextSummaries lock further down).
8225 */
8226 IORecursiveLockLock(sKextLock);
8227 IORecursiveLockLock(sKextInnerLock);
8228
8229 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8230
8231 /* If the system is powering down, don't try to unload anything.
8232 */
8233 if (sSystemSleep) {
8234 goto finish;
8235 }
8236
8237 OSKextLog(/* kext */ NULL,
8238 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8239 "Checking for unused kexts to autounload.");
8240
8241 /*****
8242 * Remove any request callbacks marked as stale,
8243 * and mark as stale any currently in flight.
8244 */
8245 count = sRequestCallbackRecords->getCount();
8246 if (count) {
8247 i = count - 1;
8248 do {
8249 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8250 sRequestCallbackRecords->getObject(i));
8251 if (callbackRecord) {
8252 OSBoolean * stale = OSDynamicCast(OSBoolean,
8253 callbackRecord->getObject(kKextRequestStaleKey));
8254
8255 if (stale == kOSBooleanTrue) {
8256 OSKext::invokeRequestCallback(callbackRecord,
8257 kOSKextReturnTimeout);
8258 } else {
8259 callbackRecord->setObject(kKextRequestStaleKey,
8260 kOSBooleanTrue);
8261 }
8262 }
8263 } while (i--);
8264 }
8265
8266 /*****
8267 * Make multiple passes through the array of loaded kexts until
8268 * we don't unload any. This handles unwinding of dependency
8269 * chains. We have to go *backwards* through the array because
8270 * kexts are removed from it when unloaded, and we cannot make
8271 * a copy or we'll mess up the retain counts we rely on to
8272 * check whether a kext will unload. If only we could have
8273 * nonretaining collections like CF has....
8274 */
8275 do {
8276 didUnload = false;
8277
8278 count = sLoadedKexts->getCount();
8279 if (count) {
8280 i = count - 1;
8281 do {
8282 OSKext * thisKext = OSDynamicCast(OSKext,
8283 sLoadedKexts->getObject(i));
8284 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8285 } while (i--);
8286 }
8287 } while (didUnload);
8288
8289 finish:
8290 sConsiderUnloadsPending = false;
8291 sConsiderUnloadsExecuted = true;
8292
8293 (void) OSKext::considerRebuildOfPrelinkedKernel();
8294
8295 IORecursiveLockUnlock(sKextInnerLock);
8296 IORecursiveLockUnlock(sKextLock);
8297
8298 return;
8299 }
8300
8301 /*********************************************************************
8302 * Do not call any function that takes sKextLock here!
8303 *********************************************************************/
8304 void
8305 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8306 {
8307 AbsoluteTime when;
8308
8309 IORecursiveLockLock(sKextInnerLock);
8310
8311 if (!sUnloadCallout) {
8312 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8313 }
8314
8315 /* we only reset delay value for unloading if we already have something
8316 * pending. rescheduleOnlyFlag should not start the count down.
8317 */
8318 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8319 goto finish;
8320 }
8321
8322 thread_call_cancel(sUnloadCallout);
8323 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8324 #if !NO_KEXTD
8325 && sIOKitDaemonActive
8326 #endif
8327 ) {
8328 clock_interval_to_deadline(sConsiderUnloadDelay,
8329 1000 * 1000 * 1000, &when);
8330
8331 OSKextLog(/* kext */ NULL,
8332 kOSKextLogProgressLevel |
8333 kOSKextLogLoadFlag,
8334 "%scheduling %sscan for unused kexts in %lu seconds.",
8335 sConsiderUnloadsPending ? "Res" : "S",
8336 sConsiderUnloadsCalled ? "" : "initial ",
8337 (unsigned long)sConsiderUnloadDelay);
8338
8339 sConsiderUnloadsPending = true;
8340 thread_call_enter_delayed(sUnloadCallout, when);
8341 }
8342
8343 finish:
8344 /* The kxld context should be reused throughout boot. We mark the end of
8345 * period as the first time considerUnloads() is called, and we destroy
8346 * the first kxld context in that function. Afterwards, it will be
8347 * destroyed in flushNonloadedKexts.
8348 */
8349 if (!sConsiderUnloadsCalled) {
8350 sConsiderUnloadsCalled = true;
8351 OSKext::considerDestroyingLinkContext();
8352 }
8353
8354 IORecursiveLockUnlock(sKextInnerLock);
8355 return;
8356 }
8357
8358 /*********************************************************************
8359 * Do not call any function that takes sKextLock here!
8360 *********************************************************************/
8361 extern "C" {
8362 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
8363 IOReturn
8364 OSKextSystemSleepOrWake(UInt32 messageType)
8365 {
8366 IORecursiveLockLock(sKextInnerLock);
8367
8368 /* If the system is going to sleep, cancel the reaper thread timer,
8369 * and note that we're in a sleep state in case it just fired but hasn't
8370 * taken the lock yet. If we are coming back from sleep, just
8371 * clear the sleep flag; IOService's normal operation will cause
8372 * unloads to be considered soon enough.
8373 */
8374 if (messageType == kIOMessageSystemWillSleep) {
8375 if (sUnloadCallout) {
8376 thread_call_cancel(sUnloadCallout);
8377 }
8378 sSystemSleep = true;
8379 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8380 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8381 sSystemSleep = false;
8382 clock_get_uptime(&sLastWakeTime);
8383 }
8384 IORecursiveLockUnlock(sKextInnerLock);
8385
8386 return kIOReturnSuccess;
8387 }
8388 };
8389
8390
8391 #if PRAGMA_MARK
8392 #pragma mark Prelinked Kernel
8393 #endif
8394
8395 #ifdef CONFIG_KXLD
8396 /*********************************************************************
8397 * Do not access sConsiderUnloads... variables other than
8398 * sConsiderUnloadsExecuted in this function. They are guarded by a
8399 * different lock.
8400 *********************************************************************/
8401 /* static */
8402 void
8403 OSKext::considerRebuildOfPrelinkedKernel(void)
8404 {
8405 static bool requestedPrelink = false;
8406 OSReturn checkResult = kOSReturnError;
8407 OSSharedPtr<OSDictionary> prelinkRequest;
8408 OSSharedPtr<OSCollectionIterator> kextIterator;
8409 const OSSymbol * thisID = NULL; // do not release
8410 bool doRebuild = false;
8411 AbsoluteTime my_abstime;
8412 UInt64 my_ns;
8413 SInt32 delta_secs;
8414
8415 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8416 if (requestedPrelink || !sPrelinkBoot) {
8417 return;
8418 }
8419
8420 /* no direct return from this point */
8421 IORecursiveLockLock(sKextLock);
8422
8423 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8424 * and any new startup kexts loaded.
8425 */
8426 if (!sConsiderUnloadsExecuted ||
8427 !sDeferredLoadSucceeded) {
8428 goto finish;
8429 }
8430
8431 /* we really only care about boot / system start up related kexts so bail
8432 * if we're here after REBUILD_MAX_TIME.
8433 */
8434 if (!_OSKextInPrelinkRebuildWindow()) {
8435 OSKextLog(/* kext */ NULL,
8436 kOSKextLogArchiveFlag,
8437 "%s prebuild rebuild has expired",
8438 __FUNCTION__);
8439 requestedPrelink = true;
8440 goto finish;
8441 }
8442
8443 /* we do not want to trigger a rebuild if we get here too close to waking
8444 * up. (see radar 10233768)
8445 */
8446 IORecursiveLockLock(sKextInnerLock);
8447
8448 clock_get_uptime(&my_abstime);
8449 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8450 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8451 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8452 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8453 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8454 }
8455 IORecursiveLockUnlock(sKextInnerLock);
8456
8457 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8458 /* too close to time of last wake from sleep */
8459 goto finish;
8460 }
8461 requestedPrelink = true;
8462
8463 /* Now it's time to see if we have a reason to rebuild. We may have done
8464 * some loads and unloads but the kernel cache didn't actually change.
8465 * We will rebuild if any kext is not marked prelinked AND is not in our
8466 * list of prelinked kexts that got unloaded. (see radar 9055303)
8467 */
8468 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
8469 if (!kextIterator) {
8470 goto finish;
8471 }
8472
8473 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
8474 OSKext * thisKext; // do not release
8475
8476 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8477 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8478 continue;
8479 }
8480
8481 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
8482 continue;
8483 }
8484 /* kext is loaded and was not in current kernel cache so let's rebuild
8485 */
8486 doRebuild = true;
8487 OSKextLog(/* kext */ NULL,
8488 kOSKextLogArchiveFlag,
8489 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8490 thisKext->bundleID->getCStringNoCopy());
8491 break;
8492 }
8493 sUnloadedPrelinkedKexts->flushCollection();
8494
8495 if (!doRebuild) {
8496 goto finish;
8497 }
8498
8499 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
8500 prelinkRequest);
8501 if (checkResult != kOSReturnSuccess) {
8502 goto finish;
8503 }
8504
8505 if (!sKernelRequests->setObject(prelinkRequest.get())) {
8506 goto finish;
8507 }
8508
8509 OSKext::pingIOKitDaemon();
8510
8511 finish:
8512 IORecursiveLockUnlock(sKextLock);
8513
8514 return;
8515 }
8516
8517 #else /* !CONFIG_KXLD */
8518
8519 void
8520 OSKext::considerRebuildOfPrelinkedKernel(void)
8521 {
8522 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8523 return;
8524 }
8525
8526 #endif /* CONFIG_KXLD */
8527
8528 #if PRAGMA_MARK
8529 #pragma mark Dependencies
8530 #endif
8531 /*********************************************************************
8532 *********************************************************************/
8533 bool
8534 OSKext::resolveDependencies(
8535 OSArray * loopStack)
8536 {
8537 bool result = false;
8538 OSSharedPtr<OSArray> localLoopStack;
8539 bool addedToLoopStack = false;
8540 OSDictionary * libraries = NULL; // do not release
8541 OSSharedPtr<OSCollectionIterator> libraryIterator;
8542 OSString * libraryID = NULL; // do not release
8543 OSKext * libraryKext = NULL; // do not release
8544 bool hasRawKernelDependency = false;
8545 bool hasKernelDependency = false;
8546 bool hasKPIDependency = false;
8547 bool hasPrivateKPIDependency = false;
8548 unsigned int count;
8549
8550 #if CONFIG_KXLD
8551 OSString * infoString = NULL; // do not release
8552 OSString * readableString = NULL; // do not release
8553 #endif // CONFIG_KXLD
8554
8555 /* A kernel component will automatically have this flag set,
8556 * and a loaded kext should also have it set (as should all its
8557 * loaded dependencies).
8558 */
8559 if (flags.hasAllDependencies) {
8560 result = true;
8561 goto finish;
8562 }
8563
8564 /* Check for loops in the dependency graph.
8565 */
8566 if (loopStack) {
8567 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8568 OSKextLog(this,
8569 kOSKextLogErrorLevel |
8570 kOSKextLogDependenciesFlag,
8571 "Kext %s has a dependency loop; can't resolve dependencies.",
8572 getIdentifierCString());
8573 goto finish;
8574 }
8575 } else {
8576 OSKextLog(this,
8577 kOSKextLogStepLevel |
8578 kOSKextLogDependenciesFlag,
8579 "Kext %s resolving dependencies.",
8580 getIdentifierCString());
8581
8582 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8583 if (!localLoopStack) {
8584 OSKextLog(this,
8585 kOSKextLogErrorLevel |
8586 kOSKextLogDependenciesFlag,
8587 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8588 getIdentifierCString());
8589 goto finish;
8590 }
8591 loopStack = localLoopStack.get();
8592 }
8593 if (!loopStack->setObject(this)) {
8594 OSKextLog(this,
8595 kOSKextLogErrorLevel |
8596 kOSKextLogDependenciesFlag,
8597 "Kext %s - internal error resolving dependencies.",
8598 getIdentifierCString());
8599 goto finish;
8600 }
8601 addedToLoopStack = true;
8602
8603 /* Purge any existing kexts in the dependency list and start over.
8604 */
8605 flushDependencies();
8606 if (dependencies) {
8607 OSKextLog(this,
8608 kOSKextLogErrorLevel |
8609 kOSKextLogDependenciesFlag,
8610 "Kext %s - internal error resolving dependencies.",
8611 getIdentifierCString());
8612 }
8613
8614 libraries = OSDynamicCast(OSDictionary,
8615 getPropertyForHostArch(kOSBundleLibrariesKey));
8616 if (libraries == NULL || libraries->getCount() == 0) {
8617 OSKextLog(this,
8618 kOSKextLogErrorLevel |
8619 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8620 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8621 getIdentifierCString(), kOSBundleLibrariesKey);
8622 goto finish;
8623 }
8624
8625 /* Make a new array to hold the dependencies (flush freed the old one).
8626 */
8627 dependencies = OSArray::withCapacity(libraries->getCount());
8628 if (!dependencies) {
8629 OSKextLog(this,
8630 kOSKextLogErrorLevel |
8631 kOSKextLogDependenciesFlag,
8632 "Kext %s - can't allocate dependencies array.",
8633 getIdentifierCString());
8634 goto finish;
8635 }
8636
8637 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8638 // xxx - compat: if none were declared.
8639
8640 libraryIterator = OSCollectionIterator::withCollection(libraries);
8641 if (!libraryIterator) {
8642 OSKextLog(this,
8643 kOSKextLogErrorLevel |
8644 kOSKextLogDependenciesFlag,
8645 "Kext %s - can't allocate dependencies iterator.",
8646 getIdentifierCString());
8647 goto finish;
8648 }
8649
8650 while ((libraryID = OSDynamicCast(OSString,
8651 libraryIterator->getNextObject()))) {
8652 const char * library_id = libraryID->getCStringNoCopy();
8653
8654 OSString * libraryVersion = OSDynamicCast(OSString,
8655 libraries->getObject(libraryID));
8656 if (libraryVersion == NULL) {
8657 OSKextLog(this,
8658 kOSKextLogErrorLevel |
8659 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8660 "Kext %s - illegal type in OSBundleLibraries.",
8661 getIdentifierCString());
8662 goto finish;
8663 }
8664
8665 OSKextVersion libraryVers =
8666 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8667 if (libraryVers == -1) {
8668 OSKextLog(this,
8669 kOSKextLogErrorLevel |
8670 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8671 "Kext %s - invalid library version %s.",
8672 getIdentifierCString(),
8673 libraryVersion->getCStringNoCopy());
8674 goto finish;
8675 }
8676
8677 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8678 if (libraryKext == NULL) {
8679 OSKextLog(this,
8680 kOSKextLogErrorLevel |
8681 kOSKextLogDependenciesFlag,
8682 "Kext %s - library kext %s not found.",
8683 getIdentifierCString(), library_id);
8684 goto finish;
8685 }
8686
8687 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8688 OSKextLog(this,
8689 kOSKextLogErrorLevel |
8690 kOSKextLogDependenciesFlag,
8691 "Kext %s - library kext %s not compatible "
8692 "with requested version %s.",
8693 getIdentifierCString(), library_id,
8694 libraryVersion->getCStringNoCopy());
8695 goto finish;
8696 }
8697
8698 /* If a nonprelinked library somehow got into the mix for a
8699 * prelinked kext, at any point in the chain, we must fail
8700 * because the prelinked relocs for the library will be all wrong.
8701 */
8702 if (this->isPrelinked() &&
8703 libraryKext->declaresExecutable() &&
8704 !libraryKext->isPrelinked()) {
8705 OSKextLog(this,
8706 kOSKextLogErrorLevel |
8707 kOSKextLogDependenciesFlag,
8708 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8709 getIdentifierCString(), library_id,
8710 libraryVersion->getCStringNoCopy());
8711 goto finish;
8712 }
8713
8714 if (!libraryKext->resolveDependencies(loopStack)) {
8715 goto finish;
8716 }
8717
8718 /* Add the library directly only if it has an executable to link.
8719 * Otherwise it's just used to collect other dependencies, so put
8720 * *its* dependencies on the list for this kext.
8721 */
8722 // xxx - We are losing info here; would like to make fake entries or
8723 // xxx - keep these in the dependency graph for loaded kexts.
8724 // xxx - I really want to make kernel components not a special case!
8725 if (libraryKext->declaresExecutable() ||
8726 libraryKext->isInterface()) {
8727 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8728 dependencies->setObject(libraryKext);
8729
8730 OSKextLog(this,
8731 kOSKextLogDetailLevel |
8732 kOSKextLogDependenciesFlag,
8733 "Kext %s added dependency %s.",
8734 getIdentifierCString(),
8735 libraryKext->getIdentifierCString());
8736 }
8737 } else {
8738 int numLibDependencies = libraryKext->getNumDependencies();
8739 OSArray * libraryDependencies = libraryKext->getDependencies();
8740 int index;
8741
8742 if (numLibDependencies) {
8743 // xxx - this msg level should be 1 lower than the per-kext one
8744 OSKextLog(this,
8745 kOSKextLogDetailLevel |
8746 kOSKextLogDependenciesFlag,
8747 "Kext %s pulling %d dependencies from codeless library %s.",
8748 getIdentifierCString(),
8749 numLibDependencies,
8750 libraryKext->getIdentifierCString());
8751 }
8752 for (index = 0; index < numLibDependencies; index++) {
8753 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8754 libraryDependencies->getObject(index));
8755 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8756 dependencies->setObject(thisLibDependency);
8757 OSKextLog(this,
8758 kOSKextLogDetailLevel |
8759 kOSKextLogDependenciesFlag,
8760 "Kext %s added dependency %s from codeless library %s.",
8761 getIdentifierCString(),
8762 thisLibDependency->getIdentifierCString(),
8763 libraryKext->getIdentifierCString());
8764 }
8765 }
8766 }
8767
8768 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8769 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8770 hasRawKernelDependency = true;
8771 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8772 hasKernelDependency = true;
8773 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8774 hasKPIDependency = true;
8775 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8776 hasPrivateKPIDependency = true;
8777 }
8778 }
8779 }
8780
8781 if (hasRawKernelDependency) {
8782 OSKextLog(this,
8783 kOSKextLogErrorLevel |
8784 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8785 "Error - kext %s declares a dependency on %s, which is not permitted.",
8786 getIdentifierCString(), KERNEL_LIB);
8787 goto finish;
8788 }
8789 #if __LP64__
8790 if (hasKernelDependency) {
8791 OSKextLog(this,
8792 kOSKextLogErrorLevel |
8793 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8794 "Error - kext %s declares %s dependencies. "
8795 "Only %s* dependencies are supported for 64-bit kexts.",
8796 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8797 goto finish;
8798 }
8799 if (!hasKPIDependency) {
8800 OSKextLog(this,
8801 kOSKextLogWarningLevel |
8802 kOSKextLogDependenciesFlag,
8803 "Warning - kext %s declares no %s* dependencies. "
8804 "If it uses any KPIs, the link may fail with undefined symbols.",
8805 getIdentifierCString(), KPI_LIB_PREFIX);
8806 }
8807 #else /* __LP64__ */
8808 // xxx - will change to flatly disallow "kernel" dependencies at some point
8809 // xxx - is it invalid to do both "com.apple.kernel" and any
8810 // xxx - "com.apple.kernel.*"?
8811
8812 if (hasKernelDependency && hasKPIDependency) {
8813 OSKextLog(this,
8814 kOSKextLogWarningLevel |
8815 kOSKextLogDependenciesFlag,
8816 "Warning - kext %s has immediate dependencies on both "
8817 "%s* and %s* components; use only one style.",
8818 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8819 }
8820
8821 if (!hasKernelDependency && !hasKPIDependency) {
8822 // xxx - do we want to use validation flag for these too?
8823 OSKextLog(this,
8824 kOSKextLogWarningLevel |
8825 kOSKextLogDependenciesFlag,
8826 "Warning - %s declares no kernel dependencies; using %s.",
8827 getIdentifierCString(), KERNEL6_LIB);
8828 OSKext * kernelKext = OSDynamicCast(OSKext,
8829 sKextsByID->getObject(KERNEL6_LIB));
8830 if (kernelKext) {
8831 dependencies->setObject(kernelKext);
8832 } else {
8833 OSKextLog(this,
8834 kOSKextLogErrorLevel |
8835 kOSKextLogDependenciesFlag,
8836 "Error - Library %s not found for %s.",
8837 KERNEL6_LIB, getIdentifierCString());
8838 }
8839 }
8840
8841 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8842 * its indirect dependencies to simulate old-style linking. XXX - Should
8843 * check for duplicates.
8844 */
8845 if (!hasKPIDependency) {
8846 unsigned int i;
8847
8848 flags.hasBleedthrough = true;
8849
8850 count = getNumDependencies();
8851
8852 /* We add to the dependencies array in this loop, but do not iterate
8853 * past its original count.
8854 */
8855 for (i = 0; i < count; i++) {
8856 OSKext * dependencyKext = OSDynamicCast(OSKext,
8857 dependencies->getObject(i));
8858 dependencyKext->addBleedthroughDependencies(dependencies.get());
8859 }
8860 }
8861 #endif /* __LP64__ */
8862
8863 #if CONFIG_KXLD
8864 /*
8865 * If we're not dynamically linking kexts, then we don't need to check
8866 * copyright strings. The linker in user space has already done this.
8867 */
8868 if (hasPrivateKPIDependency) {
8869 bool hasApplePrefix = false;
8870 bool infoCopyrightIsValid = false;
8871 bool readableCopyrightIsValid = false;
8872
8873 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8874 APPLE_KEXT_PREFIX);
8875
8876 infoString = OSDynamicCast(OSString,
8877 getPropertyForHostArch("CFBundleGetInfoString"));
8878 if (infoString) {
8879 infoCopyrightIsValid =
8880 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8881 }
8882
8883 readableString = OSDynamicCast(OSString,
8884 getPropertyForHostArch("NSHumanReadableCopyright"));
8885 if (readableString) {
8886 readableCopyrightIsValid =
8887 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8888 }
8889
8890 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8891 OSKextLog(this,
8892 kOSKextLogErrorLevel |
8893 kOSKextLogDependenciesFlag,
8894 "Error - kext %s declares a dependency on %s. "
8895 "Only Apple kexts may declare a dependency on %s.",
8896 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8897 goto finish;
8898 }
8899 }
8900 #endif // CONFIG_KXLD
8901
8902 result = true;
8903 flags.hasAllDependencies = 1;
8904
8905 finish:
8906
8907 if (addedToLoopStack) {
8908 count = loopStack->getCount();
8909 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8910 loopStack->removeObject(count - 1);
8911 } else {
8912 OSKextLog(this,
8913 kOSKextLogErrorLevel |
8914 kOSKextLogDependenciesFlag,
8915 "Kext %s - internal error resolving dependencies.",
8916 getIdentifierCString());
8917 }
8918 }
8919
8920 if (result && localLoopStack) {
8921 OSKextLog(this,
8922 kOSKextLogStepLevel |
8923 kOSKextLogDependenciesFlag,
8924 "Kext %s successfully resolved dependencies.",
8925 getIdentifierCString());
8926 }
8927
8928 return result;
8929 }
8930
8931 /*********************************************************************
8932 *********************************************************************/
8933 bool
8934 OSKext::addBleedthroughDependencies(OSArray * anArray)
8935 {
8936 bool result = false;
8937 unsigned int dependencyIndex, dependencyCount;
8938
8939 dependencyCount = getNumDependencies();
8940
8941 for (dependencyIndex = 0;
8942 dependencyIndex < dependencyCount;
8943 dependencyIndex++) {
8944 OSKext * dependency = OSDynamicCast(OSKext,
8945 dependencies->getObject(dependencyIndex));
8946 if (!dependency) {
8947 OSKextLog(this,
8948 kOSKextLogErrorLevel |
8949 kOSKextLogDependenciesFlag,
8950 "Kext %s - internal error propagating compatibility dependencies.",
8951 getIdentifierCString());
8952 goto finish;
8953 }
8954 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8955 anArray->setObject(dependency);
8956 }
8957 dependency->addBleedthroughDependencies(anArray);
8958 }
8959
8960 result = true;
8961
8962 finish:
8963 return result;
8964 }
8965
8966 /*********************************************************************
8967 *********************************************************************/
8968 bool
8969 OSKext::flushDependencies(bool forceFlag)
8970 {
8971 bool result = false;
8972
8973 /* Only clear the dependencies if the kext isn't loaded;
8974 * we need the info for loaded kexts to track references.
8975 */
8976 if (!isLoaded() || forceFlag) {
8977 if (dependencies) {
8978 // xxx - check level
8979 OSKextLog(this,
8980 kOSKextLogProgressLevel |
8981 kOSKextLogDependenciesFlag,
8982 "Kext %s flushing dependencies.",
8983 getIdentifierCString());
8984 dependencies.reset();
8985 }
8986 if (!isKernelComponent()) {
8987 flags.hasAllDependencies = 0;
8988 }
8989 result = true;
8990 }
8991
8992 return result;
8993 }
8994
8995 /*********************************************************************
8996 *********************************************************************/
8997 uint32_t
8998 OSKext::getNumDependencies(void)
8999 {
9000 if (!dependencies) {
9001 return 0;
9002 }
9003 return dependencies->getCount();
9004 }
9005
9006 /*********************************************************************
9007 *********************************************************************/
9008 OSArray *
9009 OSKext::getDependencies(void)
9010 {
9011 return dependencies.get();
9012 }
9013
9014 bool
9015 OSKext::hasDependency(const OSSymbol * depID)
9016 {
9017 bool result __block;
9018
9019 if (depID == getIdentifier()) {
9020 return true;
9021 }
9022 if (!dependencies) {
9023 return false;
9024 }
9025 result = false;
9026 dependencies->iterateObjects(^bool (OSObject * obj) {
9027 OSKext * kext;
9028 kext = OSDynamicCast(OSKext, obj);
9029 if (!kext) {
9030 return false;
9031 }
9032 result = (depID == kext->getIdentifier());
9033 return result;
9034 });
9035 return result;
9036 }
9037
9038 #if PRAGMA_MARK
9039 #pragma mark OSMetaClass Support
9040 #endif
9041 /*********************************************************************
9042 *********************************************************************/
9043 OSReturn
9044 OSKext::addClass(
9045 OSMetaClass * aClass,
9046 uint32_t numClasses)
9047 {
9048 OSReturn result = kOSMetaClassNoInsKModSet;
9049
9050 if (!metaClasses) {
9051 metaClasses = OSSet::withCapacity(numClasses);
9052 if (!metaClasses) {
9053 goto finish;
9054 }
9055 }
9056
9057 if (metaClasses->containsObject(aClass)) {
9058 OSKextLog(this,
9059 kOSKextLogWarningLevel |
9060 kOSKextLogLoadFlag,
9061 "Notice - kext %s has already registered class %s.",
9062 getIdentifierCString(),
9063 aClass->getClassName());
9064 result = kOSReturnSuccess;
9065 goto finish;
9066 }
9067
9068 if (!metaClasses->setObject(aClass)) {
9069 goto finish;
9070 } else {
9071 OSKextLog(this,
9072 kOSKextLogDetailLevel |
9073 kOSKextLogLoadFlag,
9074 "Kext %s registered class %s.",
9075 getIdentifierCString(),
9076 aClass->getClassName());
9077 }
9078
9079 if (!flags.autounloadEnabled) {
9080 const OSMetaClass * metaScan = NULL; // do not release
9081
9082 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9083 if (metaScan == OSTypeID(IOService)) {
9084 OSKextLog(this,
9085 kOSKextLogProgressLevel |
9086 kOSKextLogLoadFlag,
9087 "Kext %s has IOService subclass %s; enabling autounload.",
9088 getIdentifierCString(),
9089 aClass->getClassName());
9090
9091 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9092 break;
9093 }
9094 }
9095 }
9096
9097 notifyAddClassObservers(this, aClass, flags);
9098
9099 result = kOSReturnSuccess;
9100
9101 finish:
9102 if (result != kOSReturnSuccess) {
9103 OSKextLog(this,
9104 kOSKextLogErrorLevel |
9105 kOSKextLogLoadFlag,
9106 "Kext %s failed to register class %s.",
9107 getIdentifierCString(),
9108 aClass->getClassName());
9109 }
9110
9111 return result;
9112 }
9113
9114 /*********************************************************************
9115 *********************************************************************/
9116 OSReturn
9117 OSKext::removeClass(
9118 OSMetaClass * aClass)
9119 {
9120 OSReturn result = kOSMetaClassNoKModSet;
9121
9122 if (!metaClasses) {
9123 goto finish;
9124 }
9125
9126 if (!metaClasses->containsObject(aClass)) {
9127 OSKextLog(this,
9128 kOSKextLogWarningLevel |
9129 kOSKextLogLoadFlag,
9130 "Notice - kext %s asked to unregister unknown class %s.",
9131 getIdentifierCString(),
9132 aClass->getClassName());
9133 result = kOSReturnSuccess;
9134 goto finish;
9135 }
9136
9137 OSKextLog(this,
9138 kOSKextLogDetailLevel |
9139 kOSKextLogLoadFlag,
9140 "Kext %s unregistering class %s.",
9141 getIdentifierCString(),
9142 aClass->getClassName());
9143
9144 metaClasses->removeObject(aClass);
9145
9146 notifyRemoveClassObservers(this, aClass, flags);
9147
9148 result = kOSReturnSuccess;
9149
9150 finish:
9151 if (result != kOSReturnSuccess) {
9152 OSKextLog(this,
9153 kOSKextLogErrorLevel |
9154 kOSKextLogLoadFlag,
9155 "Failed to unregister kext %s class %s.",
9156 getIdentifierCString(),
9157 aClass->getClassName());
9158 }
9159 return result;
9160 }
9161
9162 /*********************************************************************
9163 *********************************************************************/
9164 OSSet *
9165 OSKext::getMetaClasses(void)
9166 {
9167 return metaClasses.get();
9168 }
9169
9170 /*********************************************************************
9171 *********************************************************************/
9172 bool
9173 OSKext::hasOSMetaClassInstances(void)
9174 {
9175 bool result = false;
9176 OSSharedPtr<OSCollectionIterator> classIterator;
9177 OSMetaClass * checkClass = NULL; // do not release
9178
9179 if (!metaClasses) {
9180 goto finish;
9181 }
9182
9183 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9184 if (!classIterator) {
9185 // xxx - log alloc failure?
9186 goto finish;
9187 }
9188 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9189 if (checkClass->getInstanceCount()) {
9190 result = true;
9191 goto finish;
9192 }
9193 }
9194
9195 finish:
9196 return result;
9197 }
9198
9199 /*********************************************************************
9200 *********************************************************************/
9201 /* static */
9202 void
9203 OSKext::reportOSMetaClassInstances(
9204 const char * kextIdentifier,
9205 OSKextLogSpec msgLogSpec)
9206 {
9207 OSSharedPtr<OSKext> theKext;
9208
9209 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9210 if (!theKext) {
9211 goto finish;
9212 }
9213
9214 theKext->reportOSMetaClassInstances(msgLogSpec);
9215 finish:
9216 return;
9217 }
9218
9219 /*********************************************************************
9220 *********************************************************************/
9221 void
9222 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9223 {
9224 OSSharedPtr<OSCollectionIterator> classIterator;
9225 OSMetaClass * checkClass = NULL; // do not release
9226
9227 if (!metaClasses) {
9228 goto finish;
9229 }
9230
9231 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9232 if (!classIterator) {
9233 goto finish;
9234 }
9235 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9236 if (checkClass->getInstanceCount()) {
9237 OSKextLog(this,
9238 msgLogSpec,
9239 " Kext %s class %s has %d instance%s.",
9240 getIdentifierCString(),
9241 checkClass->getClassName(),
9242 checkClass->getInstanceCount(),
9243 checkClass->getInstanceCount() == 1 ? "" : "s");
9244 }
9245 }
9246
9247 finish:
9248 return;
9249 }
9250
9251 #if PRAGMA_MARK
9252 #pragma mark User-Space Requests
9253 #endif
9254
9255 static kern_return_t
9256 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9257 {
9258 OSReturn result = kOSReturnSuccess;
9259 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9260 OSDictionary * request = NULL; //do not release
9261 IOUserServerCheckInToken * token = NULL; //do not release
9262 OSString * requestPredicate = NULL; //do not release
9263 OSSharedPtr<OSNumber> portNameNumber;
9264 mach_port_name_t portName = 0;
9265 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9266 if (!request) {
9267 OSKextLog(/* kext */ NULL,
9268 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9269 "Elements of request should be of type OSDictionary");
9270 result = kOSKextReturnInternalError;
9271 goto finish;
9272 }
9273 requestPredicate = _OSKextGetRequestPredicate(request);
9274 if (!requestPredicate) {
9275 OSKextLog(/* kext */ NULL,
9276 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9277 "Failed to get request predicate");
9278 result = kOSKextReturnInternalError;
9279 goto finish;
9280 }
9281 // is this a dext launch?
9282 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9283 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9284 if (!token) {
9285 OSKextLog(/* kext */ NULL,
9286 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9287 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9288 result = kOSKextReturnInternalError;
9289 goto finish;
9290 }
9291 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9292 if (portName == 0 || portName == MACH_PORT_DEAD) {
9293 OSKextLog(/* kext */ NULL,
9294 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9295 "Could not create send right for object.");
9296 result = kOSKextReturnInternalError;
9297 goto finish;
9298 }
9299 // Store the mach port name as a OSNumber
9300 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9301 if (!portNameNumber) {
9302 OSKextLog(/* kext */ NULL,
9303 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9304 "Could not create OSNumber object.");
9305 result = kOSKextReturnNoMemory;
9306 goto finish;
9307 }
9308 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9309 OSKextLog(/* kext */ NULL,
9310 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9311 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9312 result = kOSKextReturnNoMemory;
9313 goto finish;
9314 }
9315 }
9316 finish:
9317 if (result != kOSReturnSuccess) {
9318 break;
9319 }
9320 }
9321 return result;
9322 }
9323
9324 /*********************************************************************
9325 * XXX - this function is a big ugly mess
9326 *********************************************************************/
9327 /* static */
9328 OSReturn
9329 OSKext::handleRequest(
9330 host_priv_t hostPriv,
9331 OSKextLogSpec clientLogFilter,
9332 char * requestBuffer,
9333 uint32_t requestLength,
9334 char ** responseOut,
9335 uint32_t * responseLengthOut,
9336 char ** logInfoOut,
9337 uint32_t * logInfoLengthOut)
9338 {
9339 OSReturn result = kOSReturnError;
9340 kern_return_t kmem_result = KERN_FAILURE;
9341
9342 char * response = NULL; // returned by reference
9343 uint32_t responseLength = 0;
9344
9345 bool taskCanManageAllKCs = false;
9346 bool taskOnlyManagesBootKC = false;
9347
9348 OSSharedPtr<OSObject> parsedXML;
9349 OSDictionary * requestDict = NULL; // do not release
9350 OSSharedPtr<OSString> errorString;
9351
9352 OSSharedPtr<OSObject> responseObject;
9353
9354 OSSharedPtr<OSSerialize> serializer;
9355
9356 OSSharedPtr<OSArray> logInfoArray;
9357
9358 OSString * predicate = NULL; // do not release
9359 OSString * kextIdentifier = NULL; // do not release
9360 OSArray * kextIdentifiers = NULL; // do not release
9361 OSKext * theKext = NULL; // do not release
9362 OSBoolean * boolArg = NULL; // do not release
9363
9364 IORecursiveLockLock(sKextLock);
9365
9366 if (responseOut) {
9367 *responseOut = NULL;
9368 *responseLengthOut = 0;
9369 }
9370 if (logInfoOut) {
9371 *logInfoOut = NULL;
9372 *logInfoLengthOut = 0;
9373 }
9374
9375 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9376
9377 /* XML must be nul-terminated.
9378 */
9379 if (requestBuffer[requestLength - 1] != '\0') {
9380 OSKextLog(/* kext */ NULL,
9381 kOSKextLogErrorLevel |
9382 kOSKextLogIPCFlag,
9383 "Invalid request from user space (not nul-terminated).");
9384 result = kOSKextReturnBadData;
9385 goto finish;
9386 }
9387 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
9388 if (parsedXML) {
9389 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
9390 }
9391 if (!requestDict) {
9392 const char * errorCString = "(unknown error)";
9393
9394 if (errorString && errorString->getCStringNoCopy()) {
9395 errorCString = errorString->getCStringNoCopy();
9396 } else if (parsedXML) {
9397 errorCString = "not a dictionary";
9398 }
9399 OSKextLog(/* kext */ NULL,
9400 kOSKextLogErrorLevel |
9401 kOSKextLogIPCFlag,
9402 "Error unserializing request from user space: %s.",
9403 errorCString);
9404 result = kOSKextReturnSerialization;
9405 goto finish;
9406 }
9407
9408 predicate = _OSKextGetRequestPredicate(requestDict);
9409 if (!predicate) {
9410 OSKextLog(/* kext */ NULL,
9411 kOSKextLogErrorLevel |
9412 kOSKextLogIPCFlag,
9413 "Recieved kext request from user space with no predicate.");
9414 result = kOSKextReturnInvalidArgument;
9415 goto finish;
9416 }
9417
9418 OSKextLog(/* kext */ NULL,
9419 kOSKextLogDebugLevel |
9420 kOSKextLogIPCFlag,
9421 "Received '%s' request from user space.",
9422 predicate->getCStringNoCopy());
9423
9424 /*
9425 * All management of file sets requires an entitlement
9426 */
9427 result = kOSKextReturnNotPrivileged;
9428 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9429 predicate->isEqualTo(kKextRequestPredicateStart) ||
9430 predicate->isEqualTo(kKextRequestPredicateStop) ||
9431 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9432 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9433 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9434 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9435 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9436 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9437 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9438 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9439 if (hostPriv == HOST_PRIV_NULL) {
9440 OSKextLog(/* kext */ NULL,
9441 kOSKextLogErrorLevel |
9442 kOSKextLogIPCFlag,
9443 "Access Failure - must be root user.");
9444 goto finish;
9445 }
9446 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
9447 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9448
9449 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9450 OSKextLog(/* kext */ NULL,
9451 kOSKextLogErrorLevel |
9452 kOSKextLogIPCFlag,
9453 "Access Failure - client not entitled to manage file sets.");
9454 goto finish;
9455 }
9456
9457 /*
9458 * The OnlyBootKC entitlement restricts the
9459 * collection-management entitlement to only managing kexts in
9460 * the BootKC. All other predicates that alter global state or
9461 * add new KCs are disallowed.
9462 */
9463 if (taskOnlyManagesBootKC &&
9464 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9465 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9466 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9467 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9468 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9469 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9470 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9471 OSKextLog(/* kext */ NULL,
9472 kOSKextLogErrorLevel |
9473 kOSKextLogIPCFlag,
9474 "Access Failure - client not entitled to manage non-primary KCs");
9475 goto finish;
9476 }
9477
9478 /*
9479 * If we get here, then the process either has the full KC
9480 * management entitlement, or it has the BootKC-only
9481 * entitlement and the request is about the BootKC.
9482 */
9483 }
9484
9485 /* Get common args in anticipation of use.
9486 */
9487 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9488 requestDict, kKextRequestArgumentBundleIdentifierKey));
9489 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9490 requestDict, kKextRequestArgumentBundleIdentifierKey));
9491 if (kextIdentifier) {
9492 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9493 }
9494 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9495 requestDict, kKextRequestArgumentValueKey));
9496
9497 if (taskOnlyManagesBootKC &&
9498 theKext &&
9499 theKext->isInFileset() &&
9500 theKext->kc_type != KCKindPrimary) {
9501 OSKextLog(/* kext */ NULL,
9502 kOSKextLogErrorLevel |
9503 kOSKextLogIPCFlag,
9504 "Access Failure - client not entitled to manage kext in non-primary KC");
9505 result = kOSKextReturnNotPrivileged;
9506 goto finish;
9507 }
9508
9509 result = kOSKextReturnInvalidArgument;
9510
9511 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9512 if (!kextIdentifier) {
9513 OSKextLog(/* kext */ NULL,
9514 kOSKextLogErrorLevel |
9515 kOSKextLogIPCFlag,
9516 "Invalid arguments to kext start request.");
9517 } else if (!theKext) {
9518 OSKextLog(/* kext */ NULL,
9519 kOSKextLogErrorLevel |
9520 kOSKextLogIPCFlag,
9521 "Kext %s not found for start request.",
9522 kextIdentifier->getCStringNoCopy());
9523 result = kOSKextReturnNotFound;
9524 } else {
9525 result = theKext->start();
9526 }
9527 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9528 if (!kextIdentifier) {
9529 OSKextLog(/* kext */ NULL,
9530 kOSKextLogErrorLevel |
9531 kOSKextLogIPCFlag,
9532 "Invalid arguments to kext stop request.");
9533 } else if (!theKext) {
9534 OSKextLog(/* kext */ NULL,
9535 kOSKextLogErrorLevel |
9536 kOSKextLogIPCFlag,
9537 "Kext %s not found for stop request.",
9538 kextIdentifier->getCStringNoCopy());
9539 result = kOSKextReturnNotFound;
9540 } else {
9541 result = theKext->stop();
9542 }
9543 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9544 result = OSKext::setMissingAuxKCBundles(requestDict);
9545 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9546 if (!kextIdentifier) {
9547 OSKextLog(/* kext */ NULL,
9548 kOSKextLogErrorLevel |
9549 kOSKextLogIPCFlag,
9550 "Invalid arguments to AuxKC Bundle Available request.");
9551 } else {
9552 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9553 }
9554 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9555 if (!kextIdentifier) {
9556 OSKextLog(/* kext */ NULL,
9557 kOSKextLogErrorLevel |
9558 kOSKextLogIPCFlag,
9559 "Invalid arguments to kext load from KC request.");
9560 } else if (!theKext) {
9561 OSKextLog(/* kext */ NULL,
9562 kOSKextLogErrorLevel |
9563 kOSKextLogIPCFlag,
9564 "Kext %s not found for load from KC request.",
9565 kextIdentifier->getCStringNoCopy());
9566 result = kOSKextReturnNotFound;
9567 } else if (!theKext->isInFileset()) {
9568 OSKextLog(/* kext */ NULL,
9569 kOSKextLogErrorLevel |
9570 kOSKextLogIPCFlag,
9571 "Kext %s does not exist in a KC: refusing to load.",
9572 kextIdentifier->getCStringNoCopy());
9573 result = kOSKextReturnNotLoadable;
9574 } else {
9575 result = OSKext::loadKextFromKC(theKext, requestDict);
9576 }
9577 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9578 if (!kextIdentifier) {
9579 OSKextLog(/* kext */ NULL,
9580 kOSKextLogErrorLevel |
9581 kOSKextLogIPCFlag,
9582 "Invalid arguments to codeless kext load interface (missing identifier).");
9583 } else {
9584 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9585 }
9586 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9587 if (!kextIdentifier) {
9588 OSKextLog(/* kext */ NULL,
9589 kOSKextLogErrorLevel |
9590 kOSKextLogIPCFlag,
9591 "Invalid arguments to kext unload request.");
9592 } else if (!theKext) {
9593 OSKextLog(/* kext */ NULL,
9594 kOSKextLogErrorLevel |
9595 kOSKextLogIPCFlag,
9596 "Kext %s not found for unload request.",
9597 kextIdentifier->getCStringNoCopy());
9598 result = kOSKextReturnNotFound;
9599 } else {
9600 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9601 _OSKextGetRequestArgument(requestDict,
9602 kKextRequestArgumentTerminateIOServicesKey));
9603 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9604 }
9605 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9606 result = OSKext::dispatchResource(requestDict);
9607 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9608 OSNumber *lookupNum = NULL;
9609 lookupNum = OSDynamicCast(OSNumber,
9610 _OSKextGetRequestArgument(requestDict,
9611 kKextRequestArgumentLookupAddressKey));
9612
9613 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9614 if (responseObject) {
9615 result = kOSReturnSuccess;
9616 } else {
9617 goto finish;
9618 }
9619 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
9620 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9621 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9622 OSBoolean * delayAutounloadBool = NULL;
9623 OSObject * infoKeysRaw = NULL;
9624 OSArray * infoKeys = NULL;
9625 uint32_t infoKeysCount = 0;
9626
9627 delayAutounloadBool = OSDynamicCast(OSBoolean,
9628 _OSKextGetRequestArgument(requestDict,
9629 kKextRequestArgumentDelayAutounloadKey));
9630
9631 /* If asked to delay autounload, reset the timer if it's currently set.
9632 * (That is, don't schedule an unload if one isn't already pending.
9633 */
9634 if (delayAutounloadBool == kOSBooleanTrue) {
9635 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9636 }
9637
9638 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9639 kKextRequestArgumentInfoKeysKey);
9640 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9641 if (infoKeysRaw && !infoKeys) {
9642 OSKextLog(/* kext */ NULL,
9643 kOSKextLogErrorLevel |
9644 kOSKextLogIPCFlag,
9645 "Invalid arguments to kext info request.");
9646 goto finish;
9647 }
9648
9649 if (infoKeys) {
9650 infoKeysCount = infoKeys->getCount();
9651 for (uint32_t i = 0; i < infoKeysCount; i++) {
9652 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9653 OSKextLog(/* kext */ NULL,
9654 kOSKextLogErrorLevel |
9655 kOSKextLogIPCFlag,
9656 "Invalid arguments to kext info request.");
9657 goto finish;
9658 }
9659 }
9660 }
9661
9662 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9663 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9664 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9665 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
9666 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9667 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
9668 }
9669
9670 if (!responseObject) {
9671 result = kOSKextReturnInternalError;
9672 } else {
9673 OSKextLog(/* kext */ NULL,
9674 kOSKextLogDebugLevel |
9675 kOSKextLogIPCFlag,
9676 "Returning loaded kext info.");
9677 result = kOSReturnSuccess;
9678 }
9679 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9680 /* Hand the current sKernelRequests array to the caller
9681 * (who must release it), and make a new one.
9682 */
9683 responseObject = os::move(sKernelRequests);
9684 sKernelRequests = OSArray::withCapacity(0);
9685 sPostedKextLoadIdentifiers->flushCollection();
9686 OSKextLog(/* kext */ NULL,
9687 kOSKextLogDebugLevel |
9688 kOSKextLogIPCFlag,
9689 "Returning kernel requests.");
9690 result = kOSReturnSuccess;
9691 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9692 /* Return the set of all requested bundle identifiers */
9693 responseObject = sAllKextLoadIdentifiers;
9694 OSKextLog(/* kext */ NULL,
9695 kOSKextLogDebugLevel |
9696 kOSKextLogIPCFlag,
9697 "Returning load requests.");
9698 result = kOSReturnSuccess;
9699 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9700 printf("KextLog: Loading FileSet KC(s)\n");
9701 result = OSKext::loadFileSetKexts(requestDict);
9702 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9703 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9704 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
9705 } else {
9706 OSKextLog(/* kext */ NULL,
9707 kOSKextLogDebugLevel |
9708 kOSKextLogIPCFlag,
9709 "Received '%s' invalid request from user space.",
9710 predicate->getCStringNoCopy());
9711 goto finish;
9712 }
9713
9714 /**********
9715 * Now we have handle the request, or not. Gather up the response & logging
9716 * info to ship to user space.
9717 *********/
9718
9719 /* Note: Nothing in OSKext is supposed to retain requestDict,
9720 * but you never know....
9721 */
9722 if (requestDict->getRetainCount() > 1) {
9723 OSKextLog(/* kext */ NULL,
9724 kOSKextLogWarningLevel |
9725 kOSKextLogIPCFlag,
9726 "Request from user space still retained by a kext; "
9727 "probable memory leak.");
9728 }
9729
9730 if (responseOut && responseObject) {
9731 serializer = OSSerialize::withCapacity(0);
9732 if (!serializer) {
9733 result = kOSKextReturnNoMemory;
9734 goto finish;
9735 }
9736 /*
9737 * Before serializing the kernel requests, patch the dext launch requests so
9738 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9739 * IOUserServerCheckInToken kernel object.
9740 */
9741 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9742 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9743 task_t calling_task = current_task();
9744 if (!requests) {
9745 OSKextLog(/* kext */ NULL,
9746 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9747 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9748 result = kOSKextReturnInternalError;
9749 goto finish;
9750 }
9751 result = patchDextLaunchRequests(calling_task, requests);
9752 if (result != kOSReturnSuccess) {
9753 OSKextLog(/* kext */ NULL,
9754 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9755 "Failed to patch dext launch requests.");
9756 goto finish;
9757 }
9758 }
9759
9760 if (!responseObject->serialize(serializer.get())) {
9761 OSKextLog(/* kext */ NULL,
9762 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9763 "Failed to serialize response to request from user space.");
9764 result = kOSKextReturnSerialization;
9765 goto finish;
9766 }
9767
9768 response = (char *)serializer->text();
9769 responseLength = serializer->getLength();
9770 }
9771
9772 if (responseOut && response) {
9773 char * buffer;
9774
9775 /* This kmem_alloc sets the return value of the function.
9776 */
9777 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9778 round_page(responseLength), KMA_DATA, VM_KERN_MEMORY_OSKEXT);
9779 if (kmem_result != KERN_SUCCESS) {
9780 OSKextLog(/* kext */ NULL,
9781 kOSKextLogErrorLevel |
9782 kOSKextLogIPCFlag,
9783 "Failed to copy response to request from user space.");
9784 result = kmem_result;
9785 goto finish;
9786 } else {
9787 /* 11981737 - clear uninitialized data in last page */
9788 bzero((void *)(buffer + responseLength),
9789 (round_page(responseLength) - responseLength));
9790 memcpy(buffer, response, responseLength);
9791 *responseOut = buffer;
9792 *responseLengthOut = responseLength;
9793 }
9794 }
9795
9796 finish:
9797
9798 /* Gather up the collected log messages for user space. Any messages
9799 * messages past this call will not make it up as log messages but
9800 * will be in the system log. Note that we ignore the return of the
9801 * serialize; it has no bearing on the operation at hand even if we
9802 * fail to get the log messages.
9803 */
9804 logInfoArray = OSKext::clearUserSpaceLogFilter();
9805
9806 if (logInfoArray && logInfoOut && logInfoLengthOut) {
9807 (void)OSKext::serializeLogInfo(logInfoArray.get(),
9808 logInfoOut, logInfoLengthOut);
9809 }
9810
9811 IORecursiveLockUnlock(sKextLock);
9812
9813 return result;
9814 }
9815
9816 #if PRAGMA_MARK
9817 #pragma mark Linked Kext Collection Support
9818 #endif
9819
9820 static int
9821 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9822 {
9823 for (int i = 0; i < segCount; i++) {
9824 vm_offset_t segStart = segAddrs[i];
9825 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9826
9827 if (theAddr >= segStart && theAddr < segEnd) {
9828 return i;
9829 }
9830 }
9831 return -1;
9832 }
9833
9834 static void
9835 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
9836 kernel_segment_command_t *kextTextSeg,
9837 OSData *kaslrOffsets)
9838 {
9839 static const char *plk_segNames[] = {
9840 "__TEXT",
9841 "__TEXT_EXEC",
9842 "__DATA",
9843 "__DATA_CONST",
9844 "__LINKEDIT",
9845 "__PRELINK_TEXT",
9846 "__PLK_TEXT_EXEC",
9847 "__PRELINK_DATA",
9848 "__PLK_DATA_CONST",
9849 "__PLK_LLVM_COV",
9850 "__PLK_LINKEDIT",
9851 "__PRELINK_INFO"
9852 };
9853 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9854
9855 unsigned long plk_segSizes[num_plk_seg];
9856 vm_offset_t plk_segAddrs[num_plk_seg];
9857
9858 for (size_t i = 0; i < num_plk_seg; i++) {
9859 plk_segSizes[i] = 0;
9860 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9861 }
9862
9863 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9864
9865 int slidKextAddrCount = 0;
9866 int badSlideAddr = 0;
9867 int badSlideTarget = 0;
9868
9869 struct kaslrPackedOffsets {
9870 uint32_t count; /* number of offsets */
9871 uint32_t offsetsArray[]; /* offsets to slide */
9872 };
9873 const struct kaslrPackedOffsets *myOffsets = NULL;
9874 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9875
9876 for (uint32_t j = 0; j < myOffsets->count; j++) {
9877 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9878 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9879 int slideAddrSegIndex = -1;
9880 int addrToSlideSegIndex = -1;
9881
9882 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9883 if (slideAddrSegIndex >= 0) {
9884 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9885 if (addrToSlideSegIndex < 0) {
9886 badSlideTarget++;
9887 continue;
9888 }
9889 } else {
9890 badSlideAddr++;
9891 continue;
9892 }
9893
9894 slidKextAddrCount++;
9895 *slideAddr = ml_static_slide(*slideAddr);
9896 } // for ...
9897 }
9898
9899
9900
9901 /********************************************************************
9902 * addKextsFromKextCollection
9903 *
9904 * Input: MachO header of kext collection. The MachO is assumed to
9905 * have a section named 'info_seg_name,info_sect_name' that
9906 * contains a serialized XML info dictionary. This dictionary
9907 * contains a UUID, possibly a set of relocations (for older
9908 * kxld-built binaries), and an array of kext personalities.
9909 *
9910 ********************************************************************/
9911 bool
9912 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9913 OSDictionary *infoDict, const char *text_seg_name,
9914 OSData **kcUUID, kc_kind_t type)
9915 {
9916 bool result = false;
9917
9918 OSArray *kextArray = NULL; // do not release
9919 OSData *infoDictKCUUID = NULL; // do not release
9920 OSData *kaslrOffsets = NULL; // do not release
9921
9922 IORegistryEntry *registryRoot = NULL; // do not release
9923 OSSharedPtr<OSNumber> kcKextCount;
9924
9925 /* extract the KC UUID from the dictionary */
9926 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9927 if (infoDictKCUUID) {
9928 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9929 panic("kcUUID length is %d, expected %lu",
9930 infoDictKCUUID->getLength(), sizeof(uuid_t));
9931 }
9932 }
9933
9934 /* locate the array of kext dictionaries */
9935 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9936 if (!kextArray) {
9937 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9938 "The given KC has no kext info dictionaries");
9939 goto finish;
9940 }
9941
9942 /*
9943 * old-style KASLR offsets may be present in the info dictionary. If
9944 * we find them, use them and eventually slide them.
9945 */
9946 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9947
9948 /*
9949 * Before processing any kexts, locate the special kext bundle which
9950 * contains a list of kexts that we are to prevent from loading.
9951 */
9952 createExcludeListFromPrelinkInfo(kextArray);
9953
9954 /*
9955 * Create OSKext objects for each kext we find in the array of kext
9956 * info plist dictionaries.
9957 */
9958 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9959 OSDictionary *kextDict = NULL;
9960 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9961 if (!kextDict) {
9962 OSKextLog(/* kext */ NULL,
9963 kOSKextLogErrorLevel |
9964 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9965 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9966 continue;
9967 }
9968
9969 /*
9970 * Create the kext for the entry, then release it, because the
9971 * kext system keeps a reference around until the kext is
9972 * explicitly removed. Any creation/registration failures are
9973 * already logged for us.
9974 */
9975 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9976 }
9977
9978 /*
9979 * slide old-style kxld relocations
9980 * NOTE: this is still used on embedded KCs built with kcgen
9981 * TODO: Remove this once we use the new kext linker everywhere!
9982 */
9983 if (kaslrOffsets && vm_kernel_slide > 0) {
9984 kernel_segment_command_t *text_segment = NULL;
9985 text_segment = getsegbynamefromheader(mh, text_seg_name);
9986 if (!text_segment) {
9987 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9988 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9989 goto finish;
9990 }
9991
9992 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9993 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9994 setAllVMAttributes();
9995 }
9996
9997 /* Store the number of prelinked kexts in the registry so we can tell
9998 * when the system has been started from a prelinked kernel.
9999 */
10000 registryRoot = IORegistryEntry::getRegistryRoot();
10001 assert(registryRoot);
10002
10003 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10004 assert(kcKextCount);
10005 if (kcKextCount) {
10006 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10007 OSNumber *num;
10008 num = OSDynamicCast(OSNumber, prop.get());
10009 if (num) {
10010 kcKextCount->addValue(num->unsigned64BitValue());
10011 }
10012 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10013 }
10014
10015 OSKextLog(/* kext */ NULL,
10016 kOSKextLogProgressLevel |
10017 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10018 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10019 "%u prelinked kexts", infoDict->getCount());
10020
10021
10022 if (kcUUID && infoDictKCUUID) {
10023 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10024 }
10025
10026 result = true;
10027
10028 finish:
10029 return result;
10030 }
10031
10032 bool
10033 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10034 OSDictionary *infoDict, const char *text_seg_name,
10035 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10036 {
10037 OSData *result = NULL;
10038 bool success = addKextsFromKextCollection(mh,
10039 infoDict,
10040 text_seg_name,
10041 &result,
10042 type);
10043 if (success) {
10044 kcUUID.reset(result, OSNoRetain);
10045 }
10046 return success;
10047 }
10048
10049 static OSSharedPtr<OSObject> deferredAuxKCXML;
10050 bool
10051 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10052 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10053 {
10054 if (type != KCKindAuxiliary) {
10055 return false;
10056 }
10057
10058 kernel_mach_header_t *_mh;
10059 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
10060 if (!_mh || _mh != mh) {
10061 return false;
10062 }
10063
10064 if (deferredAuxKCXML) {
10065 /* only allow this to be called once */
10066 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10067 "An Aux KC has already been registered for deferred processing.");
10068 return false;
10069 }
10070
10071 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
10072 if (!infoDict) {
10073 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10074 "The Aux KC has info dictionary");
10075 return false;
10076 }
10077
10078 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10079 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10080 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10081 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10082 return false;
10083 }
10084
10085 /*
10086 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10087 * sysctl can return the UUID to user space which will check this
10088 * value for errors.
10089 */
10090 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10091 kcUUID->getLength());
10092 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10093 auxkc_uuid_valid = TRUE;
10094
10095 deferredAuxKCXML = parsedXML;
10096
10097 return true;
10098 }
10099
10100 OSSharedPtr<OSObject>
10101 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10102 {
10103 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10104 return NULL;
10105 }
10106
10107 return os::move(deferredAuxKCXML);
10108 }
10109
10110 #if PRAGMA_MARK
10111 #pragma mark Profile-Guided-Optimization Support
10112 #endif
10113
10114 // #include <InstrProfiling.h>
10115 extern "C" {
10116 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10117 const char *DataEnd,
10118 const char *CountersBegin,
10119 const char *CountersEnd,
10120 const char *NamesBegin,
10121 const char *NamesEnd);
10122 int __llvm_profile_write_buffer_internal(char *Buffer,
10123 const char *DataBegin,
10124 const char *DataEnd,
10125 const char *CountersBegin,
10126 const char *CountersEnd,
10127 const char *NamesBegin,
10128 const char *NamesEnd);
10129 }
10130
10131
10132 static
10133 void
10134 OSKextPgoMetadataPut(char *pBuffer,
10135 size_t *position,
10136 size_t bufferSize,
10137 uint32_t *num_pairs,
10138 const char *key,
10139 const char *value)
10140 {
10141 size_t strlen_key = strlen(key);
10142 size_t strlen_value = strlen(value);
10143 size_t len = strlen(key) + 1 + strlen(value) + 1;
10144 char *pos = pBuffer + *position;
10145 *position += len;
10146 if (pBuffer && bufferSize && *position <= bufferSize) {
10147 memcpy(pos, key, strlen_key); pos += strlen_key;
10148 *(pos++) = '=';
10149 memcpy(pos, value, strlen_value); pos += strlen_value;
10150 *(pos++) = 0;
10151 if (num_pairs) {
10152 (*num_pairs)++;
10153 }
10154 }
10155 }
10156
10157
10158 static
10159 void
10160 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10161 {
10162 *position += strlen(key) + 1 + value_max + 1;
10163 }
10164
10165
10166 static
10167 void
10168 OSKextPgoMetadataPutAll(OSKext *kext,
10169 uuid_t instance_uuid,
10170 char *pBuffer,
10171 size_t *position,
10172 size_t bufferSize,
10173 uint32_t *num_pairs)
10174 {
10175 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10176 //log_10 2^16 ≈ 4.82
10177 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10178 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10179
10180 if (!pBuffer) {
10181 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10182 OSKextPgoMetadataPutMax(position, "UUID", 36);
10183 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10184 } else {
10185 uuid_string_t instance_uuid_string;
10186 uuid_unparse(instance_uuid, instance_uuid_string);
10187 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10188 "INSTANCE", instance_uuid_string);
10189
10190 OSSharedPtr<OSData> uuid_data;
10191 uuid_t uuid;
10192 uuid_string_t uuid_string;
10193 uuid_data = kext->copyUUID();
10194 if (uuid_data) {
10195 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10196 uuid_unparse(uuid, uuid_string);
10197 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10198 "UUID", uuid_string);
10199 }
10200
10201 clock_sec_t secs;
10202 clock_usec_t usecs;
10203 clock_get_calendar_microtime(&secs, &usecs);
10204 assert(usecs < 1000000);
10205 char timestamp[max_timestamp_string_size + 1];
10206 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10207 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10208 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10209 "TIMESTAMP", timestamp);
10210 }
10211
10212 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10213 "NAME", kext->getIdentifierCString());
10214
10215 char versionCString[kOSKextVersionMaxLength];
10216 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10217 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10218 "VERSION", versionCString);
10219 }
10220
10221 static
10222 size_t
10223 OSKextPgoMetadataSize(OSKext *kext)
10224 {
10225 size_t position = 0;
10226 uuid_t fakeuuid = {};
10227 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10228 return position;
10229 }
10230
10231 int
10232 OSKextGrabPgoDataLocked(OSKext *kext,
10233 bool metadata,
10234 uuid_t instance_uuid,
10235 uint64_t *pSize,
10236 char *pBuffer,
10237 uint64_t bufferSize)
10238 {
10239 int err = 0;
10240
10241 kernel_section_t *sect_prf_data = NULL;
10242 kernel_section_t *sect_prf_name = NULL;
10243 kernel_section_t *sect_prf_cnts = NULL;
10244 uint64_t size;
10245 size_t metadata_size = 0;
10246 size_t offset_to_pairs = 0;
10247
10248 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10249 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10250 if (!sect_prf_name) {
10251 // kextcache sometimes truncates the section name to 15 chars
10252 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10253 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10254 }
10255 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10256
10257 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10258 err = ENOTSUP;
10259 goto out;
10260 }
10261
10262 size = __llvm_profile_get_size_for_buffer_internal(
10263 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10264 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10265 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10266
10267 if (metadata) {
10268 metadata_size = OSKextPgoMetadataSize(kext);
10269 size += metadata_size;
10270 size += sizeof(pgo_metadata_footer);
10271 }
10272
10273
10274 if (pSize) {
10275 *pSize = size;
10276 }
10277
10278 if (pBuffer && bufferSize) {
10279 if (bufferSize < size) {
10280 err = ERANGE;
10281 goto out;
10282 }
10283
10284 err = __llvm_profile_write_buffer_internal(
10285 pBuffer,
10286 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10287 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10288 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10289
10290 if (err) {
10291 err = EIO;
10292 goto out;
10293 }
10294
10295 if (metadata) {
10296 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10297 if (offset_to_pairs > UINT32_MAX) {
10298 err = E2BIG;
10299 goto out;
10300 }
10301
10302 char *end_of_buffer = pBuffer + size;
10303 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10304 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10305
10306 size_t metadata_position = 0;
10307 uint32_t num_pairs = 0;
10308 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10309 while (metadata_position < metadata_size) {
10310 metadata_buffer[metadata_position++] = 0;
10311 }
10312
10313 struct pgo_metadata_footer footer;
10314 footer.magic = htonl(0x6d657461);
10315 footer.number_of_pairs = htonl( num_pairs );
10316 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
10317 memcpy(footerp, &footer, sizeof(footer));
10318 }
10319 }
10320
10321 out:
10322 return err;
10323 }
10324
10325
10326 int
10327 OSKextGrabPgoData(uuid_t uuid,
10328 uint64_t *pSize,
10329 char *pBuffer,
10330 uint64_t bufferSize,
10331 int wait_for_unload,
10332 int metadata)
10333 {
10334 int err = 0;
10335 OSSharedPtr<OSKext> kext;
10336
10337
10338 IORecursiveLockLock(sKextLock);
10339
10340 kext = OSKext::lookupKextWithUUID(uuid);
10341 if (!kext) {
10342 err = ENOENT;
10343 goto out;
10344 }
10345
10346 if (wait_for_unload) {
10347 OSKextGrabPgoStruct s;
10348
10349 s.metadata = metadata;
10350 s.pSize = pSize;
10351 s.pBuffer = pBuffer;
10352 s.bufferSize = bufferSize;
10353 s.err = EINTR;
10354
10355 struct list_head *prev = &kext->pendingPgoHead;
10356 struct list_head *next = kext->pendingPgoHead.next;
10357
10358 s.list_head.prev = prev;
10359 s.list_head.next = next;
10360
10361 prev->next = &s.list_head;
10362 next->prev = &s.list_head;
10363
10364 kext.reset();
10365
10366 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
10367
10368 prev = s.list_head.prev;
10369 next = s.list_head.next;
10370
10371 prev->next = next;
10372 next->prev = prev;
10373
10374 err = s.err;
10375 } else {
10376 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
10377 }
10378
10379 out:
10380
10381 IORecursiveLockUnlock(sKextLock);
10382
10383 return err;
10384 }
10385
10386 void
10387 OSKextResetPgoCountersLock()
10388 {
10389 IORecursiveLockLock(sKextLock);
10390 }
10391
10392 void
10393 OSKextResetPgoCountersUnlock()
10394 {
10395 IORecursiveLockUnlock(sKextLock);
10396 }
10397
10398
10399 extern unsigned int not_in_kdp;
10400
10401 void
10402 OSKextResetPgoCounters()
10403 {
10404 assert(!not_in_kdp);
10405 uint32_t count = sLoadedKexts->getCount();
10406 for (uint32_t i = 0; i < count; i++) {
10407 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10408 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10409 if (!sect_prf_cnts) {
10410 continue;
10411 }
10412 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10413 }
10414 }
10415
10416 OSSharedPtr<OSDictionary>
10417 OSKext::copyLoadedKextInfoByUUID(
10418 OSArray * kextIdentifiers,
10419 OSArray * infoKeys)
10420 {
10421 OSSharedPtr<OSDictionary> result;
10422 OSSharedPtr<OSDictionary> kextInfo;
10423 uint32_t max_count, i, j;
10424 uint32_t idCount = 0;
10425 uint32_t idIndex = 0;
10426 IORecursiveLockLock(sKextLock);
10427 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
10428 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
10429
10430 #if CONFIG_MACF
10431 /* Is the calling process allowed to query kext info? */
10432 if (current_task() != kernel_task) {
10433 int macCheckResult = 0;
10434 kauth_cred_t cred = NULL;
10435
10436 cred = kauth_cred_get_with_ref();
10437 macCheckResult = mac_kext_check_query(cred);
10438 kauth_cred_unref(&cred);
10439
10440 if (macCheckResult != 0) {
10441 OSKextLog(/* kext */ NULL,
10442 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10443 "Failed to query kext info (MAC policy error 0x%x).",
10444 macCheckResult);
10445 goto finish;
10446 }
10447 }
10448 #endif
10449
10450 /* Empty list of UUIDs is equivalent to no list (get all).
10451 */
10452 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10453 kextIdentifiers = NULL;
10454 } else if (kextIdentifiers) {
10455 idCount = kextIdentifiers->getCount();
10456 }
10457
10458 /* Same for keys.
10459 */
10460 if (infoKeys && !infoKeys->getCount()) {
10461 infoKeys = NULL;
10462 }
10463
10464 max_count = count[0] + count[1];
10465 result = OSDictionary::withCapacity(max_count);
10466 if (!result) {
10467 goto finish;
10468 }
10469
10470 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10471 for (i = 0; i < count[j]; i++) {
10472 OSKext *thisKext = NULL; // do not release
10473 Boolean includeThis = true;
10474 uuid_t thisKextUUID;
10475 uuid_t thisKextTextUUID;
10476 OSSharedPtr<OSData> uuid_data;
10477 uuid_string_t uuid_key;
10478
10479 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10480 if (!thisKext) {
10481 continue;
10482 }
10483
10484 uuid_data = thisKext->copyUUID();
10485 if (!uuid_data) {
10486 continue;
10487 }
10488
10489 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
10490
10491 uuid_unparse(thisKextUUID, uuid_key);
10492
10493 uuid_data = thisKext->copyTextUUID();
10494 if (!uuid_data) {
10495 continue;
10496 }
10497 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
10498
10499 /* Skip current kext if we have a list of UUIDs and
10500 * it isn't in the list.
10501 */
10502 if (kextIdentifiers) {
10503 includeThis = false;
10504
10505 for (idIndex = 0; idIndex < idCount; idIndex++) {
10506 const OSString* wantedUUID = OSDynamicCast(OSString,
10507 kextIdentifiers->getObject(idIndex));
10508
10509 uuid_t uuid;
10510 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10511
10512 if ((0 == uuid_compare(uuid, thisKextUUID))
10513 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10514 includeThis = true;
10515 /* Only need to find the first kext if multiple match,
10516 * ie. asking for the kernel uuid does not need to find
10517 * interface kexts or builtin static kexts.
10518 */
10519 kextIdentifiers->removeObject(idIndex);
10520 uuid_unparse(uuid, uuid_key);
10521 break;
10522 }
10523 }
10524 }
10525
10526 if (!includeThis) {
10527 continue;
10528 }
10529
10530 kextInfo = thisKext->copyInfo(infoKeys);
10531 if (kextInfo) {
10532 result->setObject(uuid_key, kextInfo.get());
10533 }
10534
10535 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10536 goto finish;
10537 }
10538 }
10539 }
10540
10541 finish:
10542 IORecursiveLockUnlock(sKextLock);
10543
10544 return result;
10545 }
10546
10547 /*********************************************************************
10548 *********************************************************************/
10549 /* static */
10550 OSSharedPtr<OSDictionary>
10551 OSKext::copyKextCollectionInfo(
10552 OSDictionary *requestDict,
10553 OSArray *infoKeys)
10554 {
10555 OSSharedPtr<OSDictionary> result;
10556 OSString *collectionType = NULL;
10557 OSObject *rawLoadedState = NULL;
10558 OSString *loadedState = NULL;
10559
10560 kc_kind_t kc_request_kind = KCKindUnknown;
10561 bool onlyLoaded = false;
10562 bool onlyUnloaded = false;
10563
10564 #if CONFIG_MACF
10565 /* Is the calling process allowed to query kext info? */
10566 if (current_task() != kernel_task) {
10567 int macCheckResult = 0;
10568 kauth_cred_t cred = NULL;
10569
10570 cred = kauth_cred_get_with_ref();
10571 macCheckResult = mac_kext_check_query(cred);
10572 kauth_cred_unref(&cred);
10573
10574 if (macCheckResult != 0) {
10575 OSKextLog(/* kext */ NULL,
10576 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10577 "Failed to query kext info (MAC policy error 0x%x).",
10578 macCheckResult);
10579 goto finish;
10580 }
10581 }
10582 #endif
10583
10584 if (infoKeys && !infoKeys->getCount()) {
10585 infoKeys = NULL;
10586 }
10587
10588 collectionType = OSDynamicCast(OSString,
10589 _OSKextGetRequestArgument(requestDict,
10590 kKextRequestArgumentCollectionTypeKey));
10591 if (!collectionType) {
10592 OSKextLog(/* kext */ NULL,
10593 kOSKextLogErrorLevel |
10594 kOSKextLogIPCFlag,
10595 "Invalid '%s' argument to kext collection info request.",
10596 kKextRequestArgumentCollectionTypeKey);
10597 goto finish;
10598 }
10599 if (collectionType->isEqualTo(kKCTypePrimary)) {
10600 kc_request_kind = KCKindPrimary;
10601 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10602 kc_request_kind = KCKindPageable;
10603 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10604 kc_request_kind = KCKindAuxiliary;
10605 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10606 kc_request_kind = KCKindNone;
10607 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10608 OSKextLog(/* kext */ NULL,
10609 kOSKextLogErrorLevel |
10610 kOSKextLogIPCFlag,
10611 "Invalid '%s' argument value '%s' to kext collection info request.",
10612 kKextRequestArgumentCollectionTypeKey,
10613 collectionType->getCStringNoCopy());
10614 goto finish;
10615 }
10616
10617 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10618 kKextRequestArgumentLoadedStateKey);
10619 if (rawLoadedState) {
10620 loadedState = OSDynamicCast(OSString, rawLoadedState);
10621 if (!loadedState) {
10622 OSKextLog(/* kext */ NULL,
10623 kOSKextLogErrorLevel |
10624 kOSKextLogIPCFlag,
10625 "Invalid '%s' argument to kext collection info request.",
10626 kKextRequestArgumentLoadedStateKey);
10627 goto finish;
10628 }
10629 }
10630 if (loadedState) {
10631 if (loadedState->isEqualTo("Loaded")) {
10632 onlyLoaded = true;
10633 } else if (loadedState->isEqualTo("Unloaded")) {
10634 onlyUnloaded = true;
10635 } else if (!loadedState->isEqualTo("Any")) {
10636 OSKextLog(/* kext */ NULL,
10637 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10638 "Invalid '%s' argument value '%s' for '%s' collection info",
10639 kKextRequestArgumentLoadedStateKey,
10640 loadedState->getCStringNoCopy(),
10641 collectionType->getCStringNoCopy());
10642 goto finish;
10643 }
10644 }
10645
10646 result = OSDictionary::withCapacity(sKextsByID->getCount());
10647 if (!result) {
10648 goto finish;
10649 }
10650
10651 IORecursiveLockLock(sKextLock);
10652 { // start block scope
10653 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10654 {
10655 OSKext *thisKext = NULL; // do not release
10656 OSSharedPtr<OSDictionary> kextInfo;
10657
10658 (void)thisKextID;
10659
10660 thisKext = OSDynamicCast(OSKext, obj);
10661 if (!thisKext) {
10662 return false;
10663 }
10664
10665 /*
10666 * skip the kext if it came from the wrong collection type
10667 * (and the caller requested a specific type)
10668 */
10669 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10670 return false;
10671 }
10672
10673 /*
10674 * respect the caller's desire to find only loaded or
10675 * unloaded kexts
10676 */
10677 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10678 return false;
10679 }
10680 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10681 return false;
10682 }
10683
10684 kextInfo = thisKext->copyInfo(infoKeys);
10685 if (kextInfo) {
10686 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10687 }
10688 return false;
10689 });
10690 } // end block scope
10691 IORecursiveLockUnlock(sKextLock);
10692
10693 finish:
10694 return result;
10695 }
10696
10697 /*********************************************************************
10698 *********************************************************************/
10699 /* static */
10700 OSSharedPtr<OSDictionary>
10701 OSKext::copyLoadedKextInfo(
10702 OSArray * kextIdentifiers,
10703 OSArray * infoKeys)
10704 {
10705 OSSharedPtr<OSDictionary> result;
10706 uint32_t idCount = 0;
10707 bool onlyLoaded;
10708
10709 IORecursiveLockLock(sKextLock);
10710
10711 #if CONFIG_MACF
10712 /* Is the calling process allowed to query kext info? */
10713 if (current_task() != kernel_task) {
10714 int macCheckResult = 0;
10715 kauth_cred_t cred = NULL;
10716
10717 cred = kauth_cred_get_with_ref();
10718 macCheckResult = mac_kext_check_query(cred);
10719 kauth_cred_unref(&cred);
10720
10721 if (macCheckResult != 0) {
10722 OSKextLog(/* kext */ NULL,
10723 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10724 "Failed to query kext info (MAC policy error 0x%x).",
10725 macCheckResult);
10726 goto finish;
10727 }
10728 }
10729 #endif
10730
10731 /* Empty list of bundle ids is equivalent to no list (get all).
10732 */
10733 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10734 kextIdentifiers = NULL;
10735 } else if (kextIdentifiers) {
10736 idCount = kextIdentifiers->getCount();
10737 }
10738
10739 /* Same for keys.
10740 */
10741 if (infoKeys && !infoKeys->getCount()) {
10742 infoKeys = NULL;
10743 }
10744
10745 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10746
10747 result = OSDictionary::withCapacity(128);
10748 if (!result) {
10749 goto finish;
10750 }
10751
10752 #if 0
10753 OSKextLog(/* kext */ NULL,
10754 kOSKextLogErrorLevel |
10755 kOSKextLogGeneralFlag,
10756 "kaslr: vm_kernel_slide 0x%lx \n",
10757 vm_kernel_slide);
10758 OSKextLog(/* kext */ NULL,
10759 kOSKextLogErrorLevel |
10760 kOSKextLogGeneralFlag,
10761 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10762 vm_kernel_stext, vm_kernel_etext);
10763 OSKextLog(/* kext */ NULL,
10764 kOSKextLogErrorLevel |
10765 kOSKextLogGeneralFlag,
10766 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10767 vm_kernel_base, vm_kernel_top);
10768 OSKextLog(/* kext */ NULL,
10769 kOSKextLogErrorLevel |
10770 kOSKextLogGeneralFlag,
10771 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10772 vm_kext_base, vm_kext_top);
10773 OSKextLog(/* kext */ NULL,
10774 kOSKextLogErrorLevel |
10775 kOSKextLogGeneralFlag,
10776 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10777 vm_prelink_stext, vm_prelink_etext);
10778 OSKextLog(/* kext */ NULL,
10779 kOSKextLogErrorLevel |
10780 kOSKextLogGeneralFlag,
10781 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10782 vm_prelink_sinfo, vm_prelink_einfo);
10783 OSKextLog(/* kext */ NULL,
10784 kOSKextLogErrorLevel |
10785 kOSKextLogGeneralFlag,
10786 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10787 vm_slinkedit, vm_elinkedit);
10788 #endif
10789 { // start block scope
10790 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10791 {
10792 OSKext * thisKext = NULL; // do not release
10793 Boolean includeThis = true;
10794 OSSharedPtr<OSDictionary> kextInfo;
10795
10796 thisKext = OSDynamicCast(OSKext, obj);
10797 if (!thisKext) {
10798 return false;
10799 }
10800
10801 /* Skip current kext if not yet started and caller didn't request all.
10802 */
10803 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10804 return false;
10805 }
10806
10807 /* Skip current kext if we have a list of bundle IDs and
10808 * it isn't in the list.
10809 */
10810 if (kextIdentifiers) {
10811 includeThis = false;
10812
10813 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10814 const OSString * thisRequestID = OSDynamicCast(OSString,
10815 kextIdentifiers->getObject(idIndex));
10816 if (thisKextID->isEqualTo(thisRequestID)) {
10817 includeThis = true;
10818 break;
10819 }
10820 }
10821 }
10822
10823 if (!includeThis) {
10824 return false;
10825 }
10826
10827 kextInfo = thisKext->copyInfo(infoKeys);
10828 if (kextInfo) {
10829 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10830 }
10831 return false;
10832 });
10833 } // end block scope
10834
10835 finish:
10836 IORecursiveLockUnlock(sKextLock);
10837
10838 return result;
10839 }
10840
10841 /*********************************************************************
10842 * Any info that needs to do allocations must goto finish on alloc
10843 * failure. Info that is just a lookup should just not set the object
10844 * if the info does not exist.
10845 *********************************************************************/
10846 #define _OSKextLoadInfoDictCapacity (12)
10847
10848 OSSharedPtr<OSDictionary>
10849 OSKext::copyInfo(OSArray * infoKeys)
10850 {
10851 OSSharedPtr<OSDictionary> result;
10852 bool success = false;
10853 OSSharedPtr<OSData> headerData;
10854 OSSharedPtr<OSData> logData;
10855 OSSharedPtr<OSNumber> cpuTypeNumber;
10856 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10857 OSString * versionString = NULL; // do not release
10858 OSString * bundleType = NULL; // do not release
10859 uint32_t executablePathCStringSize = 0;
10860 char * executablePathCString = NULL; // must kfree
10861 OSSharedPtr<OSString> executablePathString;
10862 OSSharedPtr<OSData> uuid;
10863 OSSharedPtr<OSArray> dependencyLoadTags;
10864 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10865 OSSharedPtr<OSArray> metaClassInfo;
10866 OSSharedPtr<OSDictionary> metaClassDict;
10867 OSMetaClass * thisMetaClass = NULL; // do not release
10868 OSSharedPtr<OSString> metaClassName;
10869 OSSharedPtr<OSString> superclassName;
10870 kc_format_t kcformat;
10871 uint32_t count, i;
10872
10873 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10874 if (!result) {
10875 goto finish;
10876 }
10877
10878
10879 /* Empty keys means no keys, but NULL is quicker to check.
10880 */
10881 if (infoKeys && !infoKeys->getCount()) {
10882 infoKeys = NULL;
10883 }
10884
10885 if (!PE_get_primary_kc_format(&kcformat)) {
10886 goto finish;
10887 }
10888
10889 /* Headers, CPU type, and CPU subtype.
10890 */
10891 if (!infoKeys ||
10892 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10893 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10894 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10895 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10896 if (linkedExecutable && !isInterface()) {
10897 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10898 linkedExecutable->getBytesNoCopy();
10899
10900 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10901 // do not return macho header info on shipping embedded - 19095897
10902 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10903 kernel_mach_header_t * temp_kext_mach_hdr;
10904 struct load_command * lcp;
10905
10906 headerData = OSData::withBytes(kext_mach_hdr,
10907 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10908 if (!headerData) {
10909 goto finish;
10910 }
10911
10912 // unslide any vmaddrs we return to userspace - 10726716
10913 temp_kext_mach_hdr = (kernel_mach_header_t *)
10914 headerData->getBytesNoCopy();
10915 if (temp_kext_mach_hdr == NULL) {
10916 goto finish;
10917 }
10918
10919 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10920 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10921 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10922 kernel_segment_command_t * segp;
10923 kernel_section_t * secp;
10924
10925 segp = (kernel_segment_command_t *) lcp;
10926 // 10543468 - if we jettisoned __LINKEDIT clear size info
10927 if (flags.jettisonLinkeditSeg) {
10928 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10929 segp->vmsize = 0;
10930 segp->fileoff = 0;
10931 segp->filesize = 0;
10932 }
10933 }
10934
10935 #if __arm__ || __arm64__
10936 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10937 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10938 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10939 segp->vmaddr = gVirtBase;
10940 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10941 secp->size = 0; // paranoia :)
10942 secp->addr = gVirtBase;
10943 }
10944 }
10945 #endif
10946
10947 #if 0
10948 OSKextLog(/* kext */ NULL,
10949 kOSKextLogErrorLevel |
10950 kOSKextLogGeneralFlag,
10951 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10952 __FUNCTION__, segp->segname, segp->vmaddr,
10953 VM_KERNEL_UNSLIDE(segp->vmaddr),
10954 segp->vmsize, segp->nsects);
10955 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10956 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10957 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10958 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10959 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10960 OSKextLog(/* kext */ NULL,
10961 kOSKextLogErrorLevel |
10962 kOSKextLogGeneralFlag,
10963 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10964 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10965 }
10966 #endif
10967 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10968
10969 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10970 secp->addr = ml_static_unslide(secp->addr);
10971 }
10972 }
10973 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10974 }
10975 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
10976 }
10977 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10978
10979 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10980 osLogDataHeaderRef *header;
10981 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10982
10983 void *os_log_data = NULL;
10984 void *cstring_data = NULL;
10985 void *asan_cstring_data = NULL;
10986 unsigned long os_log_size = 0;
10987 unsigned long cstring_size = 0;
10988 unsigned long asan_cstring_size = 0;
10989 uint32_t os_log_offset = 0;
10990 uint32_t cstring_offset = 0;
10991 uint32_t asan_cstring_offset = 0;
10992 bool res;
10993
10994 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
10995 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
10996 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
10997 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
10998 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
10999 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
11000
11001 header = (osLogDataHeaderRef *) headerBytes;
11002 header->version = OS_LOG_HDR_VERSION;
11003 header->sect_count = NUM_OS_LOG_SECTIONS;
11004 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
11005 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
11006 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
11007 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
11008 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
11009 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
11010
11011
11012 logData = OSData::withValue(*header);
11013 if (!logData) {
11014 goto finish;
11015 }
11016 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11017 if (!res) {
11018 goto finish;
11019 }
11020 if (os_log_data) {
11021 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
11022 if (!res) {
11023 goto finish;
11024 }
11025 }
11026 if (cstring_data) {
11027 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
11028 if (!res) {
11029 goto finish;
11030 }
11031 }
11032 if (asan_cstring_data) {
11033 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
11034 if (!res) {
11035 goto finish;
11036 }
11037 }
11038 result->setObject(kOSBundleLogStringsKey, logData.get());
11039 }
11040
11041 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
11042 cpuTypeNumber = OSNumber::withNumber(
11043 (uint64_t) kext_mach_hdr->cputype,
11044 8 * sizeof(kext_mach_hdr->cputype));
11045 if (!cpuTypeNumber) {
11046 goto finish;
11047 }
11048 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
11049 }
11050
11051 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11052 cpuSubtypeNumber = OSNumber::withNumber(
11053 (uint64_t) kext_mach_hdr->cpusubtype,
11054 8 * sizeof(kext_mach_hdr->cpusubtype));
11055 if (!cpuSubtypeNumber) {
11056 goto finish;
11057 }
11058 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
11059 }
11060 } else {
11061 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11062 osLogDataHeaderRef *header;
11063 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11064 bool res;
11065
11066 header = (osLogDataHeaderRef *) headerBytes;
11067 header->version = OS_LOG_HDR_VERSION;
11068 header->sect_count = NUM_OS_LOG_SECTIONS;
11069 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
11070 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
11071 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
11072 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11073 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
11074 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11075
11076 logData = OSData::withValue(*header);
11077 if (!logData) {
11078 goto finish;
11079 }
11080 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11081 if (!res) {
11082 goto finish;
11083 }
11084 result->setObject(kOSBundleLogStringsKey, logData.get());
11085 }
11086 }
11087 }
11088
11089 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
11090 */
11091 result->setObject(kCFBundleIdentifierKey, bundleID.get());
11092
11093 /* CFBundlePackageType
11094 */
11095 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
11096 if (bundleType) {
11097 result->setObject(kCFBundlePackageTypeKey, bundleType);
11098 }
11099
11100 /* CFBundleVersion.
11101 */
11102 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
11103 versionString = OSDynamicCast(OSString,
11104 getPropertyForHostArch(kCFBundleVersionKey));
11105 if (versionString) {
11106 result->setObject(kCFBundleVersionKey, versionString);
11107 }
11108 }
11109
11110 /* OSBundleCompatibleVersion.
11111 */
11112 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
11113 versionString = OSDynamicCast(OSString,
11114 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
11115 if (versionString) {
11116 result->setObject(kOSBundleCompatibleVersionKey, versionString);
11117 }
11118 }
11119
11120 /* Path.
11121 */
11122 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
11123 if (path) {
11124 result->setObject(kOSBundlePathKey, path.get());
11125 }
11126 }
11127
11128
11129 /* OSBundleExecutablePath.
11130 */
11131 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
11132 if (path && executableRelPath) {
11133 uint32_t pathLength = path->getLength(); // gets incremented below
11134
11135 // +1 for slash, +1 for \0
11136 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11137
11138 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
11139 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
11140 if (!executablePathCString) {
11141 goto finish;
11142 }
11143 strlcpy(executablePathCString, path->getCStringNoCopy(),
11144 executablePathCStringSize);
11145 executablePathCString[pathLength++] = '/';
11146 executablePathCString[pathLength++] = '\0';
11147 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11148 executablePathCStringSize);
11149
11150 executablePathString = OSString::withCString(executablePathCString);
11151
11152 if (!executablePathString) {
11153 goto finish;
11154 }
11155
11156 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11157 } else if (flags.builtin) {
11158 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
11159 } else if (isDriverKit()) {
11160 if (path) {
11161 // +1 for slash, +1 for \0
11162 uint32_t pathLength = path->getLength();
11163 executablePathCStringSize = pathLength + 2;
11164
11165 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
11166 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
11167 if (!executablePathCString) {
11168 goto finish;
11169 }
11170 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11171 executablePathCString[pathLength++] = '/';
11172 executablePathCString[pathLength++] = '\0';
11173
11174 executablePathString = OSString::withCString(executablePathCString);
11175
11176 if (!executablePathString) {
11177 goto finish;
11178 }
11179
11180 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11181 }
11182 }
11183 }
11184
11185 /* UUID, if the kext has one.
11186 */
11187 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11188 uuid = copyUUID();
11189 if (uuid) {
11190 result->setObject(kOSBundleUUIDKey, uuid.get());
11191 }
11192 }
11193 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11194 uuid = copyTextUUID();
11195 if (uuid) {
11196 result->setObject(kOSBundleTextUUIDKey, uuid.get());
11197 }
11198 }
11199
11200 /*
11201 * Info.plist digest
11202 */
11203 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11204 OSData *digest;
11205 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11206 if (digest) {
11207 result->setObject(kOSKextInfoPlistDigestKey, digest);
11208 }
11209 }
11210
11211 /*
11212 * Collection type
11213 */
11214 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11215 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
11216 }
11217
11218 /*
11219 * Collection availability
11220 */
11221 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11222 result->setObject(kOSKextAuxKCAvailabilityKey,
11223 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11224 }
11225
11226 /*
11227 * Allows user load
11228 */
11229 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11230 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11231 if (allowUserLoad) {
11232 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11233 }
11234 }
11235
11236 /*
11237 * Bundle Dependencies (OSBundleLibraries)
11238 */
11239 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11240 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11241 if (libraries) {
11242 result->setObject(kOSBundleLibrariesKey, libraries);
11243 }
11244 }
11245
11246 /*****
11247 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11248 */
11249 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11250 result->setObject(kOSKernelResourceKey,
11251 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11252 }
11253
11254 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11255 result->setObject(kOSBundleIsInterfaceKey,
11256 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11257 }
11258
11259 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11260 result->setObject(kOSBundlePrelinkedKey,
11261 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
11262 }
11263
11264 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11265 result->setObject(kOSBundleStartedKey,
11266 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11267 }
11268
11269 /* LoadTag (Index).
11270 */
11271 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
11272 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
11273 /* numBits */ 8 * sizeof(loadTag));
11274 if (!scratchNumber) {
11275 goto finish;
11276 }
11277 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
11278 }
11279
11280 /* LoadAddress, LoadSize.
11281 */
11282 if (!infoKeys ||
11283 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11284 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11285 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11286 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11287 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11288 bool is_dext = isDriverKit();
11289 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
11290 /* These go to userspace via serialization, so we don't want any doubts
11291 * about their size.
11292 */
11293 uint64_t loadAddress = 0;
11294 uint32_t loadSize = 0;
11295 uint32_t wiredSize = 0;
11296 uint64_t execLoadAddress = 0;
11297 uint32_t execLoadSize = 0;
11298
11299 /* Interfaces always report 0 load address & size.
11300 * Just the way they roll.
11301 *
11302 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11303 * xxx - shouldn't have one!
11304 */
11305
11306 if (flags.builtin || linkedExecutable) {
11307 kernel_mach_header_t *mh = NULL;
11308 kernel_segment_command_t *seg = NULL;
11309
11310 if (flags.builtin) {
11311 loadAddress = kmod_info->address;
11312 loadSize = (uint32_t)kmod_info->size;
11313 } else {
11314 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11315 loadSize = linkedExecutable->getLength();
11316 }
11317 mh = (kernel_mach_header_t *)loadAddress;
11318 loadAddress = ml_static_unslide(loadAddress);
11319
11320 /* Walk through the kext, looking for the first executable
11321 * segment in case we were asked for its size/address.
11322 */
11323 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11324 if (seg->initprot & VM_PROT_EXECUTE) {
11325 execLoadAddress = ml_static_unslide(seg->vmaddr);
11326 execLoadSize = (uint32_t)seg->vmsize;
11327 break;
11328 }
11329 }
11330
11331 /* If we have a kmod_info struct, calculated the wired size
11332 * from that. Otherwise it's the full load size.
11333 */
11334 if (kmod_info) {
11335 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
11336 } else {
11337 wiredSize = loadSize;
11338 }
11339 } else if (is_dext) {
11340 /*
11341 * DriverKit userspace executables do not have a kernel linkedExecutable,
11342 * so we "fake" their address range with the LoadTag.
11343 */
11344 if (loadTag) {
11345 loadAddress = execLoadAddress = loadTag;
11346 loadSize = execLoadSize = 1;
11347 }
11348 }
11349
11350 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
11351 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11352 (unsigned long long)(loadAddress),
11353 /* numBits */ 8 * sizeof(loadAddress));
11354 if (!scratchNumber) {
11355 goto finish;
11356 }
11357 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
11358 }
11359 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11360 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11361 && loadAddress && loadSize) {
11362 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11363 if (!baseAddress) {
11364 goto finish;
11365 }
11366
11367 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11368 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11369 /* numBits */ 8 * sizeof(loadAddress));
11370 if (!scratchNumber) {
11371 goto finish;
11372 }
11373 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11374 }
11375 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11376 && (this == sKernelKext) && gBuiltinKmodsCount) {
11377 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
11378 }
11379 }
11380
11381 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
11382 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11383 (unsigned long long)(execLoadAddress),
11384 /* numBits */ 8 * sizeof(execLoadAddress));
11385 if (!scratchNumber) {
11386 goto finish;
11387 }
11388 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
11389 }
11390 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
11391 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11392 (unsigned long long)(loadSize),
11393 /* numBits */ 8 * sizeof(loadSize));
11394 if (!scratchNumber) {
11395 goto finish;
11396 }
11397 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
11398 }
11399 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
11400 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11401 (unsigned long long)(execLoadSize),
11402 /* numBits */ 8 * sizeof(execLoadSize));
11403 if (!scratchNumber) {
11404 goto finish;
11405 }
11406 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
11407 }
11408 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11409 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11410 (unsigned long long)(wiredSize),
11411 /* numBits */ 8 * sizeof(wiredSize));
11412 if (!scratchNumber) {
11413 goto finish;
11414 }
11415 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
11416 }
11417 }
11418 }
11419
11420 /* OSBundleDependencies. In descending order for
11421 * easy compatibility with kextstat(8).
11422 */
11423 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11424 if ((count = getNumDependencies())) {
11425 dependencyLoadTags = OSArray::withCapacity(count);
11426 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
11427
11428 i = count - 1;
11429 do {
11430 OSKext * dependency = OSDynamicCast(OSKext,
11431 dependencies->getObject(i));
11432
11433 if (!dependency) {
11434 continue;
11435 }
11436 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11437 (unsigned long long)dependency->getLoadTag(),
11438 /* numBits*/ 8 * sizeof(loadTag));
11439 if (!scratchNumber) {
11440 goto finish;
11441 }
11442 dependencyLoadTags->setObject(scratchNumber.get());
11443 } while (i--);
11444 }
11445 }
11446
11447 /* OSBundleMetaClasses.
11448 */
11449 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11450 if (metaClasses && metaClasses->getCount()) {
11451 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
11452 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11453 if (!metaClassIterator || !metaClassInfo) {
11454 goto finish;
11455 }
11456 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
11457
11458 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11459 metaClassIterator->getNextObject()))) {
11460 metaClassDict = OSDictionary::withCapacity(3);
11461 if (!metaClassDict) {
11462 goto finish;
11463 }
11464
11465 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11466 if (thisMetaClass->getSuperClass()) {
11467 superclassName = OSString::withCString(
11468 thisMetaClass->getSuperClass()->getClassName());
11469 }
11470 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
11471 8 * sizeof(unsigned int));
11472
11473 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11474 * of course.
11475 */
11476 if (!metaClassDict || !metaClassName || !scratchNumber) {
11477 goto finish;
11478 }
11479
11480 metaClassInfo->setObject(metaClassDict.get());
11481 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
11482 if (superclassName) {
11483 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
11484 }
11485 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
11486 }
11487 }
11488 }
11489
11490 /* OSBundleRetainCount.
11491 */
11492 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
11493 {
11494 int kextRetainCount = getRetainCount() - 1;
11495 if (isLoaded()) {
11496 kextRetainCount--;
11497 }
11498 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11499 (int)kextRetainCount,
11500 /* numBits*/ 8 * sizeof(int));
11501 if (scratchNumber) {
11502 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
11503 }
11504 }
11505 }
11506
11507 success = true;
11508
11509 finish:
11510 if (executablePathCString) {
11511 kfree_data(executablePathCString, executablePathCStringSize);
11512 }
11513 if (!success) {
11514 result.reset();
11515 }
11516 return result;
11517 }
11518
11519 /*********************************************************************
11520 *********************************************************************/
11521 /* static */
11522 bool
11523 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11524 {
11525 bool ok;
11526 OSSharedPtr<OSKext> kext;
11527
11528 IORecursiveLockLock(sKextLock);
11529 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
11530 IORecursiveLockUnlock(sKextLock);
11531
11532 if (!kext || !kext->path || !kext->userExecutableRelPath) {
11533 return false;
11534 }
11535 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11536 kext->path->getCStringNoCopy(),
11537 kext->userExecutableRelPath->getCStringNoCopy());
11538 ok = true;
11539
11540 return ok;
11541 }
11542
11543 /*********************************************************************
11544 *********************************************************************/
11545 /* static */
11546 OSReturn
11547 OSKext::requestResource(
11548 const char * kextIdentifierCString,
11549 const char * resourceNameCString,
11550 OSKextRequestResourceCallback callback,
11551 void * context,
11552 OSKextRequestTag * requestTagOut)
11553 {
11554 OSReturn result = kOSReturnError;
11555 OSSharedPtr<OSKext> callbackKext; // looked up
11556
11557 OSKextRequestTag requestTag = -1;
11558 OSSharedPtr<OSNumber> requestTagNum;
11559 OSSharedPtr<OSDictionary> requestDict;
11560 OSSharedPtr<OSString> kextIdentifier;
11561 OSSharedPtr<OSString> resourceName;
11562
11563 OSSharedPtr<OSDictionary> callbackRecord;
11564 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
11565
11566 OSSharedPtr<OSValueObject<void *> > contextWrapper;
11567
11568 IORecursiveLockLock(sKextLock);
11569
11570 if (requestTagOut) {
11571 *requestTagOut = kOSKextRequestTagInvalid;
11572 }
11573
11574 /* If requests to user space are disabled, don't go any further */
11575 if (!sKernelRequestsEnabled) {
11576 OSKextLog(/* kext */ NULL,
11577 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11578 "Can't request resource %s for %s - requests to user space are disabled.",
11579 resourceNameCString,
11580 kextIdentifierCString);
11581 result = kOSKextReturnDisabled;
11582 goto finish;
11583 }
11584
11585 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11586 result = kOSKextReturnInvalidArgument;
11587 goto finish;
11588 }
11589
11590 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11591 if (!callbackKext) {
11592 OSKextLog(/* kext */ NULL,
11593 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11594 "Resource request has bad callback address.");
11595 result = kOSKextReturnInvalidArgument;
11596 goto finish;
11597 }
11598 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11599 OSKextLog(/* kext */ NULL,
11600 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11601 "Resource request callback is in a kext that is not started.");
11602 result = kOSKextReturnInvalidArgument;
11603 goto finish;
11604 }
11605
11606 /* Do not allow any new requests to be made on a kext that is unloading.
11607 */
11608 if (callbackKext->flags.stopping) {
11609 result = kOSKextReturnStopping;
11610 goto finish;
11611 }
11612
11613 /* If we're wrapped the next available request tag around to the negative
11614 * numbers, we can't service any more requests.
11615 */
11616 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11617 OSKextLog(/* kext */ NULL,
11618 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11619 "No more request tags available; restart required.");
11620 result = kOSKextReturnNoResources;
11621 goto finish;
11622 }
11623 requestTag = sNextRequestTag++;
11624
11625 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
11626 requestDict);
11627 if (result != kOSReturnSuccess) {
11628 goto finish;
11629 }
11630
11631 kextIdentifier = OSString::withCString(kextIdentifierCString);
11632 resourceName = OSString::withCString(resourceNameCString);
11633 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11634 8 * sizeof(requestTag));
11635 if (!kextIdentifier ||
11636 !resourceName ||
11637 !requestTagNum ||
11638 !_OSKextSetRequestArgument(requestDict.get(),
11639 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11640 !_OSKextSetRequestArgument(requestDict.get(),
11641 kKextRequestArgumentNameKey, resourceName.get()) ||
11642 !_OSKextSetRequestArgument(requestDict.get(),
11643 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
11644 result = kOSKextReturnNoMemory;
11645 goto finish;
11646 }
11647
11648 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
11649 if (!callbackRecord) {
11650 result = kOSKextReturnNoMemory;
11651 goto finish;
11652 }
11653 // we validate callback address at call time
11654 callbackWrapper = OSValueObjectWithValue(callback);
11655 if (context) {
11656 contextWrapper = OSValueObjectWithValue(context);
11657 }
11658 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11659 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
11660 result = kOSKextReturnNoMemory;
11661 goto finish;
11662 }
11663
11664 if (context) {
11665 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11666 kKextRequestArgumentContextKey, contextWrapper.get())) {
11667 result = kOSKextReturnNoMemory;
11668 goto finish;
11669 }
11670 }
11671
11672 /* Only post the requests after all the other potential failure points
11673 * have been passed.
11674 */
11675 if (!sKernelRequests->setObject(requestDict.get()) ||
11676 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
11677 result = kOSKextReturnNoMemory;
11678 goto finish;
11679 }
11680
11681 OSKext::pingIOKitDaemon();
11682
11683 result = kOSReturnSuccess;
11684 if (requestTagOut) {
11685 *requestTagOut = requestTag;
11686 }
11687
11688 finish:
11689
11690 /* If we didn't succeed, yank the request & callback
11691 * from their holding arrays.
11692 */
11693 if (result != kOSReturnSuccess) {
11694 unsigned int index;
11695
11696 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
11697 if (index != (unsigned int)-1) {
11698 sKernelRequests->removeObject(index);
11699 }
11700 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
11701 if (index != (unsigned int)-1) {
11702 sRequestCallbackRecords->removeObject(index);
11703 }
11704 }
11705
11706 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11707
11708 IORecursiveLockUnlock(sKextLock);
11709
11710 return result;
11711 }
11712
11713 OSReturn
11714 OSKext::requestDaemonLaunch(
11715 OSString *kextIdentifier,
11716 OSString *serverName,
11717 OSNumber *serverTag,
11718 IOUserServerCheckInToken * checkInToken)
11719 {
11720 OSReturn result = kOSReturnError;
11721 OSSharedPtr<OSDictionary> requestDict;
11722
11723 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
11724 return kOSKextReturnInvalidArgument;
11725 }
11726
11727 IORecursiveLockLock(sKextLock);
11728
11729 OSKextLog(/* kext */ NULL,
11730 kOSKextLogDebugLevel |
11731 kOSKextLogGeneralFlag,
11732 "Requesting daemon launch for %s with serverName %s and tag %llu",
11733 kextIdentifier->getCStringNoCopy(),
11734 serverName->getCStringNoCopy(),
11735 serverTag->unsigned64BitValue()
11736 );
11737
11738 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
11739 if (result != kOSReturnSuccess) {
11740 goto finish;
11741 }
11742
11743 if (!_OSKextSetRequestArgument(requestDict.get(),
11744 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
11745 !_OSKextSetRequestArgument(requestDict.get(),
11746 kKextRequestArgumentDriverExtensionServerName, serverName) ||
11747 !_OSKextSetRequestArgument(requestDict.get(),
11748 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11749 !_OSKextSetRequestArgument(requestDict.get(),
11750 kKextRequestArgumentCheckInToken, checkInToken)) {
11751 result = kOSKextReturnNoMemory;
11752 goto finish;
11753 }
11754
11755 /* Only post the requests after all the other potential failure points
11756 * have been passed.
11757 */
11758 if (!sKernelRequests->setObject(requestDict.get())) {
11759 result = kOSKextReturnNoMemory;
11760 goto finish;
11761 }
11762 OSKext::pingIOKitDaemon();
11763
11764 result = kOSReturnSuccess;
11765 finish:
11766 IORecursiveLockUnlock(sKextLock);
11767 return result;
11768 }
11769
11770 /*********************************************************************
11771 * Assumes sKextLock is held.
11772 *********************************************************************/
11773 /* static */
11774 OSReturn
11775 OSKext::dequeueCallbackForRequestTag(
11776 OSKextRequestTag requestTag,
11777 OSSharedPtr<OSDictionary> &callbackRecordOut)
11778 {
11779 OSDictionary * callbackRecordOutRaw = NULL;
11780 OSReturn result;
11781
11782 result = dequeueCallbackForRequestTag(requestTag,
11783 &callbackRecordOutRaw);
11784
11785 if (kOSReturnSuccess == result) {
11786 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11787 }
11788
11789 return result;
11790 }
11791 OSReturn
11792 OSKext::dequeueCallbackForRequestTag(
11793 OSKextRequestTag requestTag,
11794 OSDictionary ** callbackRecordOut)
11795 {
11796 OSReturn result = kOSReturnError;
11797 OSSharedPtr<OSNumber> requestTagNum;
11798
11799 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11800 8 * sizeof(requestTag));
11801 if (!requestTagNum) {
11802 goto finish;
11803 }
11804
11805 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11806 callbackRecordOut);
11807
11808 finish:
11809 return result;
11810 }
11811
11812 /*********************************************************************
11813 * Assumes sKextLock is held.
11814 *********************************************************************/
11815 /* static */
11816 OSReturn
11817 OSKext::dequeueCallbackForRequestTag(
11818 OSNumber * requestTagNum,
11819 OSSharedPtr<OSDictionary> &callbackRecordOut)
11820 {
11821 OSDictionary * callbackRecordOutRaw = NULL;
11822 OSReturn result;
11823
11824 result = dequeueCallbackForRequestTag(requestTagNum,
11825 &callbackRecordOutRaw);
11826
11827 if (kOSReturnSuccess == result) {
11828 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11829 }
11830
11831 return result;
11832 }
11833 OSReturn
11834 OSKext::dequeueCallbackForRequestTag(
11835 OSNumber * requestTagNum,
11836 OSDictionary ** callbackRecordOut)
11837 {
11838 OSReturn result = kOSKextReturnInvalidArgument;
11839 OSDictionary * callbackRecord = NULL; // retain if matched!
11840 OSNumber * callbackTagNum = NULL; // do not release
11841 unsigned int count, i;
11842
11843 result = kOSReturnError;
11844 count = sRequestCallbackRecords->getCount();
11845 for (i = 0; i < count; i++) {
11846 callbackRecord = OSDynamicCast(OSDictionary,
11847 sRequestCallbackRecords->getObject(i));
11848 if (!callbackRecord) {
11849 goto finish;
11850 }
11851
11852 /* If we don't find a tag, we basically have a leak here. Maybe
11853 * we should just remove it.
11854 */
11855 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11856 callbackRecord, kKextRequestArgumentRequestTagKey));
11857 if (!callbackTagNum) {
11858 goto finish;
11859 }
11860
11861 /* We could be even more paranoid and check that all the incoming
11862 * args match what's in the callback record.
11863 */
11864 if (callbackTagNum->isEqualTo(requestTagNum)) {
11865 if (callbackRecordOut) {
11866 *callbackRecordOut = callbackRecord;
11867 callbackRecord->retain();
11868 }
11869 sRequestCallbackRecords->removeObject(i);
11870 result = kOSReturnSuccess;
11871 goto finish;
11872 }
11873 }
11874 result = kOSKextReturnNotFound;
11875
11876 finish:
11877 return result;
11878 }
11879
11880
11881 /*********************************************************************
11882 * Busy timeout triage
11883 *********************************************************************/
11884 /* static */
11885 bool
11886 OSKext::pendingIOKitDaemonRequests(void)
11887 {
11888 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11889 }
11890
11891 extern "C" int vm_enable_driverkit_shared_region;
11892
11893 /*********************************************************************
11894 * Acquires and releases sKextLock
11895 *
11896 * This function is designed to be called exactly once on boot by
11897 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11898 * kext and dext personalities, and then attempts to map a System
11899 * (pageable) KC and an Auxiliary (aux) KC.
11900 *
11901 * Even if the pageable or aux KC fail to load - this function will
11902 * not allow a second call. This avoids security issues where
11903 * kernelmanagerd has been compromised or the pageable kc has been
11904 * tampered with and the attacker attempts to re-load a malicious
11905 * variant.
11906 *
11907 * Return: if a KC fails to load the return value will contain:
11908 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11909 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11910 * Similarly, if the aux kc load fails, the return value will
11911 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11912 * compose with each other and with kOSKextReturnKCLoadFailure.
11913 *********************************************************************/
11914 /* static */
11915 OSReturn
11916 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11917 {
11918 static bool daemon_ready = false;
11919
11920 OSReturn ret = kOSKextReturnInvalidArgument;
11921 OSReturn kcerr = 0;
11922 bool start_matching = false;
11923
11924 bool allow_fileset_load = !daemon_ready;
11925 #if !(defined(__x86_64__) || defined(__i386__))
11926 /* never allow KCs full of kexts on non-x86 machines */
11927 allow_fileset_load = false;
11928 #endif
11929
11930 /*
11931 * Change with 70582300
11932 */
11933 #if 0 || !defined(VM_MAPPED_KEXTS)
11934 /*
11935 * On platforms that don't support the SystemKC or a file-backed
11936 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
11937 * needs to be queried before we load any codeless kexts or release
11938 * any 3rd party kexts to run. On platforms that support a file-backed
11939 * AuxKC, this process is done via the kext audit mechanism.
11940 */
11941
11942 printf("KextLog: waiting for kext receipt to be queried.\n");
11943 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
11944 IOSleep(30);
11945 }
11946 #endif /* !VM_MAPPED_KEXTS */
11947
11948 /*
11949 * Get the args from the request. Right now we need the file
11950 * name for the pageable and the aux kext collection file sets.
11951 */
11952 OSDictionary * requestArgs = NULL; // do not release
11953 OSString * pageable_filepath = NULL; // do not release
11954 OSString * aux_filepath = NULL; // do not release
11955 OSArray * codeless_kexts = NULL; // do not release
11956 OSNumber * enable_dk_shared_region = NULL; // do not release
11957
11958 kernel_mach_header_t *akc_mh = NULL;
11959
11960 requestArgs = OSDynamicCast(OSDictionary,
11961 requestDict->getObject(kKextRequestArgumentsKey));
11962
11963 if (requestArgs == NULL) {
11964 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11965 "KextLog: No arguments in plist for loading fileset kext\n");
11966 printf("KextLog: No arguments in plist for loading fileset kext\n");
11967 return ret;
11968 }
11969
11970 ret = kOSKextReturnDisabled;
11971
11972 IORecursiveLockLock(sKextLock);
11973
11974 if (!sLoadEnabled) {
11975 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11976 "KextLog: Kext loading is disabled (attempt to load KCs).");
11977 IORecursiveLockUnlock(sKextLock);
11978 return ret;
11979 }
11980
11981 pageable_filepath = OSDynamicCast(OSString,
11982 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11983
11984 if (allow_fileset_load && pageable_filepath != NULL) {
11985 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11986
11987 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11988 if (ret) {
11989 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11990 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11991
11992 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11993 ret = kOSKextReturnKCLoadFailure;
11994 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11995 goto try_auxkc;
11996 }
11997 /*
11998 * Even if the AuxKC fails to load, we still want to send
11999 * the System KC personalities to the catalog for matching
12000 */
12001 start_matching = true;
12002 } else if (pageable_filepath != NULL) {
12003 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12004 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
12005 ret = kOSKextReturnUnsupported;
12006 }
12007
12008 try_auxkc:
12009 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
12010 if (akc_mh) {
12011 /*
12012 * If we try to load a deferred AuxKC, then don't ever attempt
12013 * a filesystem map of a file
12014 */
12015 allow_fileset_load = false;
12016
12017 /*
12018 * This function is only called once per boot, so we haven't
12019 * yet loaded an AuxKC. If we have registered the AuxKC mach
12020 * header, that means that the kext collection has been placed
12021 * in memory for us by the booter, and is waiting for us to
12022 * process it. Grab the deferred XML plist of info
12023 * dictionaries and add all the kexts.
12024 */
12025 OSSharedPtr<OSObject> parsedXML;
12026 OSSharedPtr<OSData> loaded_kcUUID;
12027 OSDictionary *infoDict;
12028 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
12029 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12030 #if !defined(VM_MAPPED_KEXTS)
12031 /*
12032 * On platforms where we don't dynamically wire-down / page-in
12033 * kext memory, we need to maintain the invariant that if the
12034 * AuxKC in memory does not contain a kext receipt, then we
12035 * should not load any of the kexts.
12036 */
12037 size_t receipt_sz = 0;
12038 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
12039 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12040 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
12041 ret = kOSKextReturnKCLoadFailure;
12042 goto try_codeless;
12043 }
12044 #endif
12045 if (infoDict) {
12046 bool added;
12047 printf("KextLog: Adding kexts from in-memory AuxKC\n");
12048 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
12049 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
12050 if (!loaded_kcUUID) {
12051 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12052 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
12053 } else if (!added) {
12054 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12055 "KextLog: WARNING: Failed to load AuxKC from memory.");
12056 }
12057 /* only return success if the pageable load (above) was successful */
12058 if (ret != kOSKextReturnKCLoadFailure) {
12059 ret = kOSReturnSuccess;
12060 }
12061 /* the registration of the AuxKC parsed out the KC's UUID already */
12062 } else {
12063 if (daemon_ready) {
12064 /*
12065 * Complain, but don't return an error if this isn't the first time the
12066 * IOKit daemon is checking in. If the daemon ever restarts, we will
12067 * hit this case because we've already consumed the deferred personalities.
12068 * We return success here so that a call to this function from a restarted
12069 * daemon with no codeless kexts will succeed.
12070 */
12071 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12072 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
12073 if (ret != kOSKextReturnKCLoadFailure) {
12074 ret = kOSReturnSuccess;
12075 }
12076 } else {
12077 /* this is a real error case */
12078 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12079 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
12080 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
12081 ret = kOSKextReturnKCLoadFailure;
12082 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12083 }
12084 }
12085 }
12086
12087 aux_filepath = OSDynamicCast(OSString,
12088 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
12089 if (allow_fileset_load && aux_filepath != NULL) {
12090 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
12091
12092 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
12093 if (ret) {
12094 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12095 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12096
12097 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12098 ret = kOSKextReturnKCLoadFailure;
12099 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12100 goto try_codeless;
12101 }
12102 start_matching = true;
12103 } else if (aux_filepath != NULL) {
12104 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12105 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
12106 if (ret != kOSKextReturnKCLoadFailure) {
12107 ret = kOSKextReturnUnsupported;
12108 }
12109 }
12110
12111 try_codeless:
12112 /*
12113 * Load codeless kexts last so that there is no possibilty of a
12114 * codeless kext bundle ID preventing a kext in the system KC from
12115 * loading
12116 */
12117 codeless_kexts = OSDynamicCast(OSArray,
12118 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
12119 if (codeless_kexts != NULL) {
12120 uint32_t count = codeless_kexts->getCount();
12121 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12122 "KextLog: loading %d codeless kexts/dexts", count);
12123 for (uint32_t i = 0; i < count; i++) {
12124 OSDictionary *infoDict;
12125 infoDict = OSDynamicCast(OSDictionary,
12126 codeless_kexts->getObject(i));
12127 if (!infoDict) {
12128 continue;
12129 }
12130 // instantiate a new kext, and don't hold a reference
12131 // (the kext subsystem will hold one implicitly)
12132 OSKext::withCodelessInfo(infoDict);
12133 }
12134 /* ignore errors that are not KC load failures */
12135 if (ret != kOSKextReturnKCLoadFailure) {
12136 ret = kOSReturnSuccess;
12137 }
12138 start_matching = true;
12139 }
12140
12141 enable_dk_shared_region = OSDynamicCast(OSNumber,
12142 requestArgs->getObject(kKextRequestEnableDriverKitSharedRegionKey));
12143 if (enable_dk_shared_region != NULL && enable_dk_shared_region->unsigned64BitValue() == 1) {
12144 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12145 "KextLog: Enabling DriverKit shared region.");
12146 vm_enable_driverkit_shared_region = 1;
12147 }
12148
12149 /* send personalities to the IOCatalog once */
12150 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
12151 OSKext::sendAllKextPersonalitiesToCatalog(true);
12152 /*
12153 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12154 * things as active and start all the delayed matching: the
12155 * dext and codeless kext personalities should have all been
12156 * delivered via this one call.
12157 */
12158 if (!daemon_ready) {
12159 OSKext::setIOKitDaemonActive();
12160 OSKext::setDeferredLoadSucceeded(TRUE);
12161 IOService::iokitDaemonLaunched();
12162 }
12163 if (sOSKextWasResetAfterUserspaceReboot) {
12164 sOSKextWasResetAfterUserspaceReboot = false;
12165 OSKext::setIOKitDaemonActive();
12166 IOService::startDeferredMatches();
12167 }
12168 }
12169
12170 if (ret == kOSKextReturnKCLoadFailure) {
12171 ret |= kcerr;
12172 }
12173
12174 /*
12175 * Only allow this function to attempt to load the pageable and
12176 * aux KCs once per boot.
12177 */
12178 daemon_ready = true;
12179
12180 IORecursiveLockUnlock(sKextLock);
12181
12182 return ret;
12183 }
12184
12185 OSReturn
12186 OSKext::resetMutableSegments(void)
12187 {
12188 kernel_segment_command_t *seg = NULL;
12189 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12190 u_int index = 0;
12191 OSKextSavedMutableSegment *savedSegment = NULL;
12192 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12193 OSReturn err;
12194
12195 if (!savedMutableSegments) {
12196 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12197 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12198 err = kOSKextReturnInternalError;
12199 goto finish;
12200 }
12201
12202 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12203 if (!segmentIsMutable(seg)) {
12204 continue;
12205 }
12206 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12207 uint64_t vmsize = seg->vmsize;
12208 err = kOSKextReturnInternalError;
12209 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12210 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12211 assert(savedSegment);
12212 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12213 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12214 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12215 err = savedSegment->restoreContents(seg);
12216 if (err != kOSReturnSuccess) {
12217 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12218 }
12219 }
12220 }
12221 if (err != kOSReturnSuccess) {
12222 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12223 }
12224 }
12225 err = kOSReturnSuccess;
12226 finish:
12227 return err;
12228 }
12229
12230
12231 /*********************************************************************
12232 * Assumes sKextLock is held.
12233 *********************************************************************/
12234 /* static */
12235 OSReturn
12236 OSKext::loadKCFileSet(
12237 const char *filepath,
12238 kc_kind_t type)
12239 {
12240 #if VM_MAPPED_KEXTS
12241 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12242 OSReturn err;
12243 struct vnode *vp = NULL;
12244 void *fileset_control;
12245 off_t fsize;
12246 bool pageable = (type == KCKindPageable);
12247
12248 if ((pageable && pageableKCloaded) ||
12249 (!pageable && auxKCloaded)) {
12250 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12251 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12252
12253 return kOSKextReturnInvalidArgument;
12254 }
12255
12256 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12257 if (!pageable && !pageableKCloaded) {
12258 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12259 "Trying to load the Aux KC without loading the Pageable KC");
12260 return kOSKextReturnInvalidArgument;
12261 }
12262
12263 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12264
12265 if (fileset_control == NULL) {
12266 printf("Could not get memory control object for file %s", filepath);
12267
12268 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12269 "Could not get memory control object for file %s", filepath);
12270 return kOSKextReturnInvalidArgument;
12271 }
12272 if (vp == NULL) {
12273 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12274 "Could not find vnode for file %s", filepath);
12275 return kOSKextReturnInvalidArgument;
12276 }
12277
12278 kernel_mach_header_t *mh = NULL;
12279 uintptr_t slide = 0;
12280
12281 #if CONFIG_CSR
12282 /*
12283 * When SIP is enabled, the KC we map must be SIP-protected
12284 */
12285 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12286 struct vnode_attr va;
12287 int error;
12288 VATTR_INIT(&va);
12289 VATTR_WANTED(&va, va_flags);
12290 error = vnode_getattr(vp, &va, vfs_context_current());
12291 if (error) {
12292 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12293 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12294 err = kOSKextReturnInternalError;
12295 goto finish;
12296 }
12297 if (!(va.va_flags & SF_RESTRICTED)) {
12298 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12299 "Path to KC '%s' is not SIP-protected", filepath);
12300 err = kOSKextReturnInvalidArgument;
12301 goto finish;
12302 }
12303 }
12304 #endif
12305
12306 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12307 if (err) {
12308 printf("KextLog: mapKCFileSet returned %d\n", err);
12309
12310 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12311 "mapKCFileSet returned %d\n", err);
12312
12313 err = kOSKextReturnInvalidArgument;
12314 }
12315
12316 #if CONFIG_CSR
12317 finish:
12318 #endif
12319 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12320 assert(vp != NULL);
12321 if (err == kOSReturnSuccess) {
12322 PE_set_kc_vp(type, vp);
12323 if (pageable) {
12324 pageableKCloaded = true;
12325 } else {
12326 auxKCloaded = true;
12327 }
12328 } else {
12329 vnode_put(vp);
12330 }
12331
12332 return err;
12333 #else
12334 (void)filepath;
12335 (void)type;
12336 return kOSKextReturnUnsupported;
12337 #endif // VM_MAPPED_KEXTS
12338 }
12339
12340 #if defined(__x86_64__) || defined(__i386__)
12341 /*********************************************************************
12342 * Assumes sKextLock is held.
12343 *********************************************************************/
12344 /* static */
12345 OSReturn
12346 OSKext::mapKCFileSet(
12347 void *control,
12348 vm_size_t fsize,
12349 kernel_mach_header_t **mhp,
12350 off_t file_offset,
12351 uintptr_t *slidep,
12352 bool pageable,
12353 void *map_entry_list)
12354 {
12355 bool fileset_load = false;
12356 kern_return_t ret;
12357 OSReturn err;
12358 kernel_section_t *infoPlistSection = NULL;
12359 OSDictionary *infoDict = NULL;
12360
12361 OSSharedPtr<OSObject> parsedXML;
12362 OSSharedPtr<OSString> errorString;
12363 OSSharedPtr<OSData> loaded_kcUUID;
12364
12365 /* Check if initial load for file set */
12366 if (*mhp == NULL) {
12367 fileset_load = true;
12368
12369 /* Get a page aligned address from kext map to map the file */
12370 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12371 if (pagealigned_addr == 0) {
12372 return kOSKextReturnNoMemory;
12373 }
12374
12375 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12376
12377 /* Allocate memory for bailout mechanism */
12378 map_entry_list = allocate_kcfileset_map_entry_list();
12379 if (map_entry_list == NULL) {
12380 return kOSKextReturnNoMemory;
12381 }
12382 }
12383
12384 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12385 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12386 /* mhp and slideptr are updated by mapKCTextSegment */
12387 if (err) {
12388 if (fileset_load) {
12389 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12390 }
12391 return err;
12392 }
12393
12394 /* Initialize the kc header globals */
12395 if (fileset_load) {
12396 if (pageable) {
12397 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12398 } else {
12399 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12400 }
12401 }
12402
12403 /* Iterate through all the segments and map necessary segments */
12404 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12405 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12406 vm_map_offset_t start;
12407 kernel_mach_header_t *k_mh = NULL;
12408 kernel_segment_command_t * seg = NULL;
12409 struct fileset_entry_command *fse = NULL;
12410
12411 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12412 seg = (kernel_segment_command_t *)lcp;
12413 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12414 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12415 fse = (struct fileset_entry_command *)lcp;
12416 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12417
12418 /* Map the segments of the mach-o binary */
12419 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12420 if (err) {
12421 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12422 return kOSKextReturnInvalidArgument;
12423 }
12424 continue;
12425 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12426 /* Check if the Aux KC is built pageable style */
12427 if (!pageable && !fileset_load && !auxKCloaded) {
12428 resetAuxKCSegmentOnUnload = true;
12429 }
12430 continue;
12431 } else {
12432 continue;
12433 }
12434
12435 if (fileset_load) {
12436 if (seg->vmsize == 0) {
12437 continue;
12438 }
12439
12440 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12441 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12442 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12443 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12444 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12445 continue;
12446 }
12447 } else {
12448 if (seg->vmsize == 0) {
12449 continue;
12450 }
12451
12452 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12453 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12454 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12455 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12456 continue;
12457 }
12458 }
12459
12460 ret = vm_map_kcfileset_segment(
12461 &start, seg->vmsize,
12462 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12463
12464 if (ret != KERN_SUCCESS) {
12465 if (fileset_load) {
12466 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12467 }
12468 return kOSKextReturnInvalidArgument;
12469 }
12470 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12471 }
12472
12473 /* Return if regular mach-o */
12474 if (!fileset_load) {
12475 return 0;
12476 }
12477
12478 /*
12479 * Fixup for the Pageable KC and the Aux KC is done by
12480 * i386_slide_kext_collection_mh_addrs, but it differs in
12481 * following ways:
12482 *
12483 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12484 * The fixup of kext segments and kext load commands are done at kext
12485 * load time by calling i386_slide_individual_kext.
12486 *
12487 * AuxKC old style: Fixup all the segments and all the load commands.
12488 *
12489 * AuxKC pageable style: Same as the Pageable KC.
12490 */
12491 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12492 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12493 if (ret != KERN_SUCCESS) {
12494 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12495 return kOSKextReturnInvalidArgument;
12496 }
12497
12498 /* Get the prelink info dictionary */
12499 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12500 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12501 if (parsedXML) {
12502 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12503 }
12504
12505 if (!infoDict) {
12506 const char *errorCString = "(unknown error)";
12507
12508 if (errorString && errorString->getCStringNoCopy()) {
12509 errorCString = errorString->getCStringNoCopy();
12510 } else if (parsedXML) {
12511 errorCString = "not a dictionary";
12512 }
12513 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12514 "Error unserializing kext info plist section: %s.", errorCString);
12515 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12516 return kOSKextReturnInvalidArgument;
12517 }
12518
12519 /* Validate that the Kext Collection is prelinked to the loaded KC */
12520 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12521 if (err) {
12522 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12523 return kOSKextReturnInvalidArgument;
12524 }
12525
12526 /* Set Protection of Segments */
12527 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12528
12529 OSKext::addKextsFromKextCollection(*mhp,
12530 infoDict, kPrelinkTextSegment,
12531 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12532
12533 /* Copy in the KC UUID */
12534 if (!loaded_kcUUID) {
12535 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12536 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12537 } else if (pageable) {
12538 pageablekc_uuid_valid = TRUE;
12539 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12540 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12541 } else {
12542 auxkc_uuid_valid = TRUE;
12543 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12544 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12545 }
12546
12547 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12548
12549 return 0;
12550 }
12551
12552 /*********************************************************************
12553 * Assumes sKextLock is held.
12554 *********************************************************************/
12555 /* static */
12556 OSReturn
12557 OSKext::mapKCTextSegment(
12558 void *control,
12559 kernel_mach_header_t **mhp,
12560 off_t file_offset,
12561 uintptr_t *slidep,
12562 void *map_entry_list)
12563 {
12564 kern_return_t ret;
12565 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12566 PAGE_MASK);
12567 vm_map_offset_t load_command_map_size = 0;
12568 kernel_mach_header_t *base_mh = *mhp;
12569
12570 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12571 ret = vm_map_kcfileset_segment(
12572 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12573 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12574
12575 if (ret != KERN_SUCCESS) {
12576 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12577
12578 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12579 "Failed to map mach header of kc fileset with error %d", ret);
12580 return kOSKextReturnInvalidArgument;
12581 }
12582
12583 if (slidep) {
12584 /* Verify that it's an MH_FILESET */
12585 if (base_mh->filetype != MH_FILESET) {
12586 printf("Kext Log: mapKCTextSegment mach header filetype"
12587 " is not an MH_FILESET, it is %x", base_mh->filetype);
12588
12589 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12590 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12591
12592 /* Unmap the mach header */
12593 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12594 return kOSKextReturnInvalidArgument;
12595 }
12596 }
12597
12598 /* Map the remaining pages of load commands */
12599 if (base_mh->sizeofcmds > mach_header_map_size) {
12600 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12601 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12602
12603 /* Map the load commands */
12604 ret = vm_map_kcfileset_segment(
12605 &load_command_addr, load_command_map_size,
12606 (memory_object_control_t)control, file_offset + mach_header_map_size,
12607 (VM_PROT_READ | VM_PROT_WRITE));
12608
12609 if (ret != KERN_SUCCESS) {
12610 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12611 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12612 "Failed to map load commands of kc fileset with error %d", ret);
12613
12614 /* Unmap the mach header */
12615 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12616 return kOSKextReturnInvalidArgument;
12617 }
12618 }
12619
12620 kernel_segment_command_t *text_seg;
12621 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12622
12623 /* Calculate the slide and vm addr of mach header */
12624 if (slidep) {
12625 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12626 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12627 }
12628
12629 /* Cache the text segment size and file offset before unmapping */
12630 vm_map_offset_t text_segment_size = text_seg->vmsize;
12631 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12632 vm_prot_t text_maxprot = text_seg->maxprot;
12633
12634 /* Unmap the first page and loadcommands and map the text segment */
12635 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12636 assert(ret == KERN_SUCCESS);
12637
12638 if (load_command_map_size) {
12639 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12640 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12641 assert(ret == KERN_SUCCESS);
12642 }
12643
12644 /* Map the text segment at actual vm addr specified in fileset */
12645 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12646 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12647 if (ret != KERN_SUCCESS) {
12648 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12649 "Failed to map Text segment of kc fileset with error %d", ret);
12650 return kOSKextReturnInvalidArgument;
12651 }
12652
12653 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12654 return 0;
12655 }
12656
12657 /*********************************************************************
12658 * Assumes sKextLock is held.
12659 *********************************************************************/
12660 /* static */
12661 OSReturn
12662 OSKext::protectKCFileSet(
12663 kernel_mach_header_t *mh,
12664 kc_kind_t type)
12665 {
12666 vm_map_t kext_map = g_kext_map;
12667 kernel_segment_command_t * seg = NULL;
12668 vm_map_offset_t start = 0;
12669 vm_map_offset_t end = 0;
12670 OSReturn ret = 0;
12671
12672 /* Set VM permissions */
12673 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12674 while (seg) {
12675 start = round_page(seg->vmaddr);
12676 end = trunc_page(seg->vmaddr + seg->vmsize);
12677
12678 /*
12679 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12680 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12681 * for the Aux KC as well.
12682 */
12683 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12684 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12685 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12686 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12687 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12688 ret = OSKext_protect((kernel_mach_header_t *)mh,
12689 kext_map, start, end, seg->maxprot, TRUE, type);
12690 if (ret != KERN_SUCCESS) {
12691 printf("OSKext protect failed with error %d", ret);
12692 return kOSKextReturnInvalidArgument;
12693 }
12694
12695 ret = OSKext_protect((kernel_mach_header_t *)mh,
12696 kext_map, start, end, seg->initprot, FALSE, type);
12697 if (ret != KERN_SUCCESS) {
12698 printf("OSKext protect failed with error %d", ret);
12699 return kOSKextReturnInvalidArgument;
12700 }
12701
12702 ret = OSKext_wire((kernel_mach_header_t *)mh,
12703 kext_map, start, end, seg->initprot, FALSE, type);
12704 if (ret != KERN_SUCCESS) {
12705 printf("OSKext wire failed with error %d", ret);
12706 return kOSKextReturnInvalidArgument;
12707 }
12708 }
12709
12710 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12711 }
12712
12713 return 0;
12714 }
12715
12716 /*********************************************************************
12717 * Assumes sKextLock is held.
12718 *********************************************************************/
12719 /* static */
12720 void
12721 OSKext::freeKCFileSetcontrol(void)
12722 {
12723 PE_reset_all_kc_vp();
12724 }
12725
12726 /*********************************************************************
12727 * Assumes sKextLock is held.
12728 *
12729 * resetKCFileSetSegments: Kext start function expects data segment to
12730 * be pristine on every load, unmap the dirty segments on unload and
12731 * remap them from FileSet on disk. Remap all segments of kext since
12732 * fixups are done per kext and not per segment.
12733 *********************************************************************/
12734 OSReturn
12735 OSKext::resetKCFileSetSegments(void)
12736 {
12737 kernel_segment_command_t *seg = NULL;
12738 kernel_segment_command_t *text_seg;
12739 uint32_t text_fileoff;
12740 kernel_mach_header_t *k_mh = NULL;
12741 uintptr_t slide;
12742 struct vnode *vp = NULL;
12743 void *fileset_control = NULL;
12744 bool pageable = (kc_type == KCKindPageable);
12745 OSReturn err;
12746 kern_return_t kr;
12747
12748 /* Check the vnode reference is still available */
12749 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12750 if (vp == NULL) {
12751 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12752 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12753 return kOSKextReturnInternalError;
12754 }
12755
12756 fileset_control = ubc_getobject(vp, 0);
12757 assert(fileset_control != NULL);
12758
12759 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12760 "Kext %s resetting all segments", getIdentifierCString());
12761
12762 k_mh = (kernel_mach_header_t *)kmod_info->address;
12763 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12764 text_fileoff = text_seg->fileoff;
12765 slide = PE_get_kc_slide(kc_type);
12766
12767 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12768 while (seg) {
12769 if (seg->vmsize == 0) {
12770 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12771 continue;
12772 }
12773
12774 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12775 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12776 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12777 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12778 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12779 continue;
12780 }
12781
12782 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12783 assert(kr == KERN_SUCCESS);
12784 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12785 }
12786
12787 /* Unmap the text segment */
12788 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12789 assert(kr == KERN_SUCCESS);
12790
12791 /* Map all the segments of the kext */
12792 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12793 if (err) {
12794 panic("Could not reset segments of a mapped kext, error %x", err);
12795 }
12796
12797 /* Update address in kmod_info, since it has been reset */
12798 if (kmod_info->address) {
12799 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12800 }
12801
12802 return 0;
12803 }
12804
12805 /*********************************************************************
12806 * Mechanism to track all segment mapping while mapping KC fileset.
12807 *********************************************************************/
12808
12809 struct kcfileset_map_entry {
12810 vm_map_offset_t me_start;
12811 vm_map_offset_t me_size;
12812 };
12813
12814 struct kcfileset_map_entry_list {
12815 int kme_list_count;
12816 int kme_list_index;
12817 struct kcfileset_map_entry kme_list[];
12818 };
12819
12820 #define KCFILESET_MAP_ENTRY_MAX (16380)
12821
12822 static void *
12823 allocate_kcfileset_map_entry_list(void)
12824 {
12825 struct kcfileset_map_entry_list *entry_list;
12826
12827 entry_list = kalloc_type(struct kcfileset_map_entry_list,
12828 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
12829
12830 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12831 entry_list->kme_list_index = 0;
12832 return entry_list;
12833 }
12834
12835 static void
12836 add_kcfileset_map_entry(
12837 void *map_entry_list,
12838 vm_map_offset_t start,
12839 vm_map_offset_t size)
12840 {
12841 if (map_entry_list == NULL) {
12842 return;
12843 }
12844
12845 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12846
12847 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12848 panic("Ran out of map kc fileset list");
12849 }
12850
12851 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12852 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12853
12854 entry_list->kme_list_index++;
12855 }
12856
12857 static void
12858 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12859 void *map_entry_list,
12860 boolean_t unmap_entries,
12861 bool pageable)
12862 {
12863 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12864
12865 if (unmap_entries) {
12866 for (int i = 0; i < entry_list->kme_list_index; i++) {
12867 kern_return_t ret;
12868 ret = vm_unmap_kcfileset_segment(
12869 &(entry_list->kme_list[i].me_start),
12870 entry_list->kme_list[i].me_size);
12871 assert(ret == KERN_SUCCESS);
12872 }
12873
12874 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
12875 }
12876
12877 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
12878 KCFILESET_MAP_ENTRY_MAX, entry_list);
12879 }
12880
12881 /*********************************************************************
12882 * Mechanism to map kext segment.
12883 *********************************************************************/
12884
12885 kern_return_t
12886 vm_map_kcfileset_segment(
12887 vm_map_offset_t *start,
12888 vm_map_offset_t size,
12889 void *control,
12890 vm_object_offset_t fileoffset,
12891 vm_prot_t max_prot)
12892 {
12893 vm_map_kernel_flags_t vmk_flags = VM_MAP_KERNEL_FLAGS_NONE;
12894 vmk_flags.vmkf_no_copy_on_read = 1;
12895 vmk_flags.vmkf_cs_enforcement = 0;
12896 vmk_flags.vmkf_cs_enforcement_override = 1;
12897 kern_return_t ret;
12898
12899 /* Add Write to max prot to allow fixups */
12900 max_prot = max_prot | VM_PROT_WRITE;
12901
12902 /*
12903 * Map the segments from file as COPY mappings to
12904 * make sure changes on disk to the file does not affect
12905 * mapped segments.
12906 */
12907 ret = vm_map_enter_mem_object_control(
12908 g_kext_map,
12909 start,
12910 size,
12911 (mach_vm_offset_t)0,
12912 VM_FLAGS_FIXED,
12913 vmk_flags,
12914 VM_KERN_MEMORY_OSKEXT,
12915 (memory_object_control_t)control,
12916 fileoffset,
12917 TRUE, /* copy */
12918 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12919 VM_INHERIT_NONE);
12920
12921 return ret;
12922 }
12923
12924 kern_return_t
12925 vm_unmap_kcfileset_segment(
12926 vm_map_offset_t *start,
12927 vm_map_offset_t size)
12928 {
12929 return mach_vm_deallocate(g_kext_map, *start, size);
12930 }
12931
12932 #endif //(__x86_64__) || defined(__i386__)
12933
12934 /*********************************************************************
12935 * Assumes sKextLock is held.
12936 *********************************************************************/
12937 /* static */
12938 OSReturn
12939 OSKext::validateKCFileSetUUID(
12940 OSDictionary *infoDict,
12941 kc_kind_t type)
12942 {
12943 OSReturn ret = kOSReturnSuccess;
12944
12945 if (!kernelcache_uuid_valid) {
12946 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12947 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12948 ret = kOSKextReturnInvalidArgument;
12949 goto finish;
12950 }
12951 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12952 if (ret != 0) {
12953 goto finish;
12954 }
12955
12956 #if defined(__x86_64__) || defined(__i386__)
12957 /* Check if the Aux KC is prelinked to correct Pageable KC */
12958 if (type == KCKindAuxiliary) {
12959 if (!pageablekc_uuid_valid) {
12960 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12961 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12962 ret = kOSKextReturnInvalidArgument;
12963 goto finish;
12964 }
12965 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12966 if (ret != 0) {
12967 goto finish;
12968 }
12969 }
12970 #endif //(__x86_64__) || defined(__i386__)
12971
12972 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12973 finish:
12974 return ret;
12975 }
12976
12977 /*********************************************************************
12978 * Assumes sKextLock is held.
12979 *********************************************************************/
12980 /* static */
12981 OSReturn
12982 OSKext::validateKCUUIDfromPrelinkInfo(
12983 uuid_t *loaded_kcuuid,
12984 kc_kind_t type,
12985 OSDictionary *infoDict,
12986 const char *uuid_key)
12987 {
12988 /* extract the UUID from the dictionary */
12989 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12990 if (!prelinkinfoKCUUID) {
12991 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12992 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12993 return kOSKextReturnInvalidArgument;
12994 }
12995
12996 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12997 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12998 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12999 return kOSKextReturnInvalidArgument;
13000 }
13001
13002 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
13003 prelinkinfoKCUUID->getLength())) {
13004 OSData *info_dict_uuid;
13005 uuid_string_t info_dict_uuid_str = {};
13006 uuid_string_t expected_uuid_str = {};
13007 uuid_string_t given_uuid_str = {};
13008 uuid_t given_uuid;
13009
13010 /* extract the KC UUID from the dictionary */
13011 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
13012 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
13013 uuid_t tmp_uuid;
13014 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
13015 uuid_unparse(tmp_uuid, info_dict_uuid_str);
13016 }
13017
13018 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
13019 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
13020 uuid_unparse(given_uuid, given_uuid_str);
13021
13022 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
13023 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
13024 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13025 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
13026 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
13027 if (type == KCKindPageable && sPanicOnKCMismatch) {
13028 panic("System KC UUID %s linked against %s, but %s is loaded",
13029 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
13030 }
13031 return kOSKextReturnInvalidArgument;
13032 }
13033
13034 return 0;
13035 }
13036
13037 /*********************************************************************
13038 * Assumes sKextLock is held.
13039 *********************************************************************/
13040 /* static */
13041 OSReturn
13042 OSKext::dispatchResource(OSDictionary * requestDict)
13043 {
13044 OSReturn result = kOSReturnError;
13045 OSSharedPtr<OSDictionary> callbackRecord;
13046 OSNumber * requestTag = NULL; // do not release
13047 OSNumber * requestResult = NULL; // do not release
13048 OSData * dataObj = NULL; // do not release
13049 uint32_t dataLength = 0;
13050 const void * dataPtr = NULL; // do not free
13051 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
13052 OSKextRequestResourceCallback callback = NULL;
13053 OSValueObject<void *> * contextWrapper = nullptr; // do not release
13054 void * context = NULL; // do not free
13055 OSSharedPtr<OSKext> callbackKext;
13056
13057 /* Get the args from the request. Right now we need the tag
13058 * to look up the callback record, and the result for invoking the callback.
13059 */
13060 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
13061 kKextRequestArgumentRequestTagKey));
13062 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
13063 kKextRequestArgumentResultKey));
13064 if (!requestTag || !requestResult) {
13065 result = kOSKextReturnInvalidArgument;
13066 goto finish;
13067 }
13068
13069 /* Look for a callback record matching this request's tag.
13070 */
13071 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
13072 if (result != kOSReturnSuccess) {
13073 goto finish;
13074 }
13075
13076 /*****
13077 * Get the context pointer of the callback record (if there is one).
13078 */
13079 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
13080 callbackRecord.get(), kKextRequestArgumentContextKey));
13081 context = _OSKextExtractPointer(contextWrapper);
13082 if (contextWrapper && !context) {
13083 goto finish;
13084 }
13085
13086 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
13087 _OSKextGetRequestArgument(callbackRecord.get(),
13088 kKextRequestArgumentCallbackKey));
13089 callback = _OSKextExtractCallbackPointer(callbackWrapper);
13090 if (!callback) {
13091 goto finish;
13092 }
13093
13094 /* Check for a data obj. We might not have one and that's ok, that means
13095 * we didn't find the requested resource, and we still have to tell the
13096 * caller that via the callback.
13097 */
13098 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
13099 kKextRequestArgumentValueKey));
13100 if (dataObj) {
13101 dataPtr = dataObj->getBytesNoCopy();
13102 dataLength = dataObj->getLength();
13103 }
13104
13105 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
13106 if (!callbackKext) {
13107 OSKextLog(/* kext */ NULL,
13108 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13109 "Can't invoke callback for resource request; ");
13110 goto finish;
13111 }
13112 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
13113 OSKextLog(/* kext */ NULL,
13114 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13115 "Can't invoke kext resource callback; ");
13116 goto finish;
13117 }
13118
13119 (void)callback(requestTag->unsigned32BitValue(),
13120 (OSReturn)requestResult->unsigned32BitValue(),
13121 dataPtr, dataLength, context);
13122
13123 result = kOSReturnSuccess;
13124
13125 finish:
13126 return result;
13127 }
13128
13129 /*********************************************************************
13130 * Assumes sKextLock is held.
13131 *********************************************************************/
13132 /* static */
13133 OSReturn
13134 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
13135 {
13136 OSSharedPtr<OSDictionary> missingIDs;
13137 OSArray *bundleIDList = NULL; // do not release
13138
13139 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
13140 requestDict, kKextRequestArgumentMissingBundleIDs));
13141 if (!bundleIDList) {
13142 return kOSKextReturnInvalidArgument;
13143 }
13144
13145 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
13146 if (!missingIDs) {
13147 return kOSKextReturnNoMemory;
13148 }
13149
13150 uint32_t count, i;
13151 count = bundleIDList->getCount();
13152 for (i = 0; i < count; i++) {
13153 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
13154 if (thisID) {
13155 missingIDs->setObject(thisID, kOSBooleanFalse);
13156 }
13157 }
13158
13159 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13160
13161 return kOSReturnSuccess;
13162 }
13163
13164 /*********************************************************************
13165 * Assumes sKextLock is held.
13166 *********************************************************************/
13167 /* static */
13168 OSReturn
13169 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13170 {
13171 bool loadable = true;
13172 if (!kextIdentifier) {
13173 return kOSKextReturnInvalidArgument;
13174 }
13175
13176 if (requestDict) {
13177 OSBoolean *loadableArg;
13178 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13179 requestDict, kKextRequestArgumentBundleAvailability));
13180 /* If we find the "Bundle Available" arg, and it's false, then
13181 * mark the bundle ID as _not_ loadable
13182 */
13183 if (loadableArg && !loadableArg->getValue()) {
13184 loadable = false;
13185 }
13186 }
13187
13188 if (!sNonLoadableKextsByID) {
13189 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13190 }
13191
13192 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13193
13194 OSKextLog(/* kext */ NULL,
13195 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13196 "KextLog: AuxKC bundle %s marked as %s",
13197 kextIdentifier->getCStringNoCopy(),
13198 (loadable ? "loadable" : "NOT loadable"));
13199
13200 return kOSReturnSuccess;
13201 }
13202
13203 /*********************************************************************
13204 *********************************************************************/
13205 /* static */
13206 void
13207 OSKext::invokeRequestCallback(
13208 OSDictionary * callbackRecord,
13209 OSReturn callbackResult)
13210 {
13211 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
13212 OSSharedPtr<OSNumber> resultNum;
13213
13214 if (!predicate) {
13215 goto finish;
13216 }
13217
13218 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13219 8 * sizeof(callbackResult));
13220 if (!resultNum) {
13221 goto finish;
13222 }
13223
13224 /* Insert the result into the callback record and dispatch it as if it
13225 * were the reply coming down from user space.
13226 */
13227 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
13228 resultNum.get());
13229
13230 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13231 /* This removes the pending callback record.
13232 */
13233 OSKext::dispatchResource(callbackRecord);
13234 }
13235
13236 finish:
13237 return;
13238 }
13239
13240 /*********************************************************************
13241 * Assumes sKextLock is held.
13242 *********************************************************************/
13243 /* static */
13244 OSReturn
13245 OSKext::cancelRequest(
13246 OSKextRequestTag requestTag,
13247 void ** contextOut)
13248 {
13249 OSReturn result = kOSKextReturnNoMemory;
13250 OSSharedPtr<OSDictionary> callbackRecord;
13251 OSValueObject<void *> * contextWrapper = nullptr; // do not release
13252
13253 IORecursiveLockLock(sKextLock);
13254 result = OSKext::dequeueCallbackForRequestTag(requestTag,
13255 callbackRecord);
13256 IORecursiveLockUnlock(sKextLock);
13257
13258 if (result == kOSReturnSuccess && contextOut) {
13259 contextWrapper = OSDynamicCast(OSValueObject<void *>,
13260 _OSKextGetRequestArgument(callbackRecord.get(),
13261 kKextRequestArgumentContextKey));
13262 *contextOut = _OSKextExtractPointer(contextWrapper);
13263 }
13264
13265 return result;
13266 }
13267
13268 /*********************************************************************
13269 * Assumes sKextLock is held.
13270 *********************************************************************/
13271 void
13272 OSKext::invokeOrCancelRequestCallbacks(
13273 OSReturn callbackResult,
13274 bool invokeFlag)
13275 {
13276 unsigned int count, i;
13277
13278 count = sRequestCallbackRecords->getCount();
13279 if (!count) {
13280 goto finish;
13281 }
13282
13283 i = count - 1;
13284 do {
13285 OSDictionary * request = OSDynamicCast(OSDictionary,
13286 sRequestCallbackRecords->getObject(i));
13287
13288 if (!request) {
13289 continue;
13290 }
13291 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
13292 _OSKextGetRequestArgument(request,
13293 kKextRequestArgumentCallbackKey));
13294
13295 if (!callbackWrapper) {
13296 sRequestCallbackRecords->removeObject(i);
13297 continue;
13298 }
13299
13300 vm_address_t callbackAddress = (vm_address_t)
13301 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13302
13303 if ((kmod_info->address <= callbackAddress) &&
13304 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13305 if (invokeFlag) {
13306 /* This removes the callback record.
13307 */
13308 invokeRequestCallback(request, callbackResult);
13309 } else {
13310 sRequestCallbackRecords->removeObject(i);
13311 }
13312 }
13313 } while (i--);
13314
13315 finish:
13316 return;
13317 }
13318
13319 /*********************************************************************
13320 * Assumes sKextLock is held.
13321 *********************************************************************/
13322 uint32_t
13323 OSKext::countRequestCallbacks(void)
13324 {
13325 uint32_t result = 0;
13326 unsigned int count, i;
13327
13328 count = sRequestCallbackRecords->getCount();
13329 if (!count) {
13330 goto finish;
13331 }
13332
13333 i = count - 1;
13334 do {
13335 OSDictionary * request = OSDynamicCast(OSDictionary,
13336 sRequestCallbackRecords->getObject(i));
13337
13338 if (!request) {
13339 continue;
13340 }
13341 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
13342 _OSKextGetRequestArgument(request,
13343 kKextRequestArgumentCallbackKey));
13344
13345 if (!callbackWrapper) {
13346 continue;
13347 }
13348
13349 vm_address_t callbackAddress = (vm_address_t)
13350 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13351
13352 if ((kmod_info->address <= callbackAddress) &&
13353 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13354 result++;
13355 }
13356 } while (i--);
13357
13358 finish:
13359 return result;
13360 }
13361
13362 /*********************************************************************
13363 *********************************************************************/
13364 static OSReturn
13365 _OSKextCreateRequest(
13366 const char * predicate,
13367 OSSharedPtr<OSDictionary> & requestR)
13368 {
13369 OSReturn result = kOSKextReturnNoMemory;
13370 OSSharedPtr<OSDictionary> request;
13371
13372 request = OSDictionary::withCapacity(2);
13373 if (!request) {
13374 goto finish;
13375 }
13376 result = _OSDictionarySetCStringValue(request.get(),
13377 kKextRequestPredicateKey, predicate);
13378 if (result != kOSReturnSuccess) {
13379 goto finish;
13380 }
13381 result = kOSReturnSuccess;
13382
13383 finish:
13384 if (result == kOSReturnSuccess) {
13385 requestR = os::move(request);
13386 }
13387
13388 return result;
13389 }
13390
13391 /*********************************************************************
13392 *********************************************************************/
13393 static OSString *
13394 _OSKextGetRequestPredicate(OSDictionary * requestDict)
13395 {
13396 return OSDynamicCast(OSString,
13397 requestDict->getObject(kKextRequestPredicateKey));
13398 }
13399
13400 /*********************************************************************
13401 *********************************************************************/
13402 static OSObject *
13403 _OSKextGetRequestArgument(
13404 OSDictionary * requestDict,
13405 const char * argName)
13406 {
13407 OSDictionary * args = OSDynamicCast(OSDictionary,
13408 requestDict->getObject(kKextRequestArgumentsKey));
13409 if (args) {
13410 return args->getObject(argName);
13411 }
13412 return NULL;
13413 }
13414
13415 /*********************************************************************
13416 *********************************************************************/
13417 static bool
13418 _OSKextSetRequestArgument(
13419 OSDictionary * requestDict,
13420 const char * argName,
13421 OSMetaClassBase * value)
13422 {
13423 OSDictionary * args = OSDynamicCast(OSDictionary,
13424 requestDict->getObject(kKextRequestArgumentsKey));
13425 OSSharedPtr<OSDictionary> newArgs;
13426 if (!args) {
13427 newArgs = OSDictionary::withCapacity(2);
13428 args = newArgs.get();
13429 if (!args) {
13430 goto finish;
13431 }
13432 requestDict->setObject(kKextRequestArgumentsKey, args);
13433 }
13434 if (args) {
13435 return args->setObject(argName, value);
13436 }
13437 finish:
13438 return false;
13439 }
13440
13441 /*********************************************************************
13442 *********************************************************************/
13443 template <typename T>
13444 static T *
13445 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
13446 {
13447 if (!wrapper) {
13448 return nullptr;
13449 }
13450 return wrapper->getRef();
13451 }
13452
13453 /*********************************************************************
13454 *********************************************************************/
13455 static OSKextRequestResourceCallback
13456 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
13457 {
13458 if (!wrapper) {
13459 return nullptr;
13460 }
13461 return wrapper->getRef();
13462 }
13463
13464
13465 /*********************************************************************
13466 *********************************************************************/
13467 static OSReturn
13468 _OSDictionarySetCStringValue(
13469 OSDictionary * dict,
13470 const char * cKey,
13471 const char * cValue)
13472 {
13473 OSReturn result = kOSKextReturnNoMemory;
13474 OSSharedPtr<const OSSymbol> key;
13475 OSSharedPtr<OSString> value;
13476
13477 key = OSSymbol::withCString(cKey);
13478 value = OSString::withCString(cValue);
13479 if (!key || !value) {
13480 goto finish;
13481 }
13482 if (dict->setObject(key.get(), value.get())) {
13483 result = kOSReturnSuccess;
13484 }
13485
13486 finish:
13487 return result;
13488 }
13489
13490 /*********************************************************************
13491 *********************************************************************/
13492 static bool
13493 _OSArrayContainsCString(
13494 OSArray * array,
13495 const char * cString)
13496 {
13497 bool result = false;
13498 OSSharedPtr<const OSSymbol> symbol;
13499 uint32_t count, i;
13500
13501 if (!array || !cString) {
13502 goto finish;
13503 }
13504
13505 symbol = OSSymbol::withCStringNoCopy(cString);
13506 if (!symbol) {
13507 goto finish;
13508 }
13509
13510 count = array->getCount();
13511 for (i = 0; i < count; i++) {
13512 OSObject * thisObject = array->getObject(i);
13513 if (symbol->isEqualTo(thisObject)) {
13514 result = true;
13515 goto finish;
13516 }
13517 }
13518
13519 finish:
13520 return result;
13521 }
13522
13523 #if CONFIG_KXLD
13524 /*********************************************************************
13525 * We really only care about boot / system start up related kexts.
13526 * We return true if we're less than REBUILD_MAX_TIME since start up,
13527 * otherwise return false.
13528 *********************************************************************/
13529 bool
13530 _OSKextInPrelinkRebuildWindow(void)
13531 {
13532 static bool outside_the_window = false;
13533 AbsoluteTime my_abstime;
13534 UInt64 my_ns;
13535 SInt32 my_secs;
13536
13537 if (outside_the_window) {
13538 return false;
13539 }
13540 clock_get_uptime(&my_abstime);
13541 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13542 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13543 if (my_secs > REBUILD_MAX_TIME) {
13544 outside_the_window = true;
13545 return false;
13546 }
13547 return true;
13548 }
13549 #endif /* CONFIG_KXLD */
13550
13551 /*********************************************************************
13552 *********************************************************************/
13553 bool
13554 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13555 {
13556 int unLoadedCount, i;
13557 bool result = false;
13558
13559 IORecursiveLockLock(sKextLock);
13560
13561 if (sUnloadedPrelinkedKexts == NULL) {
13562 goto finish;
13563 }
13564 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13565 if (unLoadedCount == 0) {
13566 goto finish;
13567 }
13568
13569 for (i = 0; i < unLoadedCount; i++) {
13570 const OSSymbol * myBundleID; // do not release
13571
13572 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13573 if (!myBundleID) {
13574 continue;
13575 }
13576 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13577 result = true;
13578 break;
13579 }
13580 }
13581 finish:
13582 IORecursiveLockUnlock(sKextLock);
13583 return result;
13584 }
13585
13586 #if PRAGMA_MARK
13587 #pragma mark Personalities (IOKit Drivers)
13588 #endif
13589 /*********************************************************************
13590 *********************************************************************/
13591 /* static */
13592 OSSharedPtr<OSArray>
13593 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13594 {
13595 OSSharedPtr<OSArray> result;
13596 OSSharedPtr<OSCollectionIterator> kextIterator;
13597 OSSharedPtr<OSArray> personalities;
13598
13599 OSString * kextID = NULL; // do not release
13600 OSKext * theKext = NULL; // do not release
13601
13602 IORecursiveLockLock(sKextLock);
13603
13604 /* Let's conservatively guess that any given kext has around 3
13605 * personalities for now.
13606 */
13607 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13608 if (!result) {
13609 goto finish;
13610 }
13611
13612 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
13613 if (!kextIterator) {
13614 goto finish;
13615 }
13616
13617 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
13618 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
13619 if (theKext->flags.requireExplicitLoad) {
13620 OSKextLog(theKext,
13621 kOSKextLogDebugLevel |
13622 kOSKextLogLoadFlag,
13623 "Kext %s requires an explicit kextload; "
13624 "omitting its personalities.",
13625 theKext->getIdentifierCString());
13626 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
13627 personalities = theKext->copyPersonalitiesArray();
13628 if (!personalities) {
13629 continue;
13630 }
13631 result->merge(personalities.get());
13632 } else {
13633 // xxx - check for better place to put this log msg
13634 OSKextLog(theKext,
13635 kOSKextLogWarningLevel |
13636 kOSKextLogLoadFlag,
13637 "Kext %s is not loadable during safe boot; "
13638 "omitting its personalities.",
13639 theKext->getIdentifierCString());
13640 }
13641 }
13642
13643 finish:
13644 IORecursiveLockUnlock(sKextLock);
13645
13646 return result;
13647 }
13648
13649 /*********************************************************************
13650 *********************************************************************/
13651 /* static */
13652 void
13653 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13654 {
13655 int numPersonalities = 0;
13656
13657 OSKextLog(/* kext */ NULL,
13658 kOSKextLogStepLevel |
13659 kOSKextLogLoadFlag,
13660 "Sending all eligible registered kexts' personalities "
13661 "to the IOCatalogue %s.",
13662 startMatching ? "and starting matching" : "but not starting matching");
13663
13664 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
13665 /* filterSafeBootFlag */ true);
13666
13667 if (personalities) {
13668 gIOCatalogue->addDrivers(personalities.get(), startMatching);
13669 numPersonalities = personalities->getCount();
13670 }
13671
13672 OSKextLog(/* kext */ NULL,
13673 kOSKextLogStepLevel |
13674 kOSKextLogLoadFlag,
13675 "%d kext personalit%s sent to the IOCatalogue; %s.",
13676 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13677 startMatching ? "matching started" : "matching not started");
13678 return;
13679 }
13680
13681 /*********************************************************************
13682 * Do not make a deep copy, just convert the IOKitPersonalities dict
13683 * to an array for sending to the IOCatalogue.
13684 *********************************************************************/
13685 OSSharedPtr<OSArray>
13686 OSKext::copyPersonalitiesArray(void)
13687 {
13688 OSSharedPtr<OSArray> result;
13689 OSDictionary * personalities = NULL; // do not release
13690 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
13691
13692 OSString * personalityName = NULL; // do not release
13693 OSString * personalityBundleIdentifier = NULL; // do not release
13694
13695 personalities = OSDynamicCast(OSDictionary,
13696 getPropertyForHostArch(kIOKitPersonalitiesKey));
13697 if (!personalities) {
13698 goto finish;
13699 }
13700
13701 result = OSArray::withCapacity(personalities->getCount());
13702 if (!result) {
13703 goto finish;
13704 }
13705
13706 personalitiesIterator =
13707 OSCollectionIterator::withCollection(personalities);
13708 if (!personalitiesIterator) {
13709 goto finish;
13710 }
13711 while ((personalityName = OSDynamicCast(OSString,
13712 personalitiesIterator->getNextObject()))) {
13713 OSDictionary * personality = OSDynamicCast(OSDictionary,
13714 personalities->getObject(personalityName));
13715
13716 if (personality) {
13717 /******
13718 * If the personality doesn't have a CFBundleIdentifier, or if it
13719 * differs from the kext's, insert the kext's ID so we can find it.
13720 * The publisher ID is used to remove personalities from bundles
13721 * correctly.
13722 */
13723 personalityBundleIdentifier = OSDynamicCast(OSString,
13724 personality->getObject(kCFBundleIdentifierKey));
13725
13726 if (!personalityBundleIdentifier) {
13727 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13728 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13729 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
13730 }
13731 }
13732
13733 result->setObject(personality);
13734 }
13735
13736 finish:
13737 return result;
13738 }
13739
13740 /*********************************************************************
13741 * Might want to change this to a bool return?
13742 *********************************************************************/
13743 OSReturn
13744 OSKext::sendPersonalitiesToCatalog(
13745 bool startMatching,
13746 OSArray * personalityNames)
13747 {
13748 OSReturn result = kOSReturnSuccess;
13749 OSSharedPtr<OSArray> personalitiesToSend;
13750 OSDictionary * kextPersonalities = NULL; // do not release
13751 int count, i;
13752
13753 if (!sLoadEnabled) {
13754 OSKextLog(this,
13755 kOSKextLogErrorLevel |
13756 kOSKextLogLoadFlag,
13757 "Kext loading is disabled (attempt to start matching for kext %s).",
13758 getIdentifierCString());
13759 result = kOSKextReturnDisabled;
13760 goto finish;
13761 }
13762
13763 if (sSafeBoot && !isLoadableInSafeBoot()) {
13764 OSKextLog(this,
13765 kOSKextLogErrorLevel |
13766 kOSKextLogLoadFlag,
13767 "Kext %s is not loadable during safe boot; "
13768 "not sending personalities to the IOCatalogue.",
13769 getIdentifierCString());
13770 result = kOSKextReturnNotLoadable;
13771 goto finish;
13772 }
13773
13774 if (!personalityNames || !personalityNames->getCount()) {
13775 personalitiesToSend = copyPersonalitiesArray();
13776 } else {
13777 kextPersonalities = OSDynamicCast(OSDictionary,
13778 getPropertyForHostArch(kIOKitPersonalitiesKey));
13779 if (!kextPersonalities || !kextPersonalities->getCount()) {
13780 // not an error
13781 goto finish;
13782 }
13783 personalitiesToSend = OSArray::withCapacity(0);
13784 if (!personalitiesToSend) {
13785 result = kOSKextReturnNoMemory;
13786 goto finish;
13787 }
13788 count = personalityNames->getCount();
13789 for (i = 0; i < count; i++) {
13790 OSString * name = OSDynamicCast(OSString,
13791 personalityNames->getObject(i));
13792 if (!name) {
13793 continue;
13794 }
13795 OSDictionary * personality = OSDynamicCast(OSDictionary,
13796 kextPersonalities->getObject(name));
13797 if (personality) {
13798 personalitiesToSend->setObject(personality);
13799 }
13800 }
13801 }
13802 if (personalitiesToSend) {
13803 unsigned numPersonalities = personalitiesToSend->getCount();
13804 OSKextLog(this,
13805 kOSKextLogStepLevel |
13806 kOSKextLogLoadFlag,
13807 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13808 getIdentifierCString(),
13809 numPersonalities,
13810 numPersonalities > 1 ? "ies" : "y",
13811 startMatching ? " and starting matching" : " but not starting matching");
13812 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
13813 }
13814 finish:
13815 return result;
13816 }
13817
13818 /*********************************************************************
13819 * xxx - We should allow removing the kext's declared personalities,
13820 * xxx - even with other bundle identifiers.
13821 *********************************************************************/
13822 void
13823 OSKext::removePersonalitiesFromCatalog(void)
13824 {
13825 OSSharedPtr<OSDictionary> personality;
13826
13827 personality = OSDictionary::withCapacity(1);
13828 if (!personality) {
13829 goto finish;
13830 }
13831 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
13832
13833 OSKextLog(this,
13834 kOSKextLogStepLevel |
13835 kOSKextLogLoadFlag,
13836 "Kext %s removing all personalities naming it from the IOCatalogue.",
13837 getIdentifierCString());
13838
13839 /* Have the IOCatalog remove all personalities matching this kext's
13840 * bundle ID and trigger matching anew.
13841 */
13842 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
13843
13844 finish:
13845 return;
13846 }
13847
13848
13849 #if PRAGMA_MARK
13850 #pragma mark Logging
13851 #endif
13852 /*********************************************************************
13853 * Do not call any function that takes sKextLock here!
13854 *********************************************************************/
13855 /* static */
13856 OSKextLogSpec
13857 OSKext::setUserSpaceLogFilter(
13858 OSKextLogSpec newUserLogFilter,
13859 bool captureFlag)
13860 {
13861 OSKextLogSpec result;
13862 bool allocError = false;
13863
13864 /* Do not call any function that takes sKextLoggingLock during
13865 * this critical block. That means do logging after.
13866 */
13867 IOLockLock(sKextLoggingLock);
13868
13869 result = sUserSpaceKextLogFilter;
13870 sUserSpaceKextLogFilter = newUserLogFilter;
13871
13872 if (newUserLogFilter && captureFlag &&
13873 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13874 // xxx - do some measurements for a good initial capacity?
13875 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13876 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13877
13878 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
13879 allocError = true;
13880 }
13881 }
13882
13883 IOLockUnlock(sKextLoggingLock);
13884
13885 /* If the config flag itself is changing, log the state change
13886 * going both ways, before setting up the user-space log arrays,
13887 * so that this is only logged in the kernel.
13888 */
13889 if (result != newUserLogFilter) {
13890 OSKextLog(/* kext */ NULL,
13891 kOSKextLogDebugLevel |
13892 kOSKextLogGeneralFlag,
13893 "User-space log flags changed from 0x%x to 0x%x.",
13894 result, newUserLogFilter);
13895 }
13896 if (allocError) {
13897 OSKextLog(/* kext */ NULL,
13898 kOSKextLogErrorLevel |
13899 kOSKextLogGeneralFlag,
13900 "Failed to allocate user-space log message arrays.");
13901 }
13902
13903 return result;
13904 }
13905
13906 /*********************************************************************
13907 * Do not call any function that takes sKextLock here!
13908 *********************************************************************/
13909 /* static */
13910 OSSharedPtr<OSArray>
13911 OSKext::clearUserSpaceLogFilter(void)
13912 {
13913 OSSharedPtr<OSArray> result;
13914 OSKextLogSpec oldLogFilter;
13915 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
13916
13917 /* Do not call any function that takes sKextLoggingLock during
13918 * this critical block. That means do logging after.
13919 */
13920 IOLockLock(sKextLoggingLock);
13921
13922 result = OSArray::withCapacity(2);
13923 if (result) {
13924 result->setObject(sUserSpaceLogSpecArray.get());
13925 result->setObject(sUserSpaceLogMessageArray.get());
13926 }
13927 sUserSpaceLogSpecArray.reset();
13928 sUserSpaceLogMessageArray.reset();
13929
13930 oldLogFilter = sUserSpaceKextLogFilter;
13931 sUserSpaceKextLogFilter = newLogFilter;
13932
13933 IOLockUnlock(sKextLoggingLock);
13934
13935 /* If the config flag itself is changing, log the state change
13936 * going both ways, after tearing down the user-space log
13937 * arrays, so this is only logged within the kernel.
13938 */
13939 if (oldLogFilter != newLogFilter) {
13940 OSKextLog(/* kext */ NULL,
13941 kOSKextLogDebugLevel |
13942 kOSKextLogGeneralFlag,
13943 "User-space log flags changed from 0x%x to 0x%x.",
13944 oldLogFilter, newLogFilter);
13945 }
13946
13947 return result;
13948 }
13949
13950
13951 /*********************************************************************
13952 * Do not call any function that takes sKextLock here!
13953 *********************************************************************/
13954 /* static */
13955 OSKextLogSpec
13956 OSKext::getUserSpaceLogFilter(void)
13957 {
13958 OSKextLogSpec result;
13959
13960 IOLockLock(sKextLoggingLock);
13961 result = sUserSpaceKextLogFilter;
13962 IOLockUnlock(sKextLoggingLock);
13963
13964 return result;
13965 }
13966
13967 /*********************************************************************
13968 * This function is called by OSMetaClass during kernel C++ setup.
13969 * Be careful what you access here; assume only OSKext::initialize()
13970 * has been called.
13971 *
13972 * Do not call any function that takes sKextLock here!
13973 *********************************************************************/
13974 #define VTRESET "\033[0m"
13975
13976 #define VTBOLD "\033[1m"
13977 #define VTUNDER "\033[4m"
13978
13979 #define VTRED "\033[31m"
13980 #define VTGREEN "\033[32m"
13981 #define VTYELLOW "\033[33m"
13982 #define VTBLUE "\033[34m"
13983 #define VTMAGENTA "\033[35m"
13984 #define VTCYAN "\033[36m"
13985
13986 inline const char *
13987 colorForFlags(OSKextLogSpec flags)
13988 {
13989 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13990
13991 switch (logLevel) {
13992 case kOSKextLogErrorLevel:
13993 return VTRED VTBOLD;
13994 case kOSKextLogWarningLevel:
13995 return VTRED;
13996 case kOSKextLogBasicLevel:
13997 return VTYELLOW VTUNDER;
13998 case kOSKextLogProgressLevel:
13999 return VTYELLOW;
14000 case kOSKextLogStepLevel:
14001 return VTGREEN;
14002 case kOSKextLogDetailLevel:
14003 return VTCYAN;
14004 case kOSKextLogDebugLevel:
14005 return VTMAGENTA;
14006 default:
14007 return ""; // white
14008 }
14009 }
14010
14011 inline bool
14012 logSpecMatch(
14013 OSKextLogSpec msgLogSpec,
14014 OSKextLogSpec logFilter)
14015 {
14016 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
14017 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
14018 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
14019
14020 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
14021 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
14022 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
14023
14024 /* Explicit messages always get logged.
14025 */
14026 if (msgLevel == kOSKextLogExplicitLevel) {
14027 return true;
14028 }
14029
14030 /* Warnings and errors are logged regardless of the flags.
14031 */
14032 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
14033 return true;
14034 }
14035
14036 /* A verbose message that isn't for a logging-enabled kext and isn't global
14037 * does *not* get logged.
14038 */
14039 if (!msgKextGlobal && !filterKextGlobal) {
14040 return false;
14041 }
14042
14043 /* Warnings and errors are logged regardless of the flags.
14044 * All other messages must fit the flags and
14045 * have a level at or below the filter.
14046 *
14047 */
14048 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
14049 return true;
14050 }
14051 return false;
14052 }
14053
14054 extern "C" {
14055 void
14056 OSKextLog(
14057 OSKext * aKext,
14058 OSKextLogSpec msgLogSpec,
14059 const char * format, ...)
14060 {
14061 va_list argList;
14062
14063 va_start(argList, format);
14064 OSKextVLog(aKext, msgLogSpec, format, argList);
14065 va_end(argList);
14066 }
14067
14068 void
14069 OSKextVLog(
14070 OSKext * aKext,
14071 OSKextLogSpec msgLogSpec,
14072 const char * format,
14073 va_list srcArgList)
14074 {
14075 extern int disableConsoleOutput;
14076
14077 bool logForKernel = false;
14078 bool logForUser = false;
14079 va_list argList;
14080 char stackBuffer[120];
14081 uint32_t length = 0;
14082 char * allocBuffer = NULL; // must kfree
14083 OSSharedPtr<OSNumber> logSpecNum;
14084 OSSharedPtr<OSString> logString;
14085 char * buffer = stackBuffer; // do not free
14086
14087 IOLockLock(sKextLoggingLock);
14088
14089 /* Set the kext/global bit in the message spec if we have no
14090 * kext or if the kext requests logging.
14091 */
14092 if (!aKext || aKext->flags.loggingEnabled) {
14093 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
14094 }
14095
14096 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
14097 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14098 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
14099 }
14100
14101 if (!(logForKernel || logForUser)) {
14102 goto finish;
14103 }
14104
14105 /* No goto from here until past va_end()!
14106 */
14107 va_copy(argList, srcArgList);
14108 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
14109 va_end(argList);
14110
14111 if (length + 1 >= sizeof(stackBuffer)) {
14112 allocBuffer = (char *)kalloc_data_tag(length + 1,
14113 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14114 if (!allocBuffer) {
14115 goto finish;
14116 }
14117
14118 /* No goto from here until past va_end()!
14119 */
14120 va_copy(argList, srcArgList);
14121 vsnprintf(allocBuffer, length + 1, format, argList);
14122 va_end(argList);
14123
14124 buffer = allocBuffer;
14125 }
14126
14127 /* If user space wants the log message, queue it up.
14128 */
14129 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14130 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
14131 logString = OSString::withCString(buffer);
14132 if (logSpecNum && logString) {
14133 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
14134 sUserSpaceLogMessageArray->setObject(logString.get());
14135 }
14136 }
14137
14138 /* Always log messages from the kernel according to the kernel's
14139 * log flags.
14140 */
14141 if (logForKernel) {
14142 /* If we are in console mode and have a custom log filter,
14143 * colorize the log message.
14144 */
14145 if (!disableConsoleOutput && sBootArgLogFilterFound) {
14146 const char * color = ""; // do not free
14147 color = colorForFlags(msgLogSpec);
14148 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14149 buffer, color[0] ? VTRESET : "");
14150 } else {
14151 printf("%s\n", buffer);
14152 }
14153 }
14154
14155 finish:
14156 IOLockUnlock(sKextLoggingLock);
14157
14158 if (allocBuffer) {
14159 kfree_data(allocBuffer, length + 1);
14160 }
14161 return;
14162 }
14163
14164 #if KASLR_IOREG_DEBUG
14165
14166 #define IOLOG_INDENT( the_indention ) \
14167 { \
14168 int i; \
14169 for ( i = 0; i < (the_indention); i++ ) { \
14170 IOLog(" "); \
14171 } \
14172 }
14173
14174 extern vm_offset_t vm_kernel_stext;
14175 extern vm_offset_t vm_kernel_etext;
14176 extern mach_vm_offset_t kext_alloc_base;
14177 extern mach_vm_offset_t kext_alloc_max;
14178
14179 bool ScanForAddrInObject(OSObject * theObject,
14180 int indent );
14181
14182 bool
14183 ScanForAddrInObject(OSObject * theObject,
14184 int indent)
14185 {
14186 const OSMetaClass * myTypeID;
14187 OSSharedPtr<OSCollectionIterator> myIter;
14188 OSSymbol * myKey;
14189 OSObject * myValue;
14190 bool myResult = false;
14191
14192 if (theObject == NULL) {
14193 IOLog("%s: theObject is NULL \n",
14194 __FUNCTION__);
14195 return myResult;
14196 }
14197
14198 myTypeID = OSTypeIDInst(theObject);
14199
14200 if (myTypeID == OSTypeID(OSDictionary)) {
14201 OSDictionary * myDictionary;
14202
14203 myDictionary = OSDynamicCast(OSDictionary, theObject);
14204 myIter = OSCollectionIterator::withCollection( myDictionary );
14205 if (myIter == NULL) {
14206 return myResult;
14207 }
14208
14209 // !! reset the iterator
14210 myIter->reset();
14211
14212 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14213 bool myTempResult;
14214
14215 myValue = myDictionary->getObject(myKey);
14216 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14217 if (myTempResult) {
14218 // if we ever get a true result return true
14219 myResult = true;
14220 IOLOG_INDENT(indent);
14221 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14222 }
14223 }
14224
14225 // !! release the iterator
14226 myIter.reset();
14227 } else if (myTypeID == OSTypeID(OSArray)) {
14228 OSArray * myArray;
14229
14230 myArray = OSDynamicCast(OSArray, theObject);
14231 myIter = OSCollectionIterator::withCollection(myArray);
14232 if (myIter == NULL) {
14233 return myResult;
14234 }
14235 // !! reset the iterator
14236 myIter->reset();
14237
14238 while ((myValue = myIter->getNextObject())) {
14239 bool myTempResult;
14240 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14241 if (myTempResult) {
14242 // if we ever get a true result return true
14243 myResult = true;
14244 IOLOG_INDENT(indent);
14245 IOLog("OSArray: \n");
14246 }
14247 }
14248 // !! release the iterator
14249 myIter.reset();
14250 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14251 // should we look for addresses in strings?
14252 } else if (myTypeID == OSTypeID(OSData)) {
14253 void * * myPtrPtr;
14254 unsigned int myLen;
14255 OSData * myDataObj;
14256
14257 myDataObj = OSDynamicCast(OSData, theObject);
14258 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14259 myLen = myDataObj->getLength();
14260
14261 if (myPtrPtr && myLen && myLen > 7) {
14262 int i;
14263 int myPtrCount = (myLen / sizeof(void *));
14264
14265 for (i = 0; i < myPtrCount; i++) {
14266 UInt64 numberValue = (UInt64) * (myPtrPtr);
14267
14268 if (kext_alloc_max != 0 &&
14269 numberValue >= kext_alloc_base &&
14270 numberValue < kext_alloc_max) {
14271 OSSharedPtr<OSKext> myKext;
14272 // IOLog("found OSData %p in kext map %p to %p \n",
14273 // *(myPtrPtr),
14274 // (void *) kext_alloc_base,
14275 // (void *) kext_alloc_max);
14276
14277 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14278 if (myKext) {
14279 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14280 *(myPtrPtr),
14281 myKext->getIdentifierCString());
14282 }
14283 myResult = true;
14284 }
14285 if (vm_kernel_etext != 0 &&
14286 numberValue >= vm_kernel_stext &&
14287 numberValue < vm_kernel_etext) {
14288 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14289 *(myPtrPtr),
14290 (void *) vm_kernel_stext,
14291 (void *) vm_kernel_etext);
14292 myResult = true;
14293 }
14294 myPtrPtr++;
14295 }
14296 }
14297 } else if (myTypeID == OSTypeID(OSBoolean)) {
14298 // do nothing here...
14299 } else if (myTypeID == OSTypeID(OSNumber)) {
14300 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14301
14302 UInt64 numberValue = number->unsigned64BitValue();
14303
14304 if (kext_alloc_max != 0 &&
14305 numberValue >= kext_alloc_base &&
14306 numberValue < kext_alloc_max) {
14307 OSSharedPtr<OSKext> myKext;
14308 IOLog("found OSNumber in kext map %p to %p \n",
14309 (void *) kext_alloc_base,
14310 (void *) kext_alloc_max);
14311 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14312
14313 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14314 if (myKext) {
14315 IOLog("found in kext \"%s\" \n",
14316 myKext->getIdentifierCString());
14317 }
14318
14319 myResult = true;
14320 }
14321 if (vm_kernel_etext != 0 &&
14322 numberValue >= vm_kernel_stext &&
14323 numberValue < vm_kernel_etext) {
14324 IOLog("found OSNumber in kernel text segment %p to %p \n",
14325 (void *) vm_kernel_stext,
14326 (void *) vm_kernel_etext);
14327 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14328 myResult = true;
14329 }
14330 }
14331 #if 0
14332 else {
14333 const OSMetaClass* myMetaClass = NULL;
14334
14335 myMetaClass = theObject->getMetaClass();
14336 if (myMetaClass) {
14337 IOLog("class %s \n", myMetaClass->getClassName());
14338 } else {
14339 IOLog("Unknown object \n" );
14340 }
14341 }
14342 #endif
14343
14344 return myResult;
14345 }
14346 #endif // KASLR_KEXT_DEBUG
14347 }; /* extern "C" */
14348
14349 #if PRAGMA_MARK
14350 #pragma mark Backtrace Dump & kmod_get_info() support
14351 #endif
14352 /*********************************************************************
14353 * This function must be safe to call in panic context.
14354 *********************************************************************/
14355 /* static */
14356 void
14357 OSKext::printKextsInBacktrace(
14358 vm_offset_t * addr __unused,
14359 unsigned int cnt __unused,
14360 int (* printf_func)(const char *fmt, ...) __unused,
14361 uint32_t flags __unused)
14362 {
14363 addr64_t summary_page = 0;
14364 addr64_t last_summary_page = 0;
14365 bool found_kmod = false;
14366 u_int i = 0;
14367
14368 if (kPrintKextsLock & flags) {
14369 if (!sKextSummariesLock) {
14370 return;
14371 }
14372 IOLockLock(sKextSummariesLock);
14373 }
14374
14375 if (!gLoadedKextSummaries) {
14376 (*printf_func)(" can't perform kext scan: no kext summary");
14377 goto finish;
14378 }
14379
14380 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14381 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14382 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14383 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14384 (*printf_func)(" can't perform kext scan: "
14385 "missing kext summary page %p", summary_page);
14386 goto finish;
14387 }
14388 }
14389
14390 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14391 OSKextLoadedKextSummary * summary;
14392
14393 summary = gLoadedKextSummaries->summaries + i;
14394 if (!summary->address) {
14395 continue;
14396 }
14397
14398 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14399 continue;
14400 }
14401
14402 if (!found_kmod) {
14403 if (!(kPrintKextsTerse & flags)) {
14404 (*printf_func)(" Kernel Extensions in backtrace:\n");
14405 }
14406 found_kmod = true;
14407 }
14408
14409 printSummary(summary, printf_func, flags);
14410 }
14411
14412 finish:
14413 if (kPrintKextsLock & flags) {
14414 IOLockUnlock(sKextSummariesLock);
14415 }
14416
14417 return;
14418 }
14419
14420 /*********************************************************************
14421 * This function must be safe to call in panic context.
14422 *********************************************************************/
14423 /* static */
14424 boolean_t
14425 OSKext::summaryIsInBacktrace(
14426 OSKextLoadedKextSummary * summary,
14427 vm_offset_t * addr,
14428 unsigned int cnt)
14429 {
14430 u_int i = 0;
14431
14432 for (i = 0; i < cnt; i++) {
14433 vm_offset_t kscan_addr = addr[i];
14434 #if __has_feature(ptrauth_calls)
14435 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14436 #endif /* __has_feature(ptrauth_calls) */
14437 if ((kscan_addr >= summary->text_exec_address) &&
14438 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
14439 return TRUE;
14440 }
14441 }
14442
14443 return FALSE;
14444 }
14445
14446 /*
14447 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14448 * sKextSummariesLock held.
14449 */
14450 OSKextLoadedKextSummary *
14451 OSKext::summaryForAddress(uintptr_t addr)
14452 {
14453 #if __has_feature(ptrauth_calls)
14454 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14455 #endif /* __has_feature(ptrauth_calls) */
14456 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14457 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14458 if (!summary->address) {
14459 continue;
14460 }
14461
14462 #if VM_MAPPED_KEXTS
14463 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14464 * support split kexts, but we also may unmap the kexts, which can
14465 * race with the above codepath (see OSKext::unload). As such,
14466 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14467 */
14468 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14469 return summary;
14470 }
14471 #else
14472 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14473 kernel_segment_command_t *seg;
14474
14475 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14476 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14477 return summary;
14478 }
14479 }
14480 #endif
14481 }
14482
14483 /* addr did not map to any kext */
14484 return NULL;
14485 }
14486
14487 /* static */
14488 void *
14489 OSKext::kextForAddress(const void *address)
14490 {
14491 void * image = NULL;
14492 OSKextActiveAccount * active;
14493 OSKext * kext = NULL;
14494 uint32_t baseIdx;
14495 uint32_t lim;
14496 uintptr_t addr = (uintptr_t) address;
14497 size_t i;
14498
14499 if (!addr) {
14500 return NULL;
14501 }
14502 #if __has_feature(ptrauth_calls)
14503 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14504 #endif /* __has_feature(ptrauth_calls) */
14505
14506 if (sKextAccountsCount) {
14507 IOSimpleLockLock(sKextAccountsLock);
14508 // bsearch sKextAccounts list
14509 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14510 active = &sKextAccounts[baseIdx + (lim >> 1)];
14511 if ((addr >= active->address) && (addr < active->address_end)) {
14512 kext = active->account->kext;
14513 if (kext && kext->kmod_info) {
14514 image = (void *) kext->kmod_info->address;
14515 }
14516 break;
14517 } else if (addr > active->address) {
14518 // move right
14519 baseIdx += (lim >> 1) + 1;
14520 lim--;
14521 }
14522 // else move left
14523 }
14524 IOSimpleLockUnlock(sKextAccountsLock);
14525 }
14526 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14527 image = (void *) &_mh_execute_header;
14528 }
14529 if (!image && gLoadedKextSummaries) {
14530 IOLockLock(sKextSummariesLock);
14531 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14532 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14533 if (addr >= summary->address && addr < summary->address + summary->size) {
14534 image = (void *)summary->address;
14535 }
14536 }
14537 IOLockUnlock(sKextSummariesLock);
14538 }
14539
14540 return image;
14541 }
14542
14543 /*
14544 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14545 * Safe to call in panic context.
14546 */
14547 static OSKextLoadedKextSummary *
14548 findSummary(uint32_t tagID)
14549 {
14550 OSKextLoadedKextSummary * summary;
14551 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14552 summary = gLoadedKextSummaries->summaries + i;
14553 if (summary->loadTag == tagID) {
14554 return summary;
14555 }
14556 }
14557 return NULL;
14558 }
14559
14560 /*********************************************************************
14561 * This function must be safe to call in panic context.
14562 *********************************************************************/
14563 void
14564 OSKext::printSummary(
14565 OSKextLoadedKextSummary * summary,
14566 int (* printf_func)(const char *fmt, ...),
14567 uint32_t flags)
14568 {
14569 kmod_reference_t * kmod_ref = NULL;
14570 uuid_string_t uuid;
14571 char version[kOSKextVersionMaxLength];
14572 uint64_t tmpAddr;
14573 uint64_t tmpSize;
14574 OSKextLoadedKextSummary *dependencySummary;
14575
14576 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14577 strlcpy(version, "unknown version", sizeof(version));
14578 }
14579 (void) uuid_unparse(summary->uuid, uuid);
14580
14581 #if defined(__arm__) || defined(__arm64__)
14582 tmpAddr = summary->text_exec_address;
14583 tmpSize = summary->text_exec_size;
14584 #else
14585 tmpAddr = summary->address;
14586 tmpSize = summary->size;
14587 #endif
14588 if (kPrintKextsUnslide & flags) {
14589 tmpAddr = ml_static_unslide(tmpAddr);
14590 }
14591 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14592 (kPrintKextsTerse & flags) ? "" : " ",
14593 summary->name, version, uuid,
14594 tmpAddr, tmpAddr + tmpSize - 1);
14595
14596 if (kPrintKextsTerse & flags) {
14597 return;
14598 }
14599
14600 /* print dependency info */
14601 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14602 kmod_ref;
14603 kmod_ref = kmod_ref->next) {
14604 kmod_info_t * rinfo;
14605
14606 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14607 (*printf_func)(" kmod dependency scan stopped "
14608 "due to missing dependency page: %p\n",
14609 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14610 break;
14611 }
14612 rinfo = kmod_ref->info;
14613
14614 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14615 (*printf_func)(" kmod dependency scan stopped "
14616 "due to missing kmod page: %p\n",
14617 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14618 break;
14619 }
14620
14621 if (!rinfo->address) {
14622 continue; // skip fake entries for built-ins
14623 }
14624
14625 dependencySummary = findSummary(rinfo->id);
14626 uuid[0] = 0x00;
14627 tmpAddr = rinfo->address;
14628 tmpSize = rinfo->size;
14629 if (dependencySummary) {
14630 (void) uuid_unparse(dependencySummary->uuid, uuid);
14631 #if defined(__arm__) || defined(__arm64__)
14632 tmpAddr = dependencySummary->text_exec_address;
14633 tmpSize = dependencySummary->text_exec_size;
14634 #endif
14635 }
14636
14637 if (kPrintKextsUnslide & flags) {
14638 tmpAddr = ml_static_unslide(tmpAddr);
14639 }
14640 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14641 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
14642 }
14643 return;
14644 }
14645
14646
14647 #if !defined(__arm__) && !defined(__arm64__)
14648 /*******************************************************************************
14649 * substitute() looks at an input string (a pointer within a larger buffer)
14650 * for a match to a substring, and on match it writes the marker & substitution
14651 * character to an output string, updating the scan (from) and
14652 * output (to) indexes as appropriate.
14653 *******************************************************************************/
14654 static int substitute(
14655 const char * scan_string,
14656 char * string_out,
14657 uint32_t * to_index,
14658 uint32_t * from_index,
14659 const char * substring,
14660 char marker,
14661 char substitution);
14662
14663 /* string_out must be at least KMOD_MAX_NAME bytes.
14664 */
14665 static int
14666 substitute(
14667 const char * scan_string,
14668 char * string_out,
14669 uint32_t * to_index,
14670 uint32_t * from_index,
14671 const char * substring,
14672 char marker,
14673 char substitution)
14674 {
14675 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
14676
14677 /* On a substring match, append the marker (if there is one) and then
14678 * the substitution character, updating the output (to) index accordingly.
14679 * Then update the input (from) length by the length of the substring
14680 * that got replaced.
14681 */
14682 if (!strncmp(scan_string, substring, substring_length)) {
14683 if (marker) {
14684 string_out[(*to_index)++] = marker;
14685 }
14686 string_out[(*to_index)++] = substitution;
14687 (*from_index) += substring_length;
14688 return 1;
14689 }
14690 return 0;
14691 }
14692
14693 /*******************************************************************************
14694 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14695 * KMOD_MAX_NAME characters and performs various substitutions of common
14696 * prefixes & substrings as defined by tables in kext_panic_report.h.
14697 *******************************************************************************/
14698 static void compactIdentifier(
14699 const char * identifier,
14700 char * identifier_out,
14701 char ** identifier_out_end);
14702
14703 static void
14704 compactIdentifier(
14705 const char * identifier,
14706 char * identifier_out,
14707 char ** identifier_out_end)
14708 {
14709 uint32_t from_index, to_index;
14710 uint32_t scan_from_index = 0;
14711 uint32_t scan_to_index = 0;
14712 subs_entry_t * subs_entry = NULL;
14713 int did_sub = 0;
14714
14715 from_index = to_index = 0;
14716 identifier_out[0] = '\0';
14717
14718 /* Replace certain identifier prefixes with shorter @+character sequences.
14719 * Check the return value of substitute() so we only replace the prefix.
14720 */
14721 for (subs_entry = &kext_identifier_prefix_subs[0];
14722 subs_entry->substring && !did_sub;
14723 subs_entry++) {
14724 did_sub = substitute(identifier, identifier_out,
14725 &scan_to_index, &scan_from_index,
14726 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14727 }
14728 did_sub = 0;
14729
14730 /* Now scan through the identifier looking for the common substrings
14731 * and replacing them with shorter !+character sequences via substitute().
14732 */
14733 for (/* see above */;
14734 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14735 /* see loop */) {
14736 const char * scan_string = &identifier[scan_from_index];
14737
14738 did_sub = 0;
14739
14740 if (scan_from_index) {
14741 for (subs_entry = &kext_identifier_substring_subs[0];
14742 subs_entry->substring && !did_sub;
14743 subs_entry++) {
14744 did_sub = substitute(scan_string, identifier_out,
14745 &scan_to_index, &scan_from_index,
14746 subs_entry->substring, '!', subs_entry->substitute);
14747 }
14748 }
14749
14750 /* If we didn't substitute, copy the input character to the output.
14751 */
14752 if (!did_sub) {
14753 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14754 }
14755 }
14756
14757 identifier_out[scan_to_index] = '\0';
14758 if (identifier_out_end) {
14759 *identifier_out_end = &identifier_out[scan_to_index];
14760 }
14761
14762 return;
14763 }
14764 #endif /* !defined(__arm__) && !defined(__arm64__) */
14765
14766 /*******************************************************************************
14767 * assemble_identifier_and_version() adds to a string buffer a compacted
14768 * bundle identifier followed by a version string.
14769 *******************************************************************************/
14770
14771 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14772 */
14773 static size_t assemble_identifier_and_version(
14774 kmod_info_t * kmod_info,
14775 char * identPlusVers,
14776 size_t bufSize);
14777
14778 static size_t
14779 assemble_identifier_and_version(
14780 kmod_info_t * kmod_info,
14781 char * identPlusVers,
14782 size_t bufSize)
14783 {
14784 size_t result = 0;
14785
14786 #if defined(__arm__) || defined(__arm64__)
14787 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14788 #else
14789 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14790 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
14791 #endif
14792 identPlusVers[result++] = '\t'; // increment for real char
14793 identPlusVers[result] = '\0'; // don't increment for nul char
14794 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14795 if (result >= bufSize) {
14796 identPlusVers[bufSize - 1] = '\0';
14797 result = bufSize - 1;
14798 }
14799
14800 return result;
14801 }
14802
14803 /*******************************************************************************
14804 * Assumes sKextLock is held.
14805 *******************************************************************************/
14806 /* static */
14807 int
14808 OSKext::saveLoadedKextPanicListTyped(
14809 const char * prefix,
14810 int invertFlag,
14811 int libsFlag,
14812 char * paniclist,
14813 uint32_t list_size)
14814 {
14815 int result = -1;
14816 unsigned int count, i;
14817
14818 count = sLoadedKexts->getCount();
14819 if (!count) {
14820 goto finish;
14821 }
14822
14823 i = count - 1;
14824 do {
14825 OSObject * rawKext = sLoadedKexts->getObject(i);
14826 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14827 int match;
14828 size_t identPlusVersLength;
14829 size_t tempLen;
14830 char identPlusVers[2 * KMOD_MAX_NAME];
14831
14832 if (!rawKext) {
14833 printf("OSKext::saveLoadedKextPanicListTyped - "
14834 "NULL kext in loaded kext list; continuing\n");
14835 continue;
14836 }
14837
14838 if (!theKext) {
14839 printf("OSKext::saveLoadedKextPanicListTyped - "
14840 "Kext type cast failed in loaded kext list; continuing\n");
14841 continue;
14842 }
14843
14844 /* Skip all built-in kexts.
14845 */
14846 if (theKext->isKernelComponent()) {
14847 continue;
14848 }
14849
14850 kmod_info_t * kmod_info = theKext->kmod_info;
14851
14852 /* Filter for kmod name (bundle identifier).
14853 */
14854 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14855 if ((match && invertFlag) || (!match && !invertFlag)) {
14856 continue;
14857 }
14858
14859 /* Filter for libraries (kexts that have a compatible version).
14860 */
14861 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14862 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14863 continue;
14864 }
14865
14866 if (!kmod_info ||
14867 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14868 printf("kext scan stopped due to missing kmod_info page: %p\n",
14869 kmod_info);
14870 goto finish;
14871 }
14872
14873 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14874 identPlusVers,
14875 sizeof(identPlusVers));
14876 if (!identPlusVersLength) {
14877 printf("error saving loaded kext info\n");
14878 goto finish;
14879 }
14880
14881 /* make sure everything fits and we null terminate.
14882 */
14883 tempLen = strlcat(paniclist, identPlusVers, list_size);
14884 if (tempLen >= list_size) {
14885 // panic list is full, keep it and null terminate
14886 paniclist[list_size - 1] = 0x00;
14887 result = 0;
14888 goto finish;
14889 }
14890 tempLen = strlcat(paniclist, "\n", list_size);
14891 if (tempLen >= list_size) {
14892 // panic list is full, keep it and null terminate
14893 paniclist[list_size - 1] = 0x00;
14894 result = 0;
14895 goto finish;
14896 }
14897 } while (i--);
14898
14899 result = 0;
14900 finish:
14901
14902 return result;
14903 }
14904
14905 /*********************************************************************
14906 *********************************************************************/
14907 /* static */
14908 void
14909 OSKext::saveLoadedKextPanicList(void)
14910 {
14911 char * newlist = NULL;
14912 uint32_t newlist_size = 0;
14913
14914 newlist_size = KEXT_PANICLIST_SIZE;
14915 newlist = (char *)kalloc_data_tag(newlist_size,
14916 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14917
14918 if (!newlist) {
14919 OSKextLog(/* kext */ NULL,
14920 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14921 "Couldn't allocate kext panic log buffer.");
14922 goto finish;
14923 }
14924
14925 newlist[0] = '\0';
14926
14927 // non-"com.apple." kexts
14928 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14929 /* libs? */ -1, newlist, newlist_size) != 0) {
14930 goto finish;
14931 }
14932 // "com.apple." nonlibrary kexts
14933 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14934 /* libs? */ 0, newlist, newlist_size) != 0) {
14935 goto finish;
14936 }
14937 // "com.apple." library kexts
14938 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14939 /* libs? */ 1, newlist, newlist_size) != 0) {
14940 goto finish;
14941 }
14942
14943 if (loaded_kext_paniclist) {
14944 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
14945 }
14946 loaded_kext_paniclist = newlist;
14947 newlist = NULL;
14948 loaded_kext_paniclist_size = newlist_size;
14949
14950 finish:
14951 if (newlist) {
14952 kfree_data(newlist, newlist_size);
14953 }
14954 return;
14955 }
14956
14957 /*********************************************************************
14958 * Assumes sKextLock is held.
14959 *********************************************************************/
14960 void
14961 OSKext::savePanicString(bool isLoading)
14962 {
14963 u_long len;
14964
14965 if (!kmod_info) {
14966 return; // do not goto finish here b/c of lock
14967 }
14968
14969 len = assemble_identifier_and_version( kmod_info,
14970 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14971 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14972 if (!len) {
14973 printf("error saving unloaded kext info\n");
14974 goto finish;
14975 }
14976
14977 if (isLoading) {
14978 last_loaded_strlen = len;
14979 last_loaded_address = (void *)kmod_info->address;
14980 last_loaded_size = kmod_info->size;
14981 clock_get_uptime(&last_loaded_timestamp);
14982 } else {
14983 last_unloaded_strlen = len;
14984 last_unloaded_address = (void *)kmod_info->address;
14985 last_unloaded_size = kmod_info->size;
14986 clock_get_uptime(&last_unloaded_timestamp);
14987 }
14988
14989 finish:
14990 return;
14991 }
14992
14993 /*********************************************************************
14994 *********************************************************************/
14995 /* static */
14996 void
14997 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
14998 {
14999 if (last_loaded_strlen) {
15000 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
15001 AbsoluteTime_to_scalar(&last_loaded_timestamp),
15002 last_loaded_strlen, last_loaded_str_buf,
15003 last_loaded_address, last_loaded_size);
15004 }
15005
15006 if (last_unloaded_strlen) {
15007 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
15008 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
15009 last_unloaded_strlen, last_unloaded_str_buf,
15010 last_unloaded_address, last_unloaded_size);
15011 }
15012
15013 printf_func("loaded kexts:\n");
15014 if (loaded_kext_paniclist &&
15015 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
15016 loaded_kext_paniclist[0]) {
15017 printf_func("%.*s",
15018 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
15019 loaded_kext_paniclist);
15020 } else {
15021 printf_func("(none)\n");
15022 }
15023 return;
15024 }
15025
15026 /*********************************************************************
15027 * Assumes sKextLock is held.
15028 *********************************************************************/
15029 /* static */
15030 void
15031 OSKext::updateLoadedKextSummaries(void)
15032 {
15033 kern_return_t result = KERN_FAILURE;
15034 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
15035 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
15036 OSKext *aKext;
15037 vm_map_offset_t start, end;
15038 size_t summarySize = 0;
15039 size_t size;
15040 u_int count;
15041 u_int maxKexts;
15042 u_int i, j;
15043 OSKextActiveAccount * accountingList;
15044 OSKextActiveAccount * prevAccountingList;
15045 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
15046
15047 prevAccountingList = NULL;
15048 prevAccountingListCount = 0;
15049
15050 #if DEVELOPMENT || DEBUG
15051 if (IORecursiveLockHaveLock(sKextLock) == false) {
15052 panic("sKextLock must be held");
15053 }
15054 #endif
15055
15056 IOLockLock(sKextSummariesLock);
15057
15058 count = sLoadedKexts->getCount();
15059 for (i = 0, maxKexts = 0; i < count; ++i) {
15060 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15061 maxKexts += (aKext && aKext->isExecutable());
15062 }
15063
15064 if (!maxKexts) {
15065 goto finish;
15066 }
15067 if (maxKexts < kOSKextTypicalLoadCount) {
15068 maxKexts = kOSKextTypicalLoadCount;
15069 }
15070
15071 /* Calculate the size needed for the new summary headers.
15072 */
15073
15074 size = sizeof(*gLoadedKextSummaries);
15075 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
15076 size = round_page(size);
15077
15078 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
15079 if (gLoadedKextSummaries) {
15080 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
15081 gLoadedKextSummaries = NULL;
15082 gLoadedKextSummariesTimestamp = mach_absolute_time();
15083 sLoadedKextSummariesAllocSize = 0;
15084 }
15085 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
15086 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
15087 if (result != KERN_SUCCESS) {
15088 goto finish;
15089 }
15090 summaryHeader = summaryHeaderAlloc;
15091 summarySize = size;
15092 } else {
15093 summaryHeader = gLoadedKextSummaries;
15094 summarySize = sLoadedKextSummariesAllocSize;
15095
15096 start = (vm_map_offset_t) summaryHeader;
15097 end = start + summarySize;
15098 result = vm_map_protect(kernel_map,
15099 start,
15100 end,
15101 VM_PROT_DEFAULT,
15102 FALSE);
15103 if (result != KERN_SUCCESS) {
15104 goto finish;
15105 }
15106 }
15107
15108 /* Populate the summary header.
15109 */
15110
15111 bzero(summaryHeader, summarySize);
15112 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
15113 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
15114
15115 /* Populate each kext summary.
15116 */
15117
15118 count = sLoadedKexts->getCount();
15119 accountingListAlloc = 0;
15120 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15121 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15122 if (!aKext || !aKext->isExecutable()) {
15123 continue;
15124 }
15125
15126 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
15127 summaryHeader->numSummaries++;
15128 accountingListAlloc++;
15129 }
15130
15131 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
15132 accountingListCount = 0;
15133 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15134 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15135 if (!aKext || !aKext->isExecutable()) {
15136 continue;
15137 }
15138
15139 OSKextActiveAccount activeAccount;
15140 aKext->updateActiveAccount(&activeAccount);
15141 // order by address
15142 for (idx = 0; idx < accountingListCount; idx++) {
15143 if (activeAccount.address < accountingList[idx].address) {
15144 break;
15145 }
15146 }
15147 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
15148 accountingList[idx] = activeAccount;
15149 accountingListCount++;
15150 }
15151 assert(accountingListCount == accountingListAlloc);
15152 /* Write protect the buffer and move it into place.
15153 */
15154
15155 start = (vm_map_offset_t) summaryHeader;
15156 end = start + summarySize;
15157
15158 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15159 if (result != KERN_SUCCESS) {
15160 goto finish;
15161 }
15162
15163 gLoadedKextSummaries = summaryHeader;
15164 gLoadedKextSummariesTimestamp = mach_absolute_time();
15165 sLoadedKextSummariesAllocSize = summarySize;
15166 summaryHeaderAlloc = NULL;
15167
15168 /* Call the magic breakpoint function through a static function pointer so
15169 * the compiler can't optimize the function away.
15170 */
15171 if (sLoadedKextSummariesUpdated) {
15172 (*sLoadedKextSummariesUpdated)();
15173 }
15174
15175 IOSimpleLockLock(sKextAccountsLock);
15176 prevAccountingList = sKextAccounts;
15177 prevAccountingListCount = sKextAccountsCount;
15178 sKextAccounts = accountingList;
15179 sKextAccountsCount = accountingListCount;
15180 IOSimpleLockUnlock(sKextAccountsLock);
15181
15182 finish:
15183 IOLockUnlock(sKextSummariesLock);
15184
15185 /* If we had to allocate a new buffer but failed to generate the summaries,
15186 * free that now.
15187 */
15188 if (summaryHeaderAlloc) {
15189 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15190 }
15191 if (prevAccountingList) {
15192 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15193 }
15194
15195 return;
15196 }
15197
15198 /*********************************************************************
15199 *********************************************************************/
15200 void
15201 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15202 {
15203 OSSharedPtr<OSData> uuid;
15204
15205 strlcpy(summary->name, getIdentifierCString(),
15206 sizeof(summary->name));
15207
15208 uuid = copyUUID();
15209 if (uuid) {
15210 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
15211 }
15212
15213 if (flags.builtin) {
15214 // this value will stop lldb from parsing the mach-o header
15215 // summary->address = UINT64_MAX;
15216 // summary->size = 0;
15217 summary->address = kmod_info->address;
15218 summary->size = kmod_info->size;
15219 } else {
15220 summary->address = kmod_info->address;
15221 summary->size = kmod_info->size;
15222 }
15223 summary->version = getVersion();
15224 summary->loadTag = kmod_info->id;
15225 summary->flags = 0;
15226 summary->reference_list = (uint64_t) kmod_info->reference_list;
15227
15228 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15229 if (summary->text_exec_address == 0) {
15230 // Fallback to __TEXT
15231 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15232 }
15233 return;
15234 }
15235
15236 /*********************************************************************
15237 *********************************************************************/
15238
15239 void
15240 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
15241 {
15242 kernel_mach_header_t *hdr = NULL;
15243 kernel_segment_command_t *seg = NULL;
15244
15245 bzero(accountp, sizeof(*accountp));
15246
15247 hdr = (kernel_mach_header_t *)kmod_info->address;
15248 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15249 /*
15250 * If this kext supports split segments (or is in a new
15251 * MH_FILESET kext collection), use the first
15252 * executable segment as the range for instructions
15253 * (and thus for backtracing.
15254 */
15255 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15256 if (seg->initprot & VM_PROT_EXECUTE) {
15257 break;
15258 }
15259 }
15260 }
15261 if (seg) {
15262 accountp->address = seg->vmaddr;
15263 if (accountp->address) {
15264 accountp->address_end = seg->vmaddr + seg->vmsize;
15265 }
15266 } else {
15267 /* For non-split kexts and for kexts without executable
15268 * segments, just use the kmod_info range (as the kext
15269 * is either all in one range or should not show up in
15270 * instruction backtraces).
15271 */
15272 accountp->address = kmod_info->address;
15273 if (accountp->address) {
15274 accountp->address_end = kmod_info->address + kmod_info->size;
15275 }
15276 }
15277
15278 accountp->account = this->account;
15279 }
15280
15281 bool
15282 OSKext::isDriverKit(void)
15283 {
15284 OSString *bundleType;
15285
15286 if (infoDict) {
15287 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15288 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15289 return TRUE;
15290 }
15291 }
15292 return FALSE;
15293 }
15294
15295 bool
15296 OSKext::isInFileset(void)
15297 {
15298 if (!kmod_info) {
15299 goto check_prelinked;
15300 }
15301
15302 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15303 return true;
15304 }
15305
15306 check_prelinked:
15307 if (isPrelinked()) {
15308 /*
15309 * If we haven't setup kmod_info yet, but we know
15310 * we're loading a prelinked kext in an MH_FILESET KC,
15311 * then return true
15312 */
15313 kc_format_t kc_format;
15314 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15315 return true;
15316 }
15317 }
15318 return false;
15319 }
15320
15321 bool
15322 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15323 {
15324 kern_return_t result;
15325 if (!super::init()) {
15326 return false;
15327 }
15328 if (seg == nullptr) {
15329 return false;
15330 }
15331 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
15332 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
15333 if (result != KERN_SUCCESS) {
15334 return false;
15335 }
15336 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15337 savedSegment = seg;
15338 vmsize = seg->vmsize;
15339 vmaddr = seg->vmaddr;
15340 return true;
15341 }
15342
15343 OSSharedPtr<OSKextSavedMutableSegment>
15344 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15345 {
15346 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15347 if (me && !me->initWithSegment(seg)) {
15348 return nullptr;
15349 }
15350 return me;
15351 }
15352
15353 void
15354 OSKextSavedMutableSegment::free(void)
15355 {
15356 if (data) {
15357 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15358 }
15359 }
15360
15361 vm_offset_t
15362 OSKextSavedMutableSegment::getVMAddr() const
15363 {
15364 return vmaddr;
15365 }
15366
15367 vm_offset_t
15368 OSKextSavedMutableSegment::getVMSize() const
15369 {
15370 return vmsize;
15371 }
15372
15373 OSReturn
15374 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15375 {
15376 if (seg != savedSegment) {
15377 return kOSKextReturnInvalidArgument;
15378 }
15379 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15380 return kOSKextReturnInvalidArgument;
15381 }
15382 memcpy((void *)seg->vmaddr, data, vmsize);
15383 return kOSReturnSuccess;
15384 }
15385
15386 extern "C" kern_return_t
15387 OSKextSetReceiptQueried(void)
15388 {
15389 OSKextLog(/* kext */ NULL,
15390 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
15391 "Setting kext receipt as queried");
15392
15393 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
15394 return KERN_SUCCESS;
15395 }
15396
15397 extern "C" const vm_allocation_site_t *
15398 OSKextGetAllocationSiteForCaller(uintptr_t address)
15399 {
15400 OSKextActiveAccount * active;
15401 vm_allocation_site_t * site;
15402 vm_allocation_site_t * releasesite;
15403
15404 uint32_t baseIdx;
15405 uint32_t lim;
15406 #if __has_feature(ptrauth_calls)
15407 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15408 #endif /* __has_feature(ptrauth_calls) */
15409
15410 IOSimpleLockLock(sKextAccountsLock);
15411 site = releasesite = NULL;
15412
15413 // bsearch sKextAccounts list
15414 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15415 active = &sKextAccounts[baseIdx + (lim >> 1)];
15416 if ((address >= active->address) && (address < active->address_end)) {
15417 site = &active->account->site;
15418 if (!site->tag) {
15419 vm_tag_alloc_locked(site, &releasesite);
15420 }
15421 break;
15422 } else if (address > active->address) {
15423 // move right
15424 baseIdx += (lim >> 1) + 1;
15425 lim--;
15426 }
15427 // else move left
15428 }
15429 IOSimpleLockUnlock(sKextAccountsLock);
15430 if (releasesite) {
15431 kern_allocation_name_release(releasesite);
15432 }
15433
15434 return site;
15435 }
15436
15437 #if DEVELOPMENT || DEBUG
15438 extern "C" void
15439 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
15440 {
15441 OSKextActiveAccount * active;
15442
15443 uint32_t baseIdx;
15444 uint32_t lim;
15445 #if __has_feature(ptrauth_calls)
15446 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15447 #endif /* __has_feature(ptrauth_calls) */
15448
15449 IOSimpleLockLock(sKextAccountsLock);
15450
15451 // bsearch sKextAccounts list
15452 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15453 active = &sKextAccounts[baseIdx + (lim >> 1)];
15454 if ((address >= active->address) && (address < active->address_end)) {
15455 cb(&active->account->task_refgrp);
15456 break;
15457 } else if (address > active->address) {
15458 // move right
15459 baseIdx += (lim >> 1) + 1;
15460 lim--;
15461 }
15462 // else move left
15463 }
15464 IOSimpleLockUnlock(sKextAccountsLock);
15465 }
15466 #endif /* DEVELOPMENT || DEBUG */
15467
15468 extern "C" uint32_t
15469 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
15470 {
15471 OSKextAccount * account = (typeof(account))site;
15472 const char * kname;
15473
15474 if (name) {
15475 if (account->kext) {
15476 kname = account->kext->getIdentifierCString();
15477 } else {
15478 kname = "<>";
15479 }
15480 strlcpy(name, kname, namelen);
15481 }
15482
15483 return account->loadTag;
15484 }
15485
15486 extern "C" void
15487 OSKextFreeSite(vm_allocation_site_t * site)
15488 {
15489 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15490 IOFreeType(freeAccount, OSKextAccount);
15491 }
15492
15493 /*********************************************************************
15494 *********************************************************************/
15495
15496 #if CONFIG_IMAGEBOOT
15497 int
15498 OSKextGetUUIDForName(const char *name, uuid_t uuid)
15499 {
15500 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
15501 if (!kext) {
15502 return 1;
15503 }
15504
15505 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
15506 if (uuid_data) {
15507 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
15508 return 0;
15509 }
15510
15511 return 1;
15512 }
15513 #endif
15514
15515 static int
15516 sysctl_willuserspacereboot
15517 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15518 {
15519 int new_value = 0, old_value = 0, changed = 0;
15520 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15521 if (error) {
15522 return error;
15523 }
15524 if (changed) {
15525 OSKext::willUserspaceReboot();
15526 }
15527 return 0;
15528 }
15529
15530 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15531 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15532 NULL, 0, sysctl_willuserspacereboot, "I", "");
15533