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 OSObject * value);
144 static void * _OSKextExtractPointer(OSData * wrapper);
145 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSData * wrapper);
146 static OSReturn _OSDictionarySetCStringValue(
147 OSDictionary * dict,
148 const char * key,
149 const char * value);
150 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
151 #if CONFIG_KXLD
152 static bool _OSKextInPrelinkRebuildWindow(void);
153 #endif
154
155 // We really should add containsObject() & containsCString to OSCollection & subclasses.
156 // So few pad slots, though....
157 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
158 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
159
160 /* Prelinked arm kexts do not have VM entries because the method we use to
161 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
162 * not work on ARM. To get around that, we must free prelinked kext
163 * executables with ml_static_mfree() instead of kext_free().
164 */
165 #if __i386__ || __x86_64__
166 #define VM_MAPPED_KEXTS 1
167 #define KASLR_KEXT_DEBUG 0
168 #define KASLR_IOREG_DEBUG 0
169 #elif __arm__ || __arm64__
170 #define VM_MAPPED_KEXTS 0
171 #define KASLR_KEXT_DEBUG 0
172 #else
173 #error Unsupported architecture
174 #endif
175
176 #if PRAGMA_MARK
177 #pragma mark Constants & Macros
178 #endif
179 /*********************************************************************
180 * Constants & Macros
181 *********************************************************************/
182
183 /* Use this number to create containers.
184 */
185 #define kOSKextTypicalLoadCount (150)
186
187 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
188 * A loaded kext will no dependents or external retains will have 2 retains.
189 */
190 #define kOSKextMinRetainCount (1)
191 #define kOSKextMinLoadedRetainCount (2)
192
193 /**********
194 * Strings and substrings used in dependency resolution.
195 */
196 #define APPLE_KEXT_PREFIX "com.apple."
197 #define KERNEL_LIB "com.apple.kernel"
198
199 #define PRIVATE_KPI "com.apple.kpi.private"
200
201 /* Version for compatbility pseudokexts (com.apple.kernel.*),
202 * compatible back to v6.0.
203 */
204 #define KERNEL6_LIB "com.apple.kernel.6.0"
205 #define KERNEL6_VERSION "7.9.9"
206
207 #define KERNEL_LIB_PREFIX "com.apple.kernel."
208 #define KPI_LIB_PREFIX "com.apple.kpi."
209
210 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
211
212 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
213 #define MINIMUM_WAKEUP_SECONDS (30)
214
215 /*********************************************************************
216 * infoDict keys for internally-stored data. Saves on ivar slots for
217 * objects we don't keep around past boot time or during active load.
218 *********************************************************************/
219
220 /* A usable, uncompressed file is stored under this key.
221 */
222 #define _kOSKextExecutableKey "_OSKextExecutable"
223
224 /* An indirect reference to the executable file from an mkext
225 * is stored under this key.
226 */
227 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
228
229 /* If the file is contained in a larger buffer laid down by the booter or
230 * sent from user space, the OSKext stores that OSData under this key so that
231 * references are properly tracked. This is always an mkext, right now.
232 */
233 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
234
235 #define OS_LOG_HDR_VERSION 1
236 #define NUM_OS_LOG_SECTIONS 3
237
238 #define OS_LOG_SECT_IDX 0
239 #define CSTRING_SECT_IDX 1
240 #define ASAN_CSTRING_SECT_IDX 2
241
242 #if PRAGMA_MARK
243 #pragma mark Typedefs
244 #endif
245 /*********************************************************************
246 * Typedefs
247 *********************************************************************/
248
249 /*********************************************************************
250 * osLogDataHeaderRef describes the header information of an OSData
251 * object that is returned when querying for kOSBundleLogStringsKey.
252 * We currently return information regarding 2 sections - os_log and
253 * cstring. In the case that the os_log section doesn't exist, we just
254 * return an offset and length of 0 for that section.
255 *********************************************************************/
256 typedef struct osLogDataHeader {
257 uint32_t version;
258 uint32_t sect_count;
259 struct {
260 uint32_t sect_offset;
261 uint32_t sect_size;
262 } sections[0];
263 } osLogDataHeaderRef;
264
265 /*********************************************************************
266 * MkextEntryRef describes the contents of an OSData object
267 * referencing a file entry from an mkext so that we can uncompress
268 * (if necessary) and extract it on demand.
269 *
270 * It contains the mkextVersion in case we ever wind up supporting
271 * multiple mkext formats. Mkext format 1 is officially retired as of
272 * Snow Leopard.
273 *********************************************************************/
274 typedef struct MkextEntryRef {
275 mkext_basic_header * mkext; // beginning of whole mkext file
276 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
277 } MkextEntryRef;
278
279 #if PRAGMA_MARK
280 #pragma mark Global and static Module Variables
281 #endif
282 /*********************************************************************
283 * Global & static variables, used to keep track of kexts.
284 *********************************************************************/
285
286 static bool sPrelinkBoot = false;
287 static bool sSafeBoot = false;
288 static bool sKeepSymbols = false;
289 static bool sPanicOnKCMismatch = false;
290 static bool sOSKextWasResetAfterUserspaceReboot = false;
291
292 /*********************************************************************
293 * sKextLock is the principal lock for OSKext, and guards all static
294 * and global variables not owned by other locks (declared further
295 * below). It must be taken by any entry-point method or function,
296 * including internal functions called on scheduled threads.
297 *
298 * sKextLock and sKextInnerLock are recursive due to multiple functions
299 * that are called both externally and internally. The other locks are
300 * nonrecursive.
301 *
302 * Which locks are taken depends on what they protect, but if more than
303 * one must be taken, they must always be locked in this order
304 * (and unlocked in reverse order) to prevent deadlocks:
305 *
306 * 1. sKextLock
307 * 2. sKextInnerLock
308 * 3. sKextSummariesLock
309 * 4. sKextLoggingLock
310 */
311 static IORecursiveLock * sKextLock = NULL;
312
313 static OSSharedPtr<OSDictionary> sKextsByID;
314 static OSSharedPtr<OSDictionary> sExcludeListByID;
315 static OSKextVersion sExcludeListVersion = 0;
316 static OSSharedPtr<OSArray> sLoadedKexts;
317 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
318 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
319 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
320
321 // Requests to the IOKit daemon waiting to be picked up.
322 static OSSharedPtr<OSArray> sKernelRequests;
323 // Identifier of kext load requests in sKernelRequests
324 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
325 static OSSharedPtr<OSArray> sRequestCallbackRecords;
326
327 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
328 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
329 #if CONFIG_KXLD
330 static KXLDContext * sKxldContext = NULL;
331 #endif
332 static uint32_t sNextLoadTag = 0;
333 static uint32_t sNextRequestTag = 0;
334
335 static bool sUserLoadsActive = false;
336 static bool sIOKitDaemonActive = false;
337 static bool sDeferredLoadSucceeded = false;
338 static bool sConsiderUnloadsExecuted = false;
339
340 #if NO_KEXTD
341 static bool sKernelRequestsEnabled = false;
342 #else
343 static bool sKernelRequestsEnabled = true;
344 #endif
345 static bool sLoadEnabled = true;
346 static bool sUnloadEnabled = true;
347
348 /*********************************************************************
349 * Stuff for the OSKext representing the kernel itself.
350 **********/
351 static OSKext * sKernelKext = NULL;
352
353 /* Set up a fake kmod_info struct for the kernel.
354 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
355 * before OSKext is initialized; that call only needs the name
356 * and address to be set correctly.
357 *
358 * We don't do much else with the kerne's kmod_info; we never
359 * put it into the kmod list, never adjust the reference count,
360 * and never have kernel components reference it.
361 * For that matter, we don't do much with kmod_info structs
362 * at all anymore! We just keep them filled in for gdb and
363 * binary compability.
364 */
365 kmod_info_t g_kernel_kmod_info = {
366 .next = NULL,
367 .info_version = KMOD_INFO_VERSION,
368 .id = 0, // loadTag: kernel is always 0
369 .name = kOSKextKernelIdentifier,// bundle identifier
370 .version = "0", // filled in in OSKext::initialize()
371 .reference_count = -1, // never adjusted; kernel never unloads
372 .reference_list = NULL,
373 .address = 0,
374 .size = 0, // filled in in OSKext::initialize()
375 .hdr_size = 0,
376 .start = NULL,
377 .stop = NULL
378 };
379
380 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
381
382 kmod_info_t invalid_kmod_info = {
383 .next = NULL,
384 .info_version = KMOD_INFO_VERSION,
385 .id = UINT32_MAX,
386 .name = "invalid",
387 .version = "0",
388 .reference_count = -1,
389 .reference_list = NULL,
390 .address = 0,
391 .size = 0,
392 .hdr_size = 0,
393 .start = NULL,
394 .stop = NULL
395 };
396
397 extern "C" {
398 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
399 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
400 // misc_protos.h, db_low_trace.c, kgmacros
401 // 'kmod' is a holdover from the old kmod system, we can't rename it.
402 kmod_info_t * kmod = NULL;
403
404 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
405
406
407 static char * loaded_kext_paniclist = NULL;
408 static uint32_t loaded_kext_paniclist_size = 0;
409
410 AbsoluteTime last_loaded_timestamp;
411 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
412 static u_long last_loaded_strlen = 0;
413 static void * last_loaded_address = NULL;
414 static u_long last_loaded_size = 0;
415
416 AbsoluteTime last_unloaded_timestamp;
417 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
418 static u_long last_unloaded_strlen = 0;
419 static void * last_unloaded_address = NULL;
420 static u_long last_unloaded_size = 0;
421
422 // Statically linked kmods described by several mach-o sections:
423 //
424 // kPrelinkInfoSegment:kBuiltinInfoSection
425 // Array of pointers to kmod_info_t structs.
426 //
427 // kPrelinkInfoSegment:kBuiltinInfoSection
428 // Array of pointers to an embedded mach-o header.
429 //
430 // __DATA:kBuiltinInitSection, kBuiltinTermSection
431 // Structors for all kmods. Has to be filtered by proc address.
432 //
433
434 static uint32_t gBuiltinKmodsCount;
435 static kernel_section_t * gBuiltinKmodsSectionInfo;
436 static kernel_section_t * gBuiltinKmodsSectionStart;
437
438 const OSSymbol * gIOSurfaceIdentifier;
439 vm_tag_t gIOSurfaceTag;
440
441 /*********************************************************************
442 * sKextInnerLock protects against cross-calls with IOService and
443 * IOCatalogue, and owns the variables declared immediately below.
444 *
445 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
446 *
447 * When both sKextLock and sKextInnerLock need to be taken,
448 * always lock sKextLock first and unlock it second. Never take both
449 * locks in an entry point to OSKext; if you need to do so, you must
450 * spawn an independent thread to avoid potential deadlocks for threads
451 * calling into OSKext.
452 **********/
453 static IORecursiveLock * sKextInnerLock = NULL;
454
455 #if XNU_TARGET_OS_OSX
456 static bool sAutounloadEnabled = true;
457 #endif
458 static bool sConsiderUnloadsCalled = false;
459 static bool sConsiderUnloadsPending = false;
460
461 static unsigned int sConsiderUnloadDelay = 60; // seconds
462 static thread_call_t sUnloadCallout = NULL;
463 #if CONFIG_KXLD
464 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
465 #endif // CONFIG_KXLD
466 static bool sSystemSleep = false; // true when system going to sleep
467 static AbsoluteTime sLastWakeTime; // last time we woke up
468
469 /*********************************************************************
470 * Backtraces can be printed at various times so we need a tight lock
471 * on data used for that. sKextSummariesLock protects the variables
472 * declared immediately below.
473 *
474 * gLoadedKextSummaries is accessed by other modules, but only during
475 * a panic so the lock isn't needed then.
476 *
477 * gLoadedKextSummaries has the "used" attribute in order to ensure
478 * that it remains visible even when we are performing extremely
479 * aggressive optimizations, as it is needed to allow the debugger
480 * to automatically parse the list of loaded kexts.
481 **********/
482 static IOLock * sKextSummariesLock = NULL;
483 extern "C" lck_spin_t vm_allocation_sites_lock;
484 static IOSimpleLock * sKextAccountsLock = &vm_allocation_sites_lock;
485
486 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
487 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
488 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
489 static size_t sLoadedKextSummariesAllocSize = 0;
490
491 static OSKextActiveAccount * sKextAccounts;
492 static uint32_t sKextAccountsCount;
493 };
494
495 /*********************************************************************
496 * sKextLoggingLock protects the logging variables declared immediately below.
497 **********/
498 static IOLock * sKextLoggingLock = NULL;
499
500 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
501 kOSKextLogVerboseFlagsMask;
502 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
503 static bool sBootArgLogFilterFound = false;
504 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
505 0, "kernel kext logging");
506
507 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
508 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
509 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
510
511 /*********
512 * End scope for sKextInnerLock-protected variables.
513 *********************************************************************/
514
515
516 /*********************************************************************
517 * helper function used for collecting PGO data upon unload of a kext
518 */
519
520 static int OSKextGrabPgoDataLocked(OSKext *kext,
521 bool metadata,
522 uuid_t instance_uuid,
523 uint64_t *pSize,
524 char *pBuffer,
525 uint64_t bufferSize);
526
527 /**********************************************************************/
528
529
530
531 #if PRAGMA_MARK
532 #pragma mark OSData callbacks (need to move to OSData)
533 #endif
534 /*********************************************************************
535 * C functions used for callbacks.
536 *********************************************************************/
537 extern "C" {
538 void
osdata_kmem_free(void * ptr,unsigned int length)539 osdata_kmem_free(void * ptr, unsigned int length)
540 {
541 kmem_free(kernel_map, (vm_address_t)ptr, length);
542 return;
543 }
544
545 void
osdata_phys_free(void * ptr,unsigned int length)546 osdata_phys_free(void * ptr, unsigned int length)
547 {
548 ml_static_mfree((vm_offset_t)ptr, length);
549 return;
550 }
551
552 void
osdata_vm_deallocate(void * ptr,unsigned int length)553 osdata_vm_deallocate(void * ptr, unsigned int length)
554 {
555 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
556 return;
557 }
558
559 void
osdata_kext_free(void * ptr,unsigned int length)560 osdata_kext_free(void * ptr, unsigned int length)
561 {
562 (void)kext_free((vm_offset_t)ptr, length);
563 }
564 };
565
566 #if PRAGMA_MARK
567 #pragma mark KXLD Allocation Callback
568 #endif
569 #if CONFIG_KXLD
570 /*********************************************************************
571 * KXLD Allocation Callback
572 *********************************************************************/
573 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)574 kern_allocate(
575 u_long size,
576 KXLDAllocateFlags * flags,
577 void * user_data)
578 {
579 vm_address_t result = 0; // returned
580 kern_return_t mach_result = KERN_FAILURE;
581 bool success = false;
582 OSKext * theKext = (OSKext *)user_data;
583 unsigned int roundSize = 0;
584 OSSharedPtr<OSData> linkBuffer;
585
586 if (round_page(size) > UINT_MAX) {
587 OSKextLog(theKext,
588 kOSKextLogErrorLevel |
589 kOSKextLogGeneralFlag,
590 "%s: Requested memory size is greater than UINT_MAX.",
591 theKext->getIdentifierCString());
592 goto finish;
593 }
594
595 roundSize = (unsigned int)round_page(size);
596
597 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
598 if (mach_result != KERN_SUCCESS) {
599 OSKextLog(theKext,
600 kOSKextLogErrorLevel |
601 kOSKextLogGeneralFlag,
602 "Can't allocate kernel memory to link %s.",
603 theKext->getIdentifierCString());
604 goto finish;
605 }
606
607 /* Create an OSData wrapper for the allocated buffer.
608 */
609 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
610 if (!linkBuffer) {
611 OSKextLog(theKext,
612 kOSKextLogErrorLevel |
613 kOSKextLogGeneralFlag,
614 "Can't allocate linked executable wrapper for %s.",
615 theKext->getIdentifierCString());
616 goto finish;
617 }
618 linkBuffer->setDeallocFunction(osdata_kext_free);
619 OSKextLog(theKext,
620 kOSKextLogProgressLevel |
621 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
622 "Allocated link buffer for kext %s at %p (%lu bytes).",
623 theKext->getIdentifierCString(),
624 (void *)result, (unsigned long)roundSize);
625
626 theKext->setLinkedExecutable(linkBuffer.get());
627
628 *flags = kKxldAllocateWritable;
629 success = true;
630
631 finish:
632 if (!success && result) {
633 kext_free(result, roundSize);
634 result = 0;
635 }
636
637 return (kxld_addr_t)result;
638 }
639
640 /*********************************************************************
641 *********************************************************************/
642 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)643 kxld_log_callback(
644 KXLDLogSubsystem subsystem,
645 KXLDLogLevel level,
646 const char * format,
647 va_list argList,
648 void * user_data)
649 {
650 OSKext *theKext = (OSKext *) user_data;
651 OSKextLogSpec logSpec = 0;
652
653 switch (subsystem) {
654 case kKxldLogLinking:
655 logSpec |= kOSKextLogLinkFlag;
656 break;
657 case kKxldLogPatching:
658 logSpec |= kOSKextLogPatchFlag;
659 break;
660 }
661
662 switch (level) {
663 case kKxldLogExplicit:
664 logSpec |= kOSKextLogExplicitLevel;
665 break;
666 case kKxldLogErr:
667 logSpec |= kOSKextLogErrorLevel;
668 break;
669 case kKxldLogWarn:
670 logSpec |= kOSKextLogWarningLevel;
671 break;
672 case kKxldLogBasic:
673 logSpec |= kOSKextLogProgressLevel;
674 break;
675 case kKxldLogDetail:
676 logSpec |= kOSKextLogDetailLevel;
677 break;
678 case kKxldLogDebug:
679 logSpec |= kOSKextLogDebugLevel;
680 break;
681 }
682
683 OSKextVLog(theKext, logSpec, format, argList);
684 }
685 #endif // CONFIG_KXLD
686
687 #if PRAGMA_MARK
688 #pragma mark IOStatistics defines
689 #endif
690
691 #if IOKITSTATS
692
693 #define notifyKextLoadObservers(kext, kmod_info) \
694 do { \
695 IOStatistics::onKextLoad(kext, kmod_info); \
696 } while (0)
697
698 #define notifyKextUnloadObservers(kext) \
699 do { \
700 IOStatistics::onKextUnload(kext); \
701 } while (0)
702
703 #define notifyAddClassObservers(kext, addedClass, flags) \
704 do { \
705 IOStatistics::onClassAdded(kext, addedClass); \
706 } while (0)
707
708 #define notifyRemoveClassObservers(kext, removedClass, flags) \
709 do { \
710 IOStatistics::onClassRemoved(kext, removedClass); \
711 } while (0)
712
713 #else
714
715 #define notifyKextLoadObservers(kext, kmod_info)
716 #define notifyKextUnloadObservers(kext)
717 #define notifyAddClassObservers(kext, addedClass, flags)
718 #define notifyRemoveClassObservers(kext, removedClass, flags)
719
720 #endif /* IOKITSTATS */
721
722 #if PRAGMA_MARK
723 #pragma mark Module Config (Startup & Shutdown)
724 #endif
725 /*********************************************************************
726 * Module Config (Class Definition & Class Methods)
727 *********************************************************************/
728 #define super OSObject
729 OSDefineMetaClassAndStructors(OSKext, OSObject)
730
731 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
732
733 /*********************************************************************
734 *********************************************************************/
735 /* static */
736 void
initialize(void)737 OSKext::initialize(void)
738 {
739 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
740 u_char * kernelStart = NULL;// do not free
741 size_t kernelLength = 0;
742 IORegistryEntry * registryRoot = NULL;// do not release
743 OSSharedPtr<OSNumber> kernelCPUType;
744 OSSharedPtr<OSNumber> kernelCPUSubtype;
745 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
746 bool setResult = false;
747 uint64_t * timestamp = NULL;
748 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
749
750 /* This must be the first thing allocated. Everything else grabs this lock.
751 */
752 sKextLock = IORecursiveLockAlloc();
753 sKextInnerLock = IORecursiveLockAlloc();
754 sKextSummariesLock = IOLockAlloc();
755 sKextLoggingLock = IOLockAlloc();
756 assert(sKextLock);
757 assert(sKextInnerLock);
758 assert(sKextSummariesLock);
759 assert(sKextLoggingLock);
760
761 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
762 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
763 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
764 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
765 sKernelRequests = OSArray::withCapacity(0);
766 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
767 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
768 sRequestCallbackRecords = OSArray::withCapacity(0);
769 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
770 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
771 sRequestCallbackRecords && sUnloadedPrelinkedKexts);
772
773 /* Read the log flag boot-args and set the log flags.
774 */
775 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
776 sBootArgLogFilterFound = true;
777 sKernelLogFilter = bootLogFilter;
778 // log this if any flags are set
779 OSKextLog(/* kext */ NULL,
780 kOSKextLogBasicLevel |
781 kOSKextLogFlagsMask,
782 "Kernel kext log filter 0x%x per kextlog boot arg.",
783 (unsigned)sKernelLogFilter);
784 }
785
786 #if !defined(__arm__) && !defined(__arm64__)
787 /*
788 * On our ARM targets, the kernelcache/boot kernel collection contains
789 * the set of kexts required to boot, as specified by KCB. Safeboot is
790 * either unsupported, or is supported by the bootloader only loading
791 * the boot kernel collection; as a result OSKext has no role to play
792 * in safeboot policy on ARM.
793 */
794 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
795 sizeof(bootArgBuffer)) ? true : false;
796 #endif /* defined(__arm__) && defined(__arm64__) */
797
798 if (sSafeBoot) {
799 OSKextLog(/* kext */ NULL,
800 kOSKextLogWarningLevel |
801 kOSKextLogGeneralFlag,
802 "SAFE BOOT DETECTED - "
803 "only valid OSBundleRequired kexts will be loaded.");
804 }
805
806 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
807 #if CONFIG_DTRACE
808 if (dtrace_keep_kernel_symbols()) {
809 sKeepSymbols = true;
810 }
811 #endif /* CONFIG_DTRACE */
812 #if KASAN_DYNAMIC_BLACKLIST
813 /* needed for function lookup */
814 sKeepSymbols = true;
815 #endif
816
817 /*
818 * Should we panic when the SystemKC is not linked against the
819 * BootKC that was loaded by the booter? By default: yes, if the
820 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
821 * on mis-match and instead just print an error and continue.
822 */
823 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
824 sizeof(bootArgBuffer)) ? false : true;
825
826 /* Set up an OSKext instance to represent the kernel itself.
827 */
828 sKernelKext = new OSKext;
829 assert(sKernelKext);
830
831 kernelStart = (u_char *)&_mh_execute_header;
832 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
833 assert(kernelLength <= UINT_MAX);
834 kernelExecutable = OSData::withBytesNoCopy(
835 kernelStart, (unsigned int)kernelLength);
836 assert(kernelExecutable);
837
838 #if KASLR_KEXT_DEBUG
839 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %lu (0x%016lx) \n",
840 (unsigned long)kernelStart,
841 (unsigned long)getlastaddr(),
842 kernelLength,
843 (unsigned long)vm_kernel_slide,
844 (unsigned long)vm_kernel_slide);
845 #endif
846
847 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
848 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
849
850 sKernelKext->version = OSKextParseVersionString(osrelease);
851 sKernelKext->compatibleVersion = sKernelKext->version;
852 sKernelKext->linkedExecutable = os::move(kernelExecutable);
853 sKernelKext->interfaceUUID = sKernelKext->copyUUID();
854
855 sKernelKext->flags.hasAllDependencies = 1;
856 sKernelKext->flags.kernelComponent = 1;
857 sKernelKext->flags.prelinked = 0;
858 sKernelKext->flags.loaded = 1;
859 sKernelKext->flags.started = 1;
860 sKernelKext->flags.CPPInitialized = 0;
861 sKernelKext->flags.jettisonLinkeditSeg = 0;
862
863 sKernelKext->kmod_info = &g_kernel_kmod_info;
864 strlcpy(g_kernel_kmod_info.version, osrelease,
865 sizeof(g_kernel_kmod_info.version));
866 g_kernel_kmod_info.size = kernelLength;
867 g_kernel_kmod_info.id = sKernelKext->loadTag;
868
869 /* Cons up an info dict, so we don't have to have special-case
870 * checking all over.
871 */
872 sKernelKext->infoDict = OSDictionary::withCapacity(5);
873 assert(sKernelKext->infoDict);
874 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
875 sKernelKext->bundleID.get());
876 assert(setResult);
877 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
878 kOSBooleanTrue);
879 assert(setResult);
880
881 {
882 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
883 assert(scratchString);
884 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
885 scratchString.get());
886 assert(setResult);
887 }
888
889 {
890 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy("mach_kernel"));
891 assert(scratchString);
892 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
893 scratchString.get());
894 assert(setResult);
895 }
896
897 /* Add the kernel kext to the bookkeeping dictionaries. Note that
898 * the kernel kext doesn't have a kmod_info struct. copyInfo()
899 * gathers info from other places anyhow.
900 */
901 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
902 assert(setResult);
903 setResult = sLoadedKexts->setObject(sKernelKext);
904 assert(setResult);
905
906 // XXX: better way with OSSharedPtr?
907 // sKernelKext remains a valid pointer even after the decref
908 sKernelKext->release();
909
910 registryRoot = IORegistryEntry::getRegistryRoot();
911 kernelCPUType = OSNumber::withNumber(
912 (long long unsigned int)_mh_execute_header.cputype,
913 8 * sizeof(_mh_execute_header.cputype));
914 kernelCPUSubtype = OSNumber::withNumber(
915 (long long unsigned int)_mh_execute_header.cpusubtype,
916 8 * sizeof(_mh_execute_header.cpusubtype));
917 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
918
919 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
920 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
921
922 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
923 if (gBuiltinKmodsSectionInfo) {
924 uint32_t count;
925
926 assert(gBuiltinKmodsSectionInfo->addr);
927 assert(gBuiltinKmodsSectionInfo->size);
928 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
929 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
930
931 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
932 assert(gBuiltinKmodsSectionStart);
933 assert(gBuiltinKmodsSectionStart->addr);
934 assert(gBuiltinKmodsSectionStart->size);
935 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
936 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
937 // one extra pointer for the end of last kmod
938 assert(count == (gBuiltinKmodsCount + 1));
939
940 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
941 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
942 }
943
944 // Don't track this object -- it's never released
945 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
946
947 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
948 *timestamp = 0;
949 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
950 *timestamp = 0;
951 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
952 *timestamp = 0;
953
954 OSKextLog(/* kext */ NULL,
955 kOSKextLogProgressLevel |
956 kOSKextLogGeneralFlag,
957 "Kext system initialized.");
958
959 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
960
961 return;
962 }
963
964 /*********************************************************************
965 * This is expected to be called exactly once, from exactly one thread
966 * context, during kernel bootstrap.
967 *********************************************************************/
968 /* static */
969 OSReturn
removeKextBootstrap(void)970 OSKext::removeKextBootstrap(void)
971 {
972 OSReturn result = kOSReturnError;
973
974 const char * dt_kernel_header_name = "Kernel-__HEADER";
975 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
976 kernel_mach_header_t * dt_mach_header = NULL;
977 int dt_mach_header_size = 0;
978 struct symtab_command * dt_symtab = NULL;
979 int dt_symtab_size = 0;
980 int dt_result = 0;
981
982 kernel_segment_command_t * seg_kld = NULL;
983 kernel_segment_command_t * seg_klddata = NULL;
984 kernel_segment_command_t * seg_linkedit = NULL;
985
986 const char __unused * dt_segment_name = NULL;
987 void __unused * segment_paddress = NULL;
988 int __unused segment_size = 0;
989
990 OSKextLog(/* kext */ NULL,
991 kOSKextLogProgressLevel |
992 kOSKextLogGeneralFlag,
993 "Jettisoning kext bootstrap segments.");
994
995 /*
996 * keep the linkedit segment around when booted from a new MH_FILESET
997 * KC because all the kexts shared a linkedit segment.
998 */
999 kc_format_t kc_format;
1000 if (!PE_get_primary_kc_format(&kc_format)) {
1001 OSKextLog(/* kext */ NULL,
1002 kOSKextLogErrorLevel |
1003 kOSKextLogGeneralFlag,
1004 "Unable to determine primary KC format");
1005 }
1006
1007 /*****
1008 * Dispose of unnecessary stuff that the booter didn't need to load.
1009 */
1010 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1011 (void **)&dt_mach_header, &dt_mach_header_size);
1012 if (dt_result == 0 && dt_mach_header) {
1013 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1014 round_page_32(dt_mach_header_size));
1015 }
1016 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1017 (void **)&dt_symtab, &dt_symtab_size);
1018 if (dt_result == 0 && dt_symtab) {
1019 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1020 round_page_32(dt_symtab_size));
1021 }
1022
1023 /*****
1024 * KLD & KLDDATA bootstrap segments.
1025 */
1026 // xxx - should rename KLD segment
1027 seg_kld = getsegbyname("__KLD");
1028 seg_klddata = getsegbyname("__KLDDATA");
1029 if (seg_klddata) {
1030 // __mod_term_func is part of __KLDDATA
1031 OSRuntimeUnloadCPPForSegment(seg_klddata);
1032 }
1033
1034 #if __arm__ || __arm64__
1035 /* Free the memory that was set up by iBoot.
1036 */
1037 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1038 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1039 * is covered by the contiguous rorgn.
1040 */
1041 dt_segment_name = "Kernel-__KLD";
1042 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1043 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1044 (int)segment_size); // calls ml_static_mfree
1045 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1046 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1047 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1048 seg_kld->vmsize);
1049 }
1050 #endif
1051 dt_segment_name = "Kernel-__KLDDATA";
1052 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1053 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1054 (int)segment_size); // calls ml_static_mfree
1055 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1056 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1057 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1058 seg_klddata->vmsize);
1059 }
1060 #elif __i386__ || __x86_64__
1061 /* On x86, use the mapping data from the segment load command to
1062 * unload KLD & KLDDATA directly.
1063 * This may invalidate any assumptions about "avail_start"
1064 * defining the lower bound for valid physical addresses.
1065 */
1066 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1067 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1068 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1069 }
1070 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1071 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1072 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1073 }
1074 #else
1075 #error arch
1076 #endif
1077
1078 /*****
1079 * Prelinked kernel's symtab (if there is one).
1080 */
1081 if (kc_format != KCFormatFileset) {
1082 kernel_section_t * sect;
1083 sect = getsectbyname("__PRELINK", "__symtab");
1084 if (sect && sect->addr && sect->size) {
1085 ml_static_mfree(sect->addr, sect->size);
1086 }
1087 }
1088
1089 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1090
1091 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1092 * pageable, unless keepsyms is set. To do that, we have to copy it from
1093 * its booter-allocated memory, free the booter memory, reallocate proper
1094 * managed memory, then copy the segment back in.
1095 *
1096 * NOTE: This optimization is not valid for fileset KCs because each
1097 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1098 * that points to one fileset-global LINKEDIT segment. This
1099 * optimization is also only valid for platforms that support vm
1100 * mapped kexts or mapped kext collections (pageable KCs)
1101 */
1102 #if VM_MAPPED_KEXTS
1103 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1104 kern_return_t mem_result;
1105 void *seg_copy = NULL;
1106 void *seg_data = NULL;
1107 vm_map_offset_t seg_offset = 0;
1108 vm_map_offset_t seg_copy_offset = 0;
1109 vm_map_size_t seg_length = 0;
1110
1111 seg_data = (void *) seg_linkedit->vmaddr;
1112 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1113 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1114
1115 /* Allocate space for the LINKEDIT copy.
1116 */
1117 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1118 seg_length, VM_KERN_MEMORY_KEXT);
1119 if (mem_result != KERN_SUCCESS) {
1120 OSKextLog(/* kext */ NULL,
1121 kOSKextLogErrorLevel |
1122 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1123 "Can't copy __LINKEDIT segment for VM reassign.");
1124 return result;
1125 }
1126 seg_copy_offset = (vm_map_offset_t) seg_copy;
1127
1128 /* Copy it out.
1129 */
1130 memcpy(seg_copy, seg_data, seg_length);
1131
1132 /* Dump the booter memory.
1133 */
1134 ml_static_mfree(seg_offset, seg_length);
1135
1136 /* Set up the VM region.
1137 */
1138 mem_result = vm_map_enter_mem_object(
1139 kernel_map,
1140 &seg_offset,
1141 seg_length, /* mask */ 0,
1142 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1143 VM_MAP_KERNEL_FLAGS_NONE,
1144 VM_KERN_MEMORY_NONE,
1145 (ipc_port_t)NULL,
1146 (vm_object_offset_t) 0,
1147 /* copy */ FALSE,
1148 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1149 /* max_protection */ VM_PROT_ALL,
1150 /* inheritance */ VM_INHERIT_DEFAULT);
1151 if ((mem_result != KERN_SUCCESS) ||
1152 (seg_offset != (vm_map_offset_t) seg_data)) {
1153 OSKextLog(/* kext */ NULL,
1154 kOSKextLogErrorLevel |
1155 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1156 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1157 seg_data, seg_length, mem_result);
1158 return result;
1159 }
1160
1161 /* And copy it back.
1162 */
1163 memcpy(seg_data, seg_copy, seg_length);
1164
1165 /* Free the copy.
1166 */
1167 kmem_free(kernel_map, seg_copy_offset, seg_length);
1168 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1169 /* Remove the linkedit segment of the Boot KC */
1170 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1171 OSKext::jettisonFileSetLinkeditSegment(mh);
1172 }
1173 #else // !VM_MAPPED_KEXTS
1174 /*****
1175 * Dump the LINKEDIT segment, unless keepsyms is set.
1176 */
1177 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1178 dt_segment_name = "Kernel-__LINKEDIT";
1179 if (0 == IODTGetLoaderInfo(dt_segment_name,
1180 &segment_paddress, &segment_size)) {
1181 #ifdef SECURE_KERNEL
1182 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1183 bzero((void*)vmaddr, segment_size);
1184 #endif
1185 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1186 (int)segment_size);
1187 }
1188 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1189 /* Remove the linkedit segment of the Boot KC */
1190 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1191 OSKext::jettisonFileSetLinkeditSegment(mh);
1192 } else {
1193 OSKextLog(/* kext */ NULL,
1194 kOSKextLogBasicLevel |
1195 kOSKextLogGeneralFlag,
1196 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1197 }
1198 #endif // VM_MAPPED_KEXTS
1199
1200 result = kOSReturnSuccess;
1201
1202 return result;
1203 }
1204
1205 #if CONFIG_KXLD
1206 /*********************************************************************
1207 *********************************************************************/
1208 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1209 OSKext::flushNonloadedKexts(
1210 Boolean flushPrelinkedKexts)
1211 {
1212 OSSharedPtr<OSSet> keepKexts;
1213
1214 /* TODO: make this more efficient with MH_FILESET kexts */
1215
1216 // Do not unload prelinked kexts on arm because the kernelcache is not
1217 // structured in a way that allows them to be unmapped
1218 #if !defined(__x86_64__)
1219 flushPrelinkedKexts = false;
1220 #endif /* defined(__x86_64__) */
1221
1222 IORecursiveLockLock(sKextLock);
1223
1224 OSKextLog(/* kext */ NULL,
1225 kOSKextLogProgressLevel |
1226 kOSKextLogKextBookkeepingFlag,
1227 "Flushing nonloaded kexts and other unused data.");
1228
1229 OSKext::considerDestroyingLinkContext();
1230
1231 /* If we aren't flushing unused prelinked kexts, we have to put them
1232 * aside while we flush everything else so make a container for them.
1233 */
1234 keepKexts = OSSet::withCapacity(16);
1235 if (!keepKexts) {
1236 goto finish;
1237 }
1238
1239 /* Set aside prelinked kexts (in-use or not) and break
1240 * any lingering inter-kext references for nonloaded kexts
1241 * so they have min. retain counts.
1242 */
1243 {
1244 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1245 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1246 if (!thisKext) {
1247 return false;
1248 }
1249 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1250 keepKexts->setObject(thisKext);
1251 } else if (!thisKext->declaresExecutable()) {
1252 /*
1253 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1254 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1255 * flushNonloadedKexts().
1256 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1257 */
1258 keepKexts->setObject(thisKext);
1259 } else if (thisKext->isInFileset()) {
1260 /* keep all kexts in the new MH_FILESET KC */
1261 keepKexts->setObject(thisKext);
1262 }
1263
1264 thisKext->flushDependencies(/* forceIfLoaded */ false);
1265 return false;
1266 });
1267 }
1268 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1269 */
1270 sKextsByID->flushCollection();
1271
1272 /* Now put the loaded kexts back into the ID dictionary.
1273 */
1274 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1275 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1276 if (!thisKext) {
1277 return false;
1278 }
1279 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1280 return false;
1281 });
1282
1283 /* Finally, put back the kept kexts if we saved any.
1284 */
1285 keepKexts->iterateObjects(^bool (OSObject * obj) {
1286 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1287 if (!thisKext) {
1288 return false;
1289 }
1290 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1291 return false;
1292 });
1293
1294 finish:
1295 IORecursiveLockUnlock(sKextLock);
1296 return;
1297 }
1298 #else /* !CONFIG_KXLD */
1299
1300 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1301 OSKext::flushNonloadedKexts(
1302 Boolean flushPrelinkedKexts __unused)
1303 {
1304 IORecursiveLockLock(sKextLock);
1305
1306 OSKextLog(/* kext */ NULL,
1307 kOSKextLogProgressLevel |
1308 kOSKextLogKextBookkeepingFlag,
1309 "Flushing dependency info for non-loaded kexts.");
1310
1311 /*
1312 * In a world where we don't dynamically link kexts, they all come
1313 * from a kext collection that's either in wired memory, or
1314 * wire-on-demand. We don't need to mess around with moving kexts in
1315 * and out of the sKextsByID array - they can all just stay there.
1316 * Here we just flush the dependency list for kexts that are not
1317 * loaded.
1318 */
1319 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1320 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1321 if (!thisKext) {
1322 return false;
1323 }
1324 thisKext->flushDependencies(/* forceIfLoaded */ false);
1325 return false;
1326 });
1327
1328 IORecursiveLockUnlock(sKextLock);
1329 return;
1330 }
1331
1332 #endif /* CONFIG_KXLD */
1333
1334 /*********************************************************************
1335 *********************************************************************/
1336 /* static */
1337 void
setIOKitDaemonActive(bool active)1338 OSKext::setIOKitDaemonActive(bool active)
1339 {
1340 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1341 IORecursiveLockLock(sKextLock);
1342 sIOKitDaemonActive = active;
1343 if (sKernelRequests->getCount()) {
1344 OSKext::pingIOKitDaemon();
1345 }
1346 IORecursiveLockUnlock(sKextLock);
1347
1348 return;
1349 }
1350
1351 /*********************************************************************
1352 * OSKextLib.cpp might need access to this someday but for now it's
1353 * private.
1354 *********************************************************************/
1355 extern "C" {
1356 extern void ipc_port_release_send(ipc_port_t);
1357 };
1358
1359 /* static */
1360 OSReturn
pingIOKitDaemon(void)1361 OSKext::pingIOKitDaemon(void)
1362 {
1363 OSReturn result = kOSReturnError;
1364 #if !NO_KEXTD
1365 mach_port_t kextd_port = IPC_PORT_NULL;
1366
1367 if (!sIOKitDaemonActive) {
1368 result = kOSKextReturnDisabled; // basically unavailable
1369 goto finish;
1370 }
1371
1372 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1373 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1374 OSKextLog(/* kext */ NULL,
1375 kOSKextLogErrorLevel |
1376 kOSKextLogIPCFlag,
1377 "Can't get " kIOKitDaemonName " port.");
1378 goto finish;
1379 }
1380
1381 result = kextd_ping(kextd_port);
1382 if (result != KERN_SUCCESS) {
1383 OSKextLog(/* kext */ NULL,
1384 kOSKextLogErrorLevel |
1385 kOSKextLogIPCFlag,
1386 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1387 goto finish;
1388 }
1389
1390 finish:
1391 if (IPC_PORT_VALID(kextd_port)) {
1392 ipc_port_release_send(kextd_port);
1393 }
1394 #endif
1395
1396 return result;
1397 }
1398
1399 /*********************************************************************
1400 *********************************************************************/
1401 /* static */
1402 void
setDeferredLoadSucceeded(Boolean succeeded)1403 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1404 {
1405 IORecursiveLockLock(sKextLock);
1406 sDeferredLoadSucceeded = succeeded;
1407 IORecursiveLockUnlock(sKextLock);
1408
1409 return;
1410 }
1411
1412 /*********************************************************************
1413 * Called from IOSystemShutdownNotification.
1414 *********************************************************************/
1415 /* static */
1416 void
willShutdown(void)1417 OSKext::willShutdown(void)
1418 {
1419 #if !NO_KEXTD
1420 OSReturn checkResult = kOSReturnError;
1421 #endif
1422 OSSharedPtr<OSDictionary> exitRequest;
1423
1424 IORecursiveLockLock(sKextLock);
1425
1426 OSKext::setLoadEnabled(false);
1427 OSKext::setUnloadEnabled(false);
1428 OSKext::setAutounloadsEnabled(false);
1429 OSKext::setKernelRequestsEnabled(false);
1430
1431 #if defined(__x86_64__) || defined(__i386__)
1432 if (IOPMRootDomainGetWillShutdown()) {
1433 OSKext::freeKCFileSetcontrol();
1434 }
1435 #endif // (__x86_64__) || defined(__i386__)
1436
1437 #if !NO_KEXTD
1438 OSKextLog(/* kext */ NULL,
1439 kOSKextLogProgressLevel |
1440 kOSKextLogGeneralFlag,
1441 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1442
1443 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1444 exitRequest);
1445 if (checkResult != kOSReturnSuccess) {
1446 goto finish;
1447 }
1448 if (!sKernelRequests->setObject(exitRequest.get())) {
1449 goto finish;
1450 }
1451
1452 OSKext::pingIOKitDaemon();
1453
1454 finish:
1455 #endif
1456
1457 IORecursiveLockUnlock(sKextLock);
1458 return;
1459 }
1460
1461 void
willUserspaceReboot(void)1462 OSKext::willUserspaceReboot(void)
1463 {
1464 OSKext::willShutdown();
1465 IOService::userSpaceWillReboot();
1466 gIOCatalogue->terminateDriversForUserspaceReboot();
1467 }
1468
1469 void
resetAfterUserspaceReboot(void)1470 OSKext::resetAfterUserspaceReboot(void)
1471 {
1472 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1473 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1474
1475 IORecursiveLockLock(sKextLock);
1476 gIOCatalogue->resetAfterUserspaceReboot();
1477 IOService::userSpaceDidReboot();
1478 OSKext::removeDaemonExitRequests();
1479 OSKext::setLoadEnabled(true);
1480 OSKext::setUnloadEnabled(true);
1481 OSKext::setAutounloadsEnabled(true);
1482 OSKext::setKernelRequestsEnabled(true);
1483 sOSKextWasResetAfterUserspaceReboot = true;
1484 IORecursiveLockUnlock(sKextLock);
1485 }
1486
1487 extern "C" void
OSKextResetAfterUserspaceReboot(void)1488 OSKextResetAfterUserspaceReboot(void)
1489 {
1490 OSKext::resetAfterUserspaceReboot();
1491 }
1492
1493 /*
1494 * Remove daemon exit requests from sKernelRequests
1495 *
1496 * If we sent a daemon exit request during a userspace reboot and launchd
1497 * killed the IOKit daemon before it was able to dequeue the exit request, the
1498 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1499 *
1500 * This removes exit requests so that this does not happen.
1501 */
1502 void
removeDaemonExitRequests(void)1503 OSKext::removeDaemonExitRequests(void)
1504 {
1505 OSDictionary * current = NULL;
1506 OSString * predicate = NULL;
1507 size_t index = 0;
1508 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1509
1510 while (index < sKernelRequests->getCount()) {
1511 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1512 if (current) {
1513 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1514 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1515 sKernelRequests->removeObject(index);
1516 continue;
1517 }
1518 }
1519 index++;
1520 }
1521 }
1522
1523 /*********************************************************************
1524 *********************************************************************/
1525 /* static */
1526 bool
getLoadEnabled(void)1527 OSKext::getLoadEnabled(void)
1528 {
1529 bool result;
1530
1531 IORecursiveLockLock(sKextLock);
1532 result = sLoadEnabled;
1533 IORecursiveLockUnlock(sKextLock);
1534 return result;
1535 }
1536
1537 /*********************************************************************
1538 *********************************************************************/
1539 /* static */
1540 bool
setLoadEnabled(bool flag)1541 OSKext::setLoadEnabled(bool flag)
1542 {
1543 bool result;
1544
1545 IORecursiveLockLock(sKextLock);
1546 result = sLoadEnabled;
1547 sLoadEnabled = (flag ? true : false);
1548
1549 if (sLoadEnabled != result) {
1550 OSKextLog(/* kext */ NULL,
1551 kOSKextLogBasicLevel |
1552 kOSKextLogLoadFlag,
1553 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1554 }
1555
1556 IORecursiveLockUnlock(sKextLock);
1557
1558 return result;
1559 }
1560
1561 /*********************************************************************
1562 *********************************************************************/
1563 /* static */
1564 bool
getUnloadEnabled(void)1565 OSKext::getUnloadEnabled(void)
1566 {
1567 bool result;
1568
1569 IORecursiveLockLock(sKextLock);
1570 result = sUnloadEnabled;
1571 IORecursiveLockUnlock(sKextLock);
1572 return result;
1573 }
1574
1575 /*********************************************************************
1576 *********************************************************************/
1577 /* static */
1578 bool
setUnloadEnabled(bool flag)1579 OSKext::setUnloadEnabled(bool flag)
1580 {
1581 bool result;
1582
1583 IORecursiveLockLock(sKextLock);
1584 result = sUnloadEnabled;
1585 sUnloadEnabled = (flag ? true : false);
1586 IORecursiveLockUnlock(sKextLock);
1587
1588 if (sUnloadEnabled != result) {
1589 OSKextLog(/* kext */ NULL,
1590 kOSKextLogBasicLevel |
1591 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1592 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1593 }
1594
1595 return result;
1596 }
1597
1598 /*********************************************************************
1599 * Do not call any function that takes sKextLock here!
1600 *********************************************************************/
1601 /* static */
1602 bool
getAutounloadEnabled(void)1603 OSKext::getAutounloadEnabled(void)
1604 {
1605 #if XNU_TARGET_OS_OSX
1606 bool result;
1607
1608 IORecursiveLockLock(sKextInnerLock);
1609 result = sAutounloadEnabled ? true : false;
1610 IORecursiveLockUnlock(sKextInnerLock);
1611 return result;
1612 #else
1613 return false;
1614 #endif /* XNU_TARGET_OS_OSX */
1615 }
1616
1617 /*********************************************************************
1618 * Do not call any function that takes sKextLock here!
1619 *********************************************************************/
1620 /* static */
1621 bool
setAutounloadsEnabled(bool flag)1622 OSKext::setAutounloadsEnabled(bool flag)
1623 {
1624 #if XNU_TARGET_OS_OSX
1625 bool result;
1626
1627 IORecursiveLockLock(sKextInnerLock);
1628
1629 result = sAutounloadEnabled;
1630 sAutounloadEnabled = (flag ? true : false);
1631 if (!sAutounloadEnabled && sUnloadCallout) {
1632 thread_call_cancel(sUnloadCallout);
1633 }
1634
1635 if (sAutounloadEnabled != result) {
1636 OSKextLog(/* kext */ NULL,
1637 kOSKextLogBasicLevel |
1638 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1639 "Kext autounloading now %sabled.",
1640 sAutounloadEnabled ? "en" : "dis");
1641 }
1642
1643 IORecursiveLockUnlock(sKextInnerLock);
1644
1645 return result;
1646 #else
1647 (void)flag;
1648 return false;
1649 #endif /* XNU_TARGET_OS_OSX */
1650 }
1651
1652 /*********************************************************************
1653 *********************************************************************/
1654 /* instance method operating on OSKext field */
1655 bool
setAutounloadEnabled(bool flag)1656 OSKext::setAutounloadEnabled(bool flag)
1657 {
1658 bool result = flags.autounloadEnabled ? true : false;
1659 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1660
1661 if (result != (flag ? true : false)) {
1662 OSKextLog(this,
1663 kOSKextLogProgressLevel |
1664 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1665 "Autounloading for kext %s now %sabled.",
1666 getIdentifierCString(),
1667 flags.autounloadEnabled ? "en" : "dis");
1668 }
1669 return result;
1670 }
1671
1672 /*********************************************************************
1673 *********************************************************************/
1674 /* static */
1675 bool
setKernelRequestsEnabled(bool flag)1676 OSKext::setKernelRequestsEnabled(bool flag)
1677 {
1678 bool result;
1679
1680 IORecursiveLockLock(sKextLock);
1681 result = sKernelRequestsEnabled;
1682 sKernelRequestsEnabled = flag ? true : false;
1683
1684 if (sKernelRequestsEnabled != result) {
1685 OSKextLog(/* kext */ NULL,
1686 kOSKextLogBasicLevel |
1687 kOSKextLogGeneralFlag,
1688 "Kernel requests now %sabled.",
1689 sKernelRequestsEnabled ? "en" : "dis");
1690 }
1691 IORecursiveLockUnlock(sKextLock);
1692 return result;
1693 }
1694
1695 /*********************************************************************
1696 *********************************************************************/
1697 /* static */
1698 bool
getKernelRequestsEnabled(void)1699 OSKext::getKernelRequestsEnabled(void)
1700 {
1701 bool result;
1702
1703 IORecursiveLockLock(sKextLock);
1704 result = sKernelRequestsEnabled;
1705 IORecursiveLockUnlock(sKextLock);
1706 return result;
1707 }
1708
1709 static bool
segmentIsMutable(kernel_segment_command_t * seg)1710 segmentIsMutable(kernel_segment_command_t *seg)
1711 {
1712 /* Mutable segments have to have VM_PROT_WRITE */
1713 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1714 return false;
1715 }
1716 /* Exclude the __DATA_CONST segment */
1717 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1718 return false;
1719 }
1720 /* Exclude __LINKEDIT */
1721 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1722 return false;
1723 }
1724 return true;
1725 }
1726
1727 #if PRAGMA_MARK
1728 #pragma mark Kext Life Cycle
1729 #endif
1730 /*********************************************************************
1731 *********************************************************************/
1732 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1733 OSKext::withPrelinkedInfoDict(
1734 OSDictionary * anInfoDict,
1735 bool doCoalescedSlides,
1736 kc_kind_t type)
1737 {
1738 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1739
1740 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1741 return NULL;
1742 }
1743
1744 return newKext;
1745 }
1746
1747 /*********************************************************************
1748 *********************************************************************/
1749 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1750 OSKext::initWithPrelinkedInfoDict(
1751 OSDictionary * anInfoDict,
1752 bool doCoalescedSlides,
1753 kc_kind_t type)
1754 {
1755 bool result = false;
1756 OSString * kextPath = NULL; // do not release
1757 OSNumber * addressNum = NULL; // reused; do not release
1758 OSNumber * lengthNum = NULL; // reused; do not release
1759 OSBoolean * scratchBool = NULL; // do not release
1760 void * data = NULL; // do not free
1761 void * srcData = NULL; // do not free
1762 OSSharedPtr<OSData> prelinkedExecutable;
1763 uint32_t length = 0; // reused
1764 uintptr_t kext_slide = PE_get_kc_slide(type);
1765 bool shouldSaveSegments = false;
1766
1767 if (!super::init()) {
1768 goto finish;
1769 }
1770
1771 /* Get the path. Don't look for an arch-specific path property.
1772 */
1773 kextPath = OSDynamicCast(OSString,
1774 anInfoDict->getObject(kPrelinkBundlePathKey));
1775
1776 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1777 goto finish;
1778 }
1779
1780 #if KASLR_KEXT_DEBUG
1781 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1782 #endif
1783
1784 /* Also get the executable's bundle-relative path if present.
1785 * Don't look for an arch-specific path property.
1786 */
1787 executableRelPath.reset(OSDynamicCast(OSString,
1788 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1789 userExecutableRelPath.reset(OSDynamicCast(OSString,
1790 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1791
1792 /* Don't need the paths to be in the info dictionary any more.
1793 */
1794 anInfoDict->removeObject(kPrelinkBundlePathKey);
1795 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1796
1797 scratchBool = OSDynamicCast(OSBoolean,
1798 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1799 if (scratchBool == kOSBooleanTrue) {
1800 flags.requireExplicitLoad = 1;
1801 }
1802
1803 /* Create an OSData wrapper around the linked executable.
1804 */
1805 addressNum = OSDynamicCast(OSNumber,
1806 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1807 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1808 lengthNum = OSDynamicCast(OSNumber,
1809 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1810 if (!lengthNum) {
1811 OSKextLog(this,
1812 kOSKextLogErrorLevel |
1813 kOSKextLogArchiveFlag,
1814 "Kext %s can't find prelinked kext executable size.",
1815 getIdentifierCString());
1816 return result;
1817 }
1818
1819 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1820 length = (uint32_t) (lengthNum->unsigned32BitValue());
1821
1822 #if KASLR_KEXT_DEBUG
1823 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1824 (unsigned long)ml_static_unslide((vm_offset_t)data),
1825 (unsigned long)data,
1826 length);
1827 #endif
1828
1829 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1830 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1831
1832 /* If the kext's load address differs from its source address, allocate
1833 * space in the kext map at the load address and copy the kext over.
1834 */
1835 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1836 if (addressNum) {
1837 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1838
1839 #if KASLR_KEXT_DEBUG
1840 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1841 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1842 (unsigned long)srcData);
1843 #endif
1844
1845 if (data != srcData) {
1846 #if __LP64__
1847 kern_return_t alloc_result;
1848
1849 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1850 if (alloc_result != KERN_SUCCESS) {
1851 OSKextLog(this,
1852 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1853 "Failed to allocate space for prelinked kext %s.",
1854 getIdentifierCString());
1855 goto finish;
1856 }
1857 memcpy(data, srcData, length);
1858 #else
1859 OSKextLog(this,
1860 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1861 "Error: prelinked kext %s - source and load addresses "
1862 "differ on ILP32 architecture.",
1863 getIdentifierCString());
1864 goto finish;
1865 #endif /* __LP64__ */
1866 }
1867
1868 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1869 }
1870
1871 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1872 if (!prelinkedExecutable) {
1873 OSKextLog(this,
1874 kOSKextLogErrorLevel |
1875 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1876 "Kext %s failed to create executable wrapper.",
1877 getIdentifierCString());
1878 goto finish;
1879 }
1880
1881 #if VM_MAPPED_KEXTS
1882 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1883 #else
1884 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1885 #endif
1886 setLinkedExecutable(prelinkedExecutable.get());
1887 addressNum = OSDynamicCast(OSNumber,
1888 anInfoDict->getObject(kPrelinkKmodInfoKey));
1889 if (!addressNum) {
1890 OSKextLog(this,
1891 kOSKextLogErrorLevel |
1892 kOSKextLogArchiveFlag,
1893 "Kext %s can't find prelinked kext kmod_info address.",
1894 getIdentifierCString());
1895 goto finish;
1896 }
1897
1898 if (addressNum->unsigned64BitValue() != 0) {
1899 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1900 if (kmod_info->address) {
1901 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
1902 } else {
1903 kmod_info->address = (uintptr_t)data;
1904 kmod_info->size = length;
1905 }
1906 #if KASLR_KEXT_DEBUG
1907 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1908 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
1909 (unsigned long)kmod_info);
1910 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1911 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
1912 (unsigned long)kmod_info->address);
1913 #endif
1914 }
1915
1916 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1917 }
1918
1919 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
1920 uintptr_t builtinTextStart;
1921 uintptr_t builtinTextEnd;
1922
1923 flags.builtin = true;
1924 builtinKmodIdx = addressNum->unsigned32BitValue();
1925 assert(builtinKmodIdx < gBuiltinKmodsCount);
1926
1927 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1928 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1929
1930 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1931 kmod_info->address = builtinTextStart;
1932 kmod_info->size = builtinTextEnd - builtinTextStart;
1933 }
1934
1935 /* If the plist has a UUID for an interface, save that off.
1936 */
1937 if (isInterface()) {
1938 interfaceUUID.reset(OSDynamicCast(OSData,
1939 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
1940 if (interfaceUUID) {
1941 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1942 }
1943 }
1944
1945 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
1946 if (!result) {
1947 goto finish;
1948 }
1949
1950 kc_type = type;
1951 /* Exclude builtin and codeless kexts */
1952 if (prelinkedExecutable && kmod_info) {
1953 switch (kc_type) {
1954 case KCKindPrimary:
1955 shouldSaveSegments = (
1956 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
1957 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
1958 if (shouldSaveSegments) {
1959 flags.resetSegmentsFromImmutableCopy = 1;
1960 } else {
1961 flags.unloadUnsupported = 1;
1962 }
1963 break;
1964 case KCKindPageable:
1965 flags.resetSegmentsFromVnode = 1;
1966 break;
1967 case KCKindAuxiliary:
1968 if (!pageableKCloaded) {
1969 flags.resetSegmentsFromImmutableCopy = 1;
1970 } else if (resetAuxKCSegmentOnUnload) {
1971 flags.resetSegmentsFromVnode = 1;
1972 } else {
1973 flags.unloadUnsupported = 1;
1974 }
1975 break;
1976 default:
1977 break;
1978 }
1979 }
1980
1981 if (flags.resetSegmentsFromImmutableCopy) {
1982 /* Save a pristine copy of the mutable segments */
1983 kernel_segment_command_t *seg = NULL;
1984 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
1985
1986 savedMutableSegments = OSArray::withCapacity(0);
1987
1988 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
1989 if (!segmentIsMutable(seg)) {
1990 continue;
1991 }
1992 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
1993 uint64_t vmsize = seg->vmsize;
1994 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1995 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1996 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
1997 if (!savedSegment) {
1998 OSKextLog(this,
1999 kOSKextLogErrorLevel |
2000 kOSKextLogGeneralFlag,
2001 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2002 result = kOSKextReturnInternalError;
2003 goto finish;
2004 }
2005 savedMutableSegments->setObject(savedSegment);
2006 }
2007 }
2008
2009 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2010 /*
2011 * set VM protections now, wire pages for the old style Aux KC now,
2012 * wire pages for the rest of the KC types at load time.
2013 */
2014 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2015 if (!result) {
2016 goto finish;
2017 }
2018 }
2019
2020 flags.prelinked = true;
2021
2022 /* If we created a kext from prelink info,
2023 * we must be booting from a prelinked kernel.
2024 */
2025 sPrelinkBoot = true;
2026
2027 result = registerIdentifier();
2028
2029 finish:
2030 return result;
2031 }
2032
2033 /*********************************************************************
2034 *********************************************************************/
2035 /* static */
2036 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict)2037 OSKext::withCodelessInfo(OSDictionary * anInfoDict)
2038 {
2039 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2040
2041 if (newKext && !newKext->initWithCodelessInfo(anInfoDict)) {
2042 return NULL;
2043 }
2044
2045 return newKext;
2046 }
2047
2048 /*********************************************************************
2049 *********************************************************************/
2050 bool
initWithCodelessInfo(OSDictionary * anInfoDict)2051 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2052 {
2053 bool result = false;
2054 OSString * kextPath = NULL; // do not release
2055 OSBoolean * scratchBool = NULL; // do not release
2056
2057 if (anInfoDict == NULL || !super::init()) {
2058 goto finish;
2059 }
2060
2061 /*
2062 * Get the path. Don't look for an arch-specific path property.
2063 */
2064 kextPath = OSDynamicCast(OSString,
2065 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2066 if (!kextPath) {
2067 OSKextLog(NULL,
2068 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2069 "Requested codeless kext dictionary does not contain the '%s' key",
2070 kKextRequestArgumentCodelessInfoBundlePathKey);
2071 goto finish;
2072 }
2073
2074 uniquePersonalityProperties(anInfoDict);
2075
2076 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2077 goto finish;
2078 }
2079
2080 /*
2081 * This path is meant to initialize codeless kexts only. Refuse
2082 * anything that looks like it has an executable and/or declares
2083 * itself as a kernel component.
2084 */
2085 if (declaresExecutable() || isKernelComponent()) {
2086 OSKextLog(NULL,
2087 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2088 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2089 getIdentifierCString());
2090 goto finish;
2091 }
2092
2093 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2094 boolean_t updated = updateExcludeList(infoDict.get());
2095 if (updated) {
2096 OSKextLog(this,
2097 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2098 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2099 }
2100 }
2101
2102 kc_type = KCKindNone;
2103
2104 scratchBool = OSDynamicCast(OSBoolean,
2105 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2106 if (scratchBool == kOSBooleanTrue) {
2107 flags.requireExplicitLoad = 1;
2108 }
2109
2110 /* Also get the executable's bundle-relative path if present.
2111 * Don't look for an arch-specific path property.
2112 */
2113 userExecutableRelPath.reset(OSDynamicCast(OSString,
2114 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2115
2116 /* remove unnecessary paths from the info dict */
2117 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2118
2119 result = registerIdentifier();
2120
2121 finish:
2122 return result;
2123 }
2124
2125 /*********************************************************************
2126 *********************************************************************/
2127 /* static */
2128 void
setAllVMAttributes(void)2129 OSKext::setAllVMAttributes(void)
2130 {
2131 OSSharedPtr<OSCollectionIterator> kextIterator;
2132 const OSSymbol * thisID = NULL; // do not release
2133
2134 IORecursiveLockLock(sKextLock);
2135
2136 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2137 if (!kextIterator) {
2138 goto finish;
2139 }
2140
2141 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2142 OSKext * thisKext; // do not release
2143
2144 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2145 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2146 continue;
2147 }
2148
2149 if (!thisKext->flags.resetSegmentsFromVnode) {
2150 /*
2151 * set VM protections now, wire pages for the old style Aux KC now,
2152 * wire pages for the rest of the KC types at load time.
2153 */
2154 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2155 }
2156 }
2157
2158 finish:
2159 IORecursiveLockUnlock(sKextLock);
2160
2161 return;
2162 }
2163
2164 /*********************************************************************
2165 *********************************************************************/
2166 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2167 OSKext::withBooterData(
2168 OSString * deviceTreeName,
2169 OSData * booterData)
2170 {
2171 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2172
2173 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2174 return NULL;
2175 }
2176
2177 return newKext;
2178 }
2179
2180 /*********************************************************************
2181 *********************************************************************/
2182 typedef struct _BooterKextFileInfo {
2183 uint32_t infoDictPhysAddr;
2184 uint32_t infoDictLength;
2185 uint32_t executablePhysAddr;
2186 uint32_t executableLength;
2187 uint32_t bundlePathPhysAddr;
2188 uint32_t bundlePathLength;
2189 } _BooterKextFileInfo;
2190
2191 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2192 OSKext::initWithBooterData(
2193 OSString * deviceTreeName,
2194 OSData * booterData)
2195 {
2196 bool result = false;
2197 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2198 char * infoDictAddr = NULL; // do not free
2199 void * executableAddr = NULL; // do not free
2200 char * bundlePathAddr = NULL; // do not free
2201
2202 OSDictionary * theInfoDict = NULL; // do not release
2203 OSSharedPtr<OSObject> parsedXML;
2204 OSSharedPtr<OSString> kextPath;
2205
2206 OSSharedPtr<OSString> errorString;
2207 OSSharedPtr<OSData> executable;
2208
2209 if (!super::init()) {
2210 goto finish;
2211 }
2212
2213 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2214 if (!kextFileInfo) {
2215 OSKextLog(this,
2216 kOSKextLogErrorLevel |
2217 kOSKextLogGeneralFlag,
2218 "No booter-provided data for kext device tree entry %s.",
2219 deviceTreeName->getCStringNoCopy());
2220 goto finish;
2221 }
2222
2223 /* The info plist must exist or we can't read the kext.
2224 */
2225 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2226 OSKextLog(this,
2227 kOSKextLogErrorLevel |
2228 kOSKextLogGeneralFlag,
2229 "No kext info dictionary for booter device tree entry %s.",
2230 deviceTreeName->getCStringNoCopy());
2231 goto finish;
2232 }
2233
2234 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2235 if (!infoDictAddr) {
2236 OSKextLog(this,
2237 kOSKextLogErrorLevel |
2238 kOSKextLogGeneralFlag,
2239 "Can't translate physical address 0x%x of kext info dictionary "
2240 "for device tree entry %s.",
2241 (int)kextFileInfo->infoDictPhysAddr,
2242 deviceTreeName->getCStringNoCopy());
2243 goto finish;
2244 }
2245
2246 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2247 if (parsedXML) {
2248 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2249 }
2250 if (!theInfoDict) {
2251 const char * errorCString = "(unknown error)";
2252
2253 if (errorString && errorString->getCStringNoCopy()) {
2254 errorCString = errorString->getCStringNoCopy();
2255 } else if (parsedXML) {
2256 errorCString = "not a dictionary";
2257 }
2258 OSKextLog(this,
2259 kOSKextLogErrorLevel |
2260 kOSKextLogGeneralFlag,
2261 "Error unserializing info dictionary for device tree entry %s: %s.",
2262 deviceTreeName->getCStringNoCopy(), errorCString);
2263 goto finish;
2264 }
2265
2266 /* A bundle path is not mandatory.
2267 */
2268 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2269 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2270 if (!bundlePathAddr) {
2271 OSKextLog(this,
2272 kOSKextLogErrorLevel |
2273 kOSKextLogGeneralFlag,
2274 "Can't translate physical address 0x%x of kext bundle path "
2275 "for device tree entry %s.",
2276 (int)kextFileInfo->bundlePathPhysAddr,
2277 deviceTreeName->getCStringNoCopy());
2278 goto finish;
2279 }
2280 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2281
2282 kextPath = OSString::withCString(bundlePathAddr);
2283 if (!kextPath) {
2284 OSKextLog(this,
2285 kOSKextLogErrorLevel |
2286 kOSKextLogGeneralFlag,
2287 "Failed to create wrapper for device tree entry %s kext path %s.",
2288 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2289 goto finish;
2290 }
2291 }
2292
2293 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2294 goto finish;
2295 }
2296
2297 /* An executable is not mandatory.
2298 */
2299 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2300 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2301 if (!executableAddr) {
2302 OSKextLog(this,
2303 kOSKextLogErrorLevel |
2304 kOSKextLogGeneralFlag,
2305 "Can't translate physical address 0x%x of kext executable "
2306 "for device tree entry %s.",
2307 (int)kextFileInfo->executablePhysAddr,
2308 deviceTreeName->getCStringNoCopy());
2309 goto finish;
2310 }
2311
2312 executable = OSData::withBytesNoCopy(executableAddr,
2313 kextFileInfo->executableLength);
2314 if (!executable) {
2315 OSKextLog(this,
2316 kOSKextLogErrorLevel |
2317 kOSKextLogGeneralFlag,
2318 "Failed to create executable wrapper for device tree entry %s.",
2319 deviceTreeName->getCStringNoCopy());
2320 goto finish;
2321 }
2322
2323 /* A kext with an executable needs to retain the whole booterData
2324 * object to keep the executable in memory.
2325 */
2326 if (!setExecutable(executable.get(), booterData)) {
2327 OSKextLog(this,
2328 kOSKextLogErrorLevel |
2329 kOSKextLogGeneralFlag,
2330 "Failed to set kext executable for device tree entry %s.",
2331 deviceTreeName->getCStringNoCopy());
2332 goto finish;
2333 }
2334 }
2335
2336 result = registerIdentifier();
2337
2338 finish:
2339 return result;
2340 }
2341
2342 /*********************************************************************
2343 *********************************************************************/
2344 bool
registerIdentifier(void)2345 OSKext::registerIdentifier(void)
2346 {
2347 bool result = false;
2348 OSKext * existingKext = NULL; // do not release
2349 bool existingIsLoaded = false;
2350 bool existingIsPrelinked = false;
2351 bool existingIsCodeless = false;
2352 bool existingIsDext = false;
2353 OSKextVersion newVersion = -1;
2354 OSKextVersion existingVersion = -1;
2355 char newVersionCString[kOSKextVersionMaxLength];
2356 char existingVersionCString[kOSKextVersionMaxLength];
2357 OSSharedPtr<OSData> newUUID;
2358 OSSharedPtr<OSData> existingUUID;
2359
2360 IORecursiveLockLock(sKextLock);
2361
2362 /* Get the new kext's version for checks & log messages.
2363 */
2364 newVersion = getVersion();
2365 OSKextVersionGetString(newVersion, newVersionCString,
2366 kOSKextVersionMaxLength);
2367
2368 /* If we don't have an existing kext with this identifier,
2369 * just record the new kext and we're done!
2370 */
2371 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2372 if (!existingKext) {
2373 sKextsByID->setObject(bundleID.get(), this);
2374 result = true;
2375 goto finish;
2376 }
2377
2378 /* Get the existing kext's version for checks & log messages.
2379 */
2380 existingVersion = existingKext->getVersion();
2381 OSKextVersionGetString(existingVersion,
2382 existingVersionCString, kOSKextVersionMaxLength);
2383
2384 existingIsLoaded = existingKext->isLoaded();
2385 existingIsPrelinked = existingKext->isPrelinked();
2386 existingIsDext = existingKext->isDriverKit();
2387 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2388
2389 /* If we have a non-codeless kext with this identifier that's already
2390 * loaded/prelinked, we can't use the new one, but let's be really
2391 * thorough and check how the two are related for a precise diagnostic
2392 * log message.
2393 *
2394 * This check is valid for kexts that declare an executable and for
2395 * dexts, but not for codeless kexts - we can just replace those.
2396 */
2397 if ((!existingIsCodeless || existingIsDext) &&
2398 (existingIsLoaded || existingIsPrelinked)) {
2399 bool sameVersion = (newVersion == existingVersion);
2400 bool sameExecutable = true; // assume true unless we have UUIDs
2401
2402 /* Only get the UUID if the existing kext is loaded. Doing so
2403 * might have to uncompress an mkext executable and we shouldn't
2404 * take that hit when neither kext is loaded.
2405 *
2406 * Note: there is no decompression that happens when all kexts
2407 * are loaded from kext collecitons.
2408 */
2409 newUUID = copyUUID();
2410 existingUUID = existingKext->copyUUID();
2411
2412 if (existingIsDext && !isDriverKit()) {
2413 OSKextLog(this,
2414 kOSKextLogWarningLevel |
2415 kOSKextLogKextBookkeepingFlag,
2416 "Notice - new kext %s, v%s matches a %s dext"
2417 "with the same bundle ID, v%s.",
2418 getIdentifierCString(), newVersionCString,
2419 (existingIsLoaded ? "loaded" : "prelinked"),
2420 existingVersionCString);
2421 goto finish;
2422 }
2423
2424 /* I'm entirely too paranoid about checking equivalence of executables,
2425 * but I remember nasty problems with it in the past.
2426 *
2427 * - If we have UUIDs for both kexts, compare them.
2428 * - If only one kext has a UUID, they're definitely different.
2429 */
2430 if (newUUID && existingUUID) {
2431 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2432 } else if (newUUID || existingUUID) {
2433 sameExecutable = false;
2434 }
2435
2436 if (!newUUID && !existingUUID) {
2437 /* If there are no UUIDs, we can't really tell that the executables
2438 * are *different* without a lot of work; the loaded kext's
2439 * unrelocated executable is no longer around (and we never had it
2440 * in-kernel for a prelinked kext). We certainly don't want to do
2441 * a whole fake link for the new kext just to compare, either.
2442 */
2443 OSKextLog(this,
2444 kOSKextLogWarningLevel |
2445 kOSKextLogKextBookkeepingFlag,
2446 "Notice - new kext %s, v%s matches %s kext "
2447 "but can't determine if executables are the same (no UUIDs).",
2448 getIdentifierCString(),
2449 newVersionCString,
2450 (existingIsLoaded ? "loaded" : "prelinked"));
2451 }
2452
2453 if (sameVersion && sameExecutable) {
2454 OSKextLog(this,
2455 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2456 kOSKextLogKextBookkeepingFlag,
2457 "Refusing new kext %s, v%s: a %s copy is already present "
2458 "(same version and executable).",
2459 getIdentifierCString(), newVersionCString,
2460 (existingIsLoaded ? "loaded" : "prelinked"));
2461 } else {
2462 if (!sameVersion) {
2463 /* This condition is significant so log it under warnings.
2464 */
2465 OSKextLog(this,
2466 kOSKextLogWarningLevel |
2467 kOSKextLogKextBookkeepingFlag,
2468 "Refusing new kext %s, v%s: already have %s v%s.",
2469 getIdentifierCString(),
2470 newVersionCString,
2471 (existingIsLoaded ? "loaded" : "prelinked"),
2472 existingVersionCString);
2473 } else {
2474 /* This condition is significant so log it under warnings.
2475 */
2476 OSKextLog(this,
2477 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2478 "Refusing new kext %s, v%s: a %s copy with a different "
2479 "executable UUID is already present.",
2480 getIdentifierCString(), newVersionCString,
2481 (existingIsLoaded ? "loaded" : "prelinked"));
2482 }
2483 }
2484 goto finish;
2485 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2486
2487 /* Refuse to allow an existing loaded codeless kext be replaced by a
2488 * normal kext with the same bundle ID.
2489 */
2490 if (existingIsCodeless && declaresExecutable()) {
2491 OSKextLog(this,
2492 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2493 "Refusing new kext %s, v%s: a codeless copy is already %s",
2494 getIdentifierCString(), newVersionCString,
2495 (existingIsLoaded ? "loaded" : "prelinked"));
2496 goto finish;
2497 }
2498
2499 /* Dexts packaged in the BootKC will be protected against replacement
2500 * by non-dexts by the logic above which checks if they are prelinked.
2501 * Dexts which are prelinked into the System KC will be registered
2502 * before any other kexts in the AuxKC are registered, and we never
2503 * put dexts in the AuxKC. Therefore, there is no need to check if an
2504 * existing object is a dext and is being replaced by a non-dext.
2505 * The scenario cannot happen by construction.
2506 *
2507 * See: OSKext::loadFileSetKexts()
2508 */
2509
2510 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2511 * user loads are happening or if we're still in early boot. User agents are
2512 * supposed to resolve dependencies topside and include only the exact
2513 * kexts needed; so we always accept the new kext (in fact we should never
2514 * see an older unloaded copy hanging around).
2515 */
2516 if (sUserLoadsActive) {
2517 sKextsByID->setObject(bundleID.get(), this);
2518 result = true;
2519
2520 OSKextLog(this,
2521 kOSKextLogStepLevel |
2522 kOSKextLogKextBookkeepingFlag,
2523 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2524 getIdentifierCString(),
2525 existingVersionCString,
2526 newVersionCString);
2527
2528 goto finish;
2529 }
2530
2531 /* During early boot, the kext with the highest version always wins out.
2532 * Prelinked kernels will never hit this, but mkexts and booter-read
2533 * kexts might have duplicates.
2534 */
2535 if (newVersion > existingVersion) {
2536 sKextsByID->setObject(bundleID.get(), this);
2537 result = true;
2538
2539 OSKextLog(this,
2540 kOSKextLogStepLevel |
2541 kOSKextLogKextBookkeepingFlag,
2542 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2543 existingVersionCString,
2544 getIdentifierCString(),
2545 newVersionCString);
2546 } else {
2547 OSKextLog(this,
2548 kOSKextLogStepLevel |
2549 kOSKextLogKextBookkeepingFlag,
2550 "Kext %s is already registered with a higher/same version (v%s); "
2551 "dropping newly-added (v%s).",
2552 getIdentifierCString(),
2553 existingVersionCString,
2554 newVersionCString);
2555 }
2556
2557 /* result has been set appropriately by now. */
2558
2559 finish:
2560
2561 IORecursiveLockUnlock(sKextLock);
2562
2563 if (result) {
2564 OSKextLog(this,
2565 kOSKextLogStepLevel |
2566 kOSKextLogKextBookkeepingFlag,
2567 "Kext %s, v%s registered and available for loading.",
2568 getIdentifierCString(), newVersionCString);
2569 }
2570
2571 return result;
2572 }
2573
2574 /*********************************************************************
2575 * Does the bare minimum validation to look up a kext.
2576 * All other validation is done on the spot as needed.
2577 **********************************************************************/
2578 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)2579 OSKext::setInfoDictionaryAndPath(
2580 OSDictionary * aDictionary,
2581 OSString * aPath)
2582 {
2583 bool result = false;
2584 OSString * bundleIDString = NULL; // do not release
2585 OSString * versionString = NULL; // do not release
2586 OSString * compatibleVersionString = NULL; // do not release
2587 const char * versionCString = NULL; // do not free
2588 const char * compatibleVersionCString = NULL; // do not free
2589 OSBoolean * scratchBool = NULL; // do not release
2590 OSDictionary * scratchDict = NULL; // do not release
2591
2592 if (infoDict) {
2593 panic("Attempt to set info dictionary on a kext "
2594 "that already has one (%s).",
2595 getIdentifierCString());
2596 }
2597
2598 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2599 goto finish;
2600 }
2601
2602 infoDict.reset(aDictionary, OSRetain);
2603
2604 /* Check right away if the info dictionary has any log flags.
2605 */
2606 scratchBool = OSDynamicCast(OSBoolean,
2607 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2608 if (scratchBool == kOSBooleanTrue) {
2609 flags.loggingEnabled = 1;
2610 }
2611
2612 /* The very next thing to get is the bundle identifier. Unlike
2613 * in user space, a kext with no bundle identifier gets axed
2614 * immediately.
2615 */
2616 bundleIDString = OSDynamicCast(OSString,
2617 getPropertyForHostArch(kCFBundleIdentifierKey));
2618 if (!bundleIDString) {
2619 OSKextLog(this,
2620 kOSKextLogErrorLevel |
2621 kOSKextLogValidationFlag,
2622 "CFBundleIdentifier missing/invalid type in kext %s.",
2623 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2624 goto finish;
2625 }
2626 bundleID = OSSymbol::withString(bundleIDString);
2627 if (!bundleID) {
2628 OSKextLog(this,
2629 kOSKextLogErrorLevel |
2630 kOSKextLogValidationFlag,
2631 "Can't copy bundle identifier as symbol for kext %s.",
2632 bundleIDString->getCStringNoCopy());
2633 goto finish;
2634 }
2635
2636 /* Save the path if we got one (it should always be available but it's
2637 * just something nice to have for bookkeeping).
2638 */
2639 if (aPath) {
2640 path.reset(aPath, OSRetain);
2641 }
2642
2643 /*****
2644 * Minimal validation to initialize. We'll do other validation on the spot.
2645 */
2646 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2647 OSKextLog(this,
2648 kOSKextLogErrorLevel |
2649 kOSKextLogValidationFlag,
2650 "Kext %s error - CFBundleIdentifier over max length %d.",
2651 getIdentifierCString(), KMOD_MAX_NAME - 1);
2652 goto finish;
2653 }
2654
2655 version = compatibleVersion = -1;
2656
2657 versionString = OSDynamicCast(OSString,
2658 getPropertyForHostArch(kCFBundleVersionKey));
2659 if (!versionString) {
2660 OSKextLog(this,
2661 kOSKextLogErrorLevel |
2662 kOSKextLogValidationFlag,
2663 "Kext %s error - CFBundleVersion missing/invalid type.",
2664 getIdentifierCString());
2665 goto finish;
2666 }
2667 versionCString = versionString->getCStringNoCopy();
2668 version = OSKextParseVersionString(versionCString);
2669 if (version < 0) {
2670 OSKextLog(this,
2671 kOSKextLogErrorLevel |
2672 kOSKextLogValidationFlag,
2673 "Kext %s error - CFBundleVersion bad value '%s'.",
2674 getIdentifierCString(), versionCString);
2675 goto finish;
2676 }
2677
2678 compatibleVersion = -1; // set to illegal value for kexts that don't have
2679
2680 compatibleVersionString = OSDynamicCast(OSString,
2681 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2682 if (compatibleVersionString) {
2683 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2684 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2685 if (compatibleVersion < 0) {
2686 OSKextLog(this,
2687 kOSKextLogErrorLevel |
2688 kOSKextLogValidationFlag,
2689 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2690 getIdentifierCString(), compatibleVersionCString);
2691 goto finish;
2692 }
2693
2694 if (compatibleVersion > version) {
2695 OSKextLog(this,
2696 kOSKextLogErrorLevel |
2697 kOSKextLogValidationFlag,
2698 "Kext %s error - %s %s > %s %s (must be <=).",
2699 getIdentifierCString(),
2700 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2701 kCFBundleVersionKey, versionCString);
2702 goto finish;
2703 }
2704 }
2705
2706 /* Check to see if this kext is in exclude list */
2707 if (isInExcludeList()) {
2708 OSKextLog(this,
2709 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2710 "Kext %s is in exclude list, not loadable",
2711 getIdentifierCString());
2712 goto finish;
2713 }
2714
2715 /* Set flags for later use if the infoDict gets flushed. We only
2716 * check for true values, not false ones(!)
2717 */
2718 scratchBool = OSDynamicCast(OSBoolean,
2719 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2720 if (scratchBool == kOSBooleanTrue) {
2721 flags.interface = 1;
2722 }
2723
2724 scratchBool = OSDynamicCast(OSBoolean,
2725 getPropertyForHostArch(kOSKernelResourceKey));
2726 if (scratchBool == kOSBooleanTrue) {
2727 flags.kernelComponent = 1;
2728 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2729 flags.started = 1;
2730
2731 /* A kernel component has one implicit dependency on the kernel.
2732 */
2733 flags.hasAllDependencies = 1;
2734 }
2735
2736 /* Make sure common string values in personalities are uniqued to OSSymbols.
2737 */
2738 scratchDict = OSDynamicCast(OSDictionary,
2739 getPropertyForHostArch(kIOKitPersonalitiesKey));
2740 if (scratchDict) {
2741 uniquePersonalityProperties(scratchDict);
2742 }
2743
2744 result = true;
2745
2746 finish:
2747
2748 return result;
2749 }
2750
2751 /*********************************************************************
2752 * Not used for prelinked kernel boot as there is no unrelocated
2753 * executable.
2754 *********************************************************************/
2755 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)2756 OSKext::setExecutable(
2757 OSData * anExecutable,
2758 OSData * externalData,
2759 bool externalDataIsMkext)
2760 {
2761 bool result = false;
2762 const char * executableKey = NULL; // do not free
2763
2764 if (!anExecutable) {
2765 infoDict->removeObject(_kOSKextExecutableKey);
2766 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2767 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2768 result = true;
2769 goto finish;
2770 }
2771
2772 if (infoDict->getObject(_kOSKextExecutableKey) ||
2773 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2774 panic("Attempt to set an executable on a kext "
2775 "that already has one (%s).",
2776 getIdentifierCString());
2777 goto finish;
2778 }
2779
2780 if (externalDataIsMkext) {
2781 executableKey = _kOSKextMkextExecutableReferenceKey;
2782 } else {
2783 executableKey = _kOSKextExecutableKey;
2784 }
2785
2786 if (anExecutable) {
2787 infoDict->setObject(executableKey, anExecutable);
2788 if (externalData) {
2789 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2790 }
2791 }
2792
2793 result = true;
2794
2795 finish:
2796 return result;
2797 }
2798
2799 /*********************************************************************
2800 *********************************************************************/
2801 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)2802 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2803 {
2804 OSObject * value = NULL; // do not release
2805 OSString * stringValue = NULL; // do not release
2806 OSSharedPtr<const OSSymbol> symbolValue;
2807
2808 value = dict->getObject(key);
2809 if (!value) {
2810 goto finish;
2811 }
2812 if (OSDynamicCast(OSSymbol, value)) {
2813 /* this is already an OSSymbol: we're good */
2814 goto finish;
2815 }
2816
2817 stringValue = OSDynamicCast(OSString, value);
2818 if (!stringValue) {
2819 goto finish;
2820 }
2821
2822 symbolValue = OSSymbol::withString(stringValue);
2823 if (!symbolValue) {
2824 goto finish;
2825 }
2826
2827 dict->setObject(key, symbolValue.get());
2828
2829 finish:
2830 return;
2831 }
2832
2833 /*********************************************************************
2834 *********************************************************************/
2835 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)2836 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2837 {
2838 OSObject * value = NULL; // do not release
2839 OSString * stringValue = NULL; // do not release
2840 OSSharedPtr<const OSSymbol> symbolValue;
2841
2842 value = dict->getObject(key);
2843 if (!value) {
2844 goto finish;
2845 }
2846 if (OSDynamicCast(OSSymbol, value)) {
2847 /* this is already an OSSymbol: we're good */
2848 goto finish;
2849 }
2850
2851 stringValue = OSDynamicCast(OSString, value);
2852 if (!stringValue) {
2853 goto finish;
2854 }
2855
2856 symbolValue = OSSymbol::withString(stringValue);
2857 if (!symbolValue) {
2858 goto finish;
2859 }
2860
2861 dict->setObject(key, symbolValue.get());
2862
2863 finish:
2864 return;
2865 }
2866
2867 void
uniquePersonalityProperties(OSDictionary * personalityDict)2868 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2869 {
2870 OSKext::uniquePersonalityProperties(personalityDict, true);
2871 }
2872
2873 /*********************************************************************
2874 * Replace common personality property values with uniqued instances
2875 * to save on wired memory.
2876 *********************************************************************/
2877 /* static */
2878 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)2879 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
2880 {
2881 /* Properties every personality has.
2882 */
2883 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2884 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2885 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
2886 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
2887 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
2888 } else if (defaultAddKernelBundleIdentifier) {
2889 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
2890 }
2891
2892 /* Other commonly used properties.
2893 */
2894 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2895 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2896 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2897
2898 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2899 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2900 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2901 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2902 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2903 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2904 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2905 uniqueStringPlistProperty(personalityDict, "Vendor");
2906 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2907 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2908 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2909 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2910 uniqueStringPlistProperty(personalityDict, "idProduct");
2911
2912 return;
2913 }
2914
2915 /*********************************************************************
2916 *********************************************************************/
2917 void
free(void)2918 OSKext::free(void)
2919 {
2920 if (isLoaded()) {
2921 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2922 }
2923
2924 infoDict.reset();
2925 bundleID.reset();
2926 path.reset();
2927 executableRelPath.reset();
2928 userExecutableRelPath.reset();
2929 dependencies.reset();
2930 linkedExecutable.reset();
2931 metaClasses.reset();
2932 interfaceUUID.reset();
2933 driverKitUUID.reset();
2934
2935 if (isInterface() && kmod_info) {
2936 kfree_type(kmod_info_t, kmod_info);
2937 }
2938
2939 super::free();
2940 return;
2941 }
2942
2943 #if PRAGMA_MARK
2944 #pragma mark Mkext files
2945 #endif
2946
2947 #if CONFIG_KXLD
2948 /*
2949 * mkext archives are really only relevant on kxld-enabled kernels.
2950 * Without a dynamic kernel linker, we don't need to support any mkexts.
2951 */
2952
2953 /*********************************************************************
2954 *********************************************************************/
2955 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)2956 OSKext::readMkextArchive(OSData * mkextData,
2957 uint32_t * checksumPtr)
2958 {
2959 OSReturn result = kOSKextReturnBadData;
2960 uint32_t mkextLength = 0;
2961 mkext_header * mkextHeader = NULL; // do not free
2962 uint32_t mkextVersion = 0;
2963
2964 /* Note default return of kOSKextReturnBadData above.
2965 */
2966 mkextLength = mkextData->getLength();
2967 if (mkextLength < sizeof(mkext_basic_header)) {
2968 OSKextLog(/* kext */ NULL,
2969 kOSKextLogErrorLevel |
2970 kOSKextLogArchiveFlag,
2971 "Mkext archive too small to be valid.");
2972 goto finish;
2973 }
2974
2975 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2976
2977 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2978 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2979 OSKextLog(/* kext */ NULL,
2980 kOSKextLogErrorLevel |
2981 kOSKextLogArchiveFlag,
2982 "Mkext archive has invalid magic or signature.");
2983 goto finish;
2984 }
2985
2986 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2987 OSKextLog(/* kext */ NULL,
2988 kOSKextLogErrorLevel |
2989 kOSKextLogArchiveFlag,
2990 "Mkext archive recorded length doesn't match actual file length.");
2991 goto finish;
2992 }
2993
2994 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2995
2996 if (mkextVersion == MKEXT_VERS_2) {
2997 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2998 } else {
2999 OSKextLog(/* kext */ NULL,
3000 kOSKextLogErrorLevel |
3001 kOSKextLogArchiveFlag,
3002 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3003 result = kOSKextReturnUnsupported;
3004 }
3005
3006 finish:
3007 return result;
3008 }
3009
3010 /*********************************************************************
3011 * Assumes magic, signature, version, length have been checked.
3012 * xxx - need to add further bounds checking for each file entry
3013 *
3014 * Should keep track of all kexts created so far, and if we hit a
3015 * fatal error halfway through, remove those kexts. If we've dropped
3016 * an older version that had already been read, whoops! Might want to
3017 * add a level of buffering?
3018 *********************************************************************/
3019 /* static */
3020 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3021 OSKext::readMkext2Archive(
3022 OSData * mkextData,
3023 OSDictionary ** mkextPlistOut,
3024 uint32_t * checksumPtr)
3025 {
3026 OSReturn result = kOSReturnError;
3027 uint32_t mkextLength;
3028 mkext2_header * mkextHeader = NULL; // do not free
3029 void * mkextEnd = NULL; // do not free
3030 uint32_t mkextVersion;
3031 uint8_t * crc_address = NULL;
3032 size_t crc_buffer_size = 0;
3033 uint32_t checksum;
3034 uint32_t mkextPlistOffset;
3035 uint32_t mkextPlistCompressedSize;
3036 char * mkextPlistEnd = NULL; // do not free
3037 uint32_t mkextPlistFullSize;
3038 OSSharedPtr<OSString> errorString;
3039 OSSharedPtr<OSData> mkextPlistUncompressedData;
3040 const char * mkextPlistDataBuffer = NULL; // do not free
3041 OSSharedPtr<OSObject> parsedXML;
3042 OSDictionary * mkextPlist = NULL; // do not release
3043 OSArray * mkextInfoDictArray = NULL; // do not release
3044 uint32_t count, i;
3045 kc_format_t kc_format;
3046
3047 if (!PE_get_primary_kc_format(&kc_format)) {
3048 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3049 "Unable to determine primary KC format");
3050 goto finish;
3051 }
3052
3053 mkextLength = mkextData->getLength();
3054 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3055 mkextEnd = (char *)mkextHeader + mkextLength;
3056 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3057
3058 crc_address = (u_int8_t *)&mkextHeader->version;
3059 crc_buffer_size = (uintptr_t)mkextHeader +
3060 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3061 if (crc_buffer_size > INT32_MAX) {
3062 OSKextLog(/* kext */ NULL,
3063 kOSKextLogErrorLevel |
3064 kOSKextLogArchiveFlag,
3065 "Mkext archive size is too large (%lu > INT32_MAX).",
3066 crc_buffer_size);
3067 result = kOSKextReturnBadData;
3068 goto finish;
3069 }
3070 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3071
3072 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3073 OSKextLog(/* kext */ NULL,
3074 kOSKextLogErrorLevel |
3075 kOSKextLogArchiveFlag,
3076 "Mkext archive has bad checksum.");
3077 result = kOSKextReturnBadData;
3078 goto finish;
3079 }
3080
3081 if (checksumPtr) {
3082 *checksumPtr = checksum;
3083 }
3084
3085 /* Check that the CPU type & subtype match that of the running kernel. */
3086 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3087 OSKextLog(/* kext */ NULL,
3088 kOSKextLogErrorLevel |
3089 kOSKextLogArchiveFlag,
3090 "Mkext archive must have a specific CPU type.");
3091 result = kOSKextReturnBadData;
3092 goto finish;
3093 } else {
3094 if ((UInt32)_mh_execute_header.cputype !=
3095 MKEXT_GET_CPUTYPE(mkextHeader)) {
3096 OSKextLog(/* kext */ NULL,
3097 kOSKextLogErrorLevel |
3098 kOSKextLogArchiveFlag,
3099 "Mkext archive does not match the running kernel's CPU type.");
3100 result = kOSKextReturnArchNotFound;
3101 goto finish;
3102 }
3103 }
3104
3105 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3106 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3107 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3108 mkextPlistCompressedSize;
3109 if (mkextPlistEnd > mkextEnd) {
3110 OSKextLog(/* kext */ NULL,
3111 kOSKextLogErrorLevel |
3112 kOSKextLogArchiveFlag,
3113 "Mkext archive file overrun.");
3114 result = kOSKextReturnBadData;
3115 }
3116
3117 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3118 if (mkextPlistCompressedSize) {
3119 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3120 (UInt8 *)mkextHeader + mkextPlistOffset,
3121 "plist",
3122 mkextPlistCompressedSize, mkextPlistFullSize);
3123 if (!mkextPlistUncompressedData) {
3124 goto finish;
3125 }
3126 mkextPlistDataBuffer = (const char *)
3127 mkextPlistUncompressedData->getBytesNoCopy();
3128 } else {
3129 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3130 }
3131
3132 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3133 */
3134 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3135 if (parsedXML) {
3136 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3137 }
3138 if (!mkextPlist) {
3139 const char * errorCString = "(unknown error)";
3140
3141 if (errorString && errorString->getCStringNoCopy()) {
3142 errorCString = errorString->getCStringNoCopy();
3143 } else if (parsedXML) {
3144 errorCString = "not a dictionary";
3145 }
3146 OSKextLog(/* kext */ NULL,
3147 kOSKextLogErrorLevel |
3148 kOSKextLogArchiveFlag,
3149 "Error unserializing mkext plist: %s.", errorCString);
3150 goto finish;
3151 }
3152
3153 mkextInfoDictArray = OSDynamicCast(OSArray,
3154 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3155 if (!mkextInfoDictArray) {
3156 OSKextLog(/* kext */ NULL,
3157 kOSKextLogErrorLevel |
3158 kOSKextLogArchiveFlag,
3159 "Mkext archive contains no kext info dictionaries.");
3160 goto finish;
3161 }
3162
3163 count = mkextInfoDictArray->getCount();
3164 for (i = 0; i < count; i++) {
3165 OSDictionary * infoDict;
3166
3167
3168 infoDict = OSDynamicCast(OSDictionary,
3169 mkextInfoDictArray->getObject(i));
3170
3171 /* Create the kext for the entry, then release it, because the
3172 * kext system keeps them around until explicitly removed.
3173 * Any creation/registration failures are already logged for us.
3174 */
3175 if (infoDict) {
3176 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3177
3178 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3179 if (kc_format == KCFormatFileset &&
3180 newKext &&
3181 !(newKext->isPrelinked()) &&
3182 newKext->declaresExecutable()) {
3183 result = kOSReturnError;
3184 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3185 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3186
3187 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3188 "Dynamic loading of kext denied for kext %s\n",
3189 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3190 goto finish;
3191 }
3192 }
3193 }
3194
3195 /* If the caller needs the plist, hand them back our copy
3196 */
3197 if (mkextPlistOut) {
3198 *mkextPlistOut = mkextPlist;
3199 parsedXML.detach();
3200 }
3201
3202 /* Even if we didn't keep any kexts from the mkext, we may have a load
3203 * request to process, so we are successful (no errors occurred).
3204 */
3205 result = kOSReturnSuccess;
3206
3207 finish:
3208 return result;
3209 }
3210
3211 /* static */
3212 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3213 OSKext::readMkext2Archive(
3214 OSData * mkextData,
3215 OSSharedPtr<OSDictionary> &mkextPlistOut,
3216 uint32_t * checksumPtr)
3217 {
3218 OSDictionary * mkextPlist = NULL;
3219 OSReturn ret;
3220
3221 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3222 &mkextPlist,
3223 checksumPtr))) {
3224 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3225 }
3226 return ret;
3227 }
3228
3229 /*********************************************************************
3230 *********************************************************************/
3231 /* static */
3232 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3233 OSKext::withMkext2Info(
3234 OSDictionary * anInfoDict,
3235 OSData * mkextData)
3236 {
3237 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3238
3239 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3240 return NULL;
3241 }
3242
3243 return newKext;
3244 }
3245
3246 /*********************************************************************
3247 *********************************************************************/
3248 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3249 OSKext::initWithMkext2Info(
3250 OSDictionary * anInfoDict,
3251 OSData * mkextData)
3252 {
3253 bool result = false;
3254 OSString * kextPath = NULL; // do not release
3255 OSNumber * executableOffsetNum = NULL; // do not release
3256 OSSharedPtr<OSData> executable;
3257
3258 if (anInfoDict == NULL || !super::init()) {
3259 goto finish;
3260 }
3261
3262 /* Get the path. Don't look for an arch-specific path property.
3263 */
3264 kextPath = OSDynamicCast(OSString,
3265 anInfoDict->getObject(kMKEXTBundlePathKey));
3266
3267 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3268 goto finish;
3269 }
3270
3271 /* If we have a path to the executable, save it.
3272 */
3273 executableRelPath.reset(OSDynamicCast(OSString,
3274 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3275
3276 /* Don't need the paths to be in the info dictionary any more.
3277 */
3278 anInfoDict->removeObject(kMKEXTBundlePathKey);
3279 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3280
3281 executableOffsetNum = OSDynamicCast(OSNumber,
3282 infoDict->getObject(kMKEXTExecutableKey));
3283 if (executableOffsetNum) {
3284 executable = createMkext2FileEntry(mkextData,
3285 executableOffsetNum, "executable");
3286 infoDict->removeObject(kMKEXTExecutableKey);
3287 if (!executable) {
3288 goto finish;
3289 }
3290 if (!setExecutable(executable.get(), mkextData, true)) {
3291 goto finish;
3292 }
3293 }
3294
3295 result = registerIdentifier();
3296
3297 finish:
3298 return result;
3299 }
3300
3301 /*********************************************************************
3302 *********************************************************************/
3303 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3304 OSKext::createMkext2FileEntry(
3305 OSData * mkextData,
3306 OSNumber * offsetNum,
3307 const char * name)
3308 {
3309 OSSharedPtr<OSData> result;
3310 MkextEntryRef entryRef;
3311 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3312 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3313
3314 result = OSData::withCapacity(sizeof(entryRef));
3315 if (!result) {
3316 goto finish;
3317 }
3318
3319 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3320 entryRef.fileinfo = mkextBuffer + entryOffset;
3321 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
3322 result.reset();
3323 goto finish;
3324 }
3325
3326 finish:
3327 if (!result) {
3328 OSKextLog(this,
3329 kOSKextLogErrorLevel |
3330 kOSKextLogArchiveFlag,
3331 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3332 name, getIdentifierCString());
3333 }
3334 return result;
3335 }
3336
3337 /*********************************************************************
3338 *********************************************************************/
3339 extern "C" {
3340 static void * z_alloc(void *, u_int items, u_int size);
3341 static void z_free(void *, void *ptr);
3342
3343 typedef struct z_mem {
3344 uint32_t alloc_size;
3345 uint8_t data[0];
3346 } z_mem;
3347
3348 /*
3349 * Space allocation and freeing routines for use by zlib routines.
3350 */
3351 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3352 z_alloc(void * notused __unused, u_int num_items, u_int size)
3353 {
3354 void * result = NULL;
3355 z_mem * zmem = NULL;
3356
3357 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3358 //Check for overflow due to multiplication
3359 if (total > UINT32_MAX) {
3360 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3361 notused, num_items, size, num_items, size);
3362 }
3363
3364 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3365 //Check for overflow due to addition
3366 if (allocSize64 > UINT32_MAX) {
3367 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3368 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3369 }
3370 uint32_t allocSize = (uint32_t)allocSize64;
3371
3372 zmem = (z_mem *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, allocSize,
3373 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
3374 if (!zmem) {
3375 goto finish;
3376 }
3377 zmem->alloc_size = allocSize;
3378 result = (void *)&(zmem->data);
3379 finish:
3380 return result;
3381 }
3382
3383 void
z_free(void * notused __unused,void * ptr)3384 z_free(void * notused __unused, void * ptr)
3385 {
3386 uint32_t * skipper = (uint32_t *)ptr - 1;
3387 z_mem * zmem = (z_mem *)skipper;
3388 kheap_free(KHEAP_DATA_BUFFERS, zmem, zmem->alloc_size);
3389 return;
3390 }
3391 };
3392
3393 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3394 OSKext::extractMkext2FileData(
3395 UInt8 * data,
3396 const char * name,
3397 uint32_t compressedSize,
3398 uint32_t fullSize)
3399 {
3400 OSSharedPtr<OSData> result;
3401 OSSharedPtr<OSData> uncompressedData; // release on error
3402
3403 uint8_t * uncompressedDataBuffer = NULL; // do not free
3404 unsigned long uncompressedSize;
3405 z_stream zstream;
3406 bool zstream_inited = false;
3407 int zlib_result;
3408
3409 /* If the file isn't compressed, we want to make a copy
3410 * so that we don't have the tie to the larger mkext file buffer any more.
3411 */
3412 if (!compressedSize) {
3413 uncompressedData = OSData::withBytes(data, fullSize);
3414 // xxx - no check for failure?
3415 result = uncompressedData;
3416 goto finish;
3417 }
3418
3419 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3420 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
3421 /* How's this for cheesy? The kernel is only asked to extract
3422 * kext plists so we tailor the log messages.
3423 */
3424 if (isKernel()) {
3425 OSKextLog(this,
3426 kOSKextLogErrorLevel |
3427 kOSKextLogArchiveFlag,
3428 "Allocation failure extracting %s from mkext.", name);
3429 } else {
3430 OSKextLog(this,
3431 kOSKextLogErrorLevel |
3432 kOSKextLogArchiveFlag,
3433 "Allocation failure extracting %s from mkext for kext %s.",
3434 name, getIdentifierCString());
3435 }
3436
3437 goto finish;
3438 }
3439 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3440 if (!uncompressedData) {
3441 if (isKernel()) {
3442 OSKextLog(this,
3443 kOSKextLogErrorLevel |
3444 kOSKextLogArchiveFlag,
3445 "Allocation failure extracting %s from mkext.", name);
3446 } else {
3447 OSKextLog(this,
3448 kOSKextLogErrorLevel |
3449 kOSKextLogArchiveFlag,
3450 "Allocation failure extracting %s from mkext for kext %s.",
3451 name, getIdentifierCString());
3452 }
3453 goto finish;
3454 }
3455 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3456
3457 if (isKernel()) {
3458 OSKextLog(this,
3459 kOSKextLogDetailLevel |
3460 kOSKextLogArchiveFlag,
3461 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3462 name, compressedSize, fullSize);
3463 } else {
3464 OSKextLog(this,
3465 kOSKextLogDetailLevel |
3466 kOSKextLogArchiveFlag,
3467 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3468 getIdentifierCString(), name, compressedSize, fullSize);
3469 }
3470
3471 bzero(&zstream, sizeof(zstream));
3472 zstream.next_in = (UInt8 *)data;
3473 zstream.avail_in = compressedSize;
3474
3475 zstream.next_out = uncompressedDataBuffer;
3476 zstream.avail_out = fullSize;
3477
3478 zstream.zalloc = z_alloc;
3479 zstream.zfree = z_free;
3480
3481 zlib_result = inflateInit(&zstream);
3482 if (Z_OK != zlib_result) {
3483 if (isKernel()) {
3484 OSKextLog(this,
3485 kOSKextLogErrorLevel |
3486 kOSKextLogArchiveFlag,
3487 "Mkext error; zlib inflateInit failed (%d) for %s.",
3488 zlib_result, name);
3489 } else {
3490 OSKextLog(this,
3491 kOSKextLogErrorLevel |
3492 kOSKextLogArchiveFlag,
3493 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3494 getIdentifierCString(), zlib_result, name);
3495 }
3496 goto finish;
3497 } else {
3498 zstream_inited = true;
3499 }
3500
3501 zlib_result = inflate(&zstream, Z_FINISH);
3502
3503 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3504 uncompressedSize = zstream.total_out;
3505 } else {
3506 if (isKernel()) {
3507 OSKextLog(this,
3508 kOSKextLogErrorLevel |
3509 kOSKextLogArchiveFlag,
3510 "Mkext error; zlib inflate failed (%d) for %s.",
3511 zlib_result, name);
3512 } else {
3513 OSKextLog(this,
3514 kOSKextLogErrorLevel |
3515 kOSKextLogArchiveFlag,
3516 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3517 getIdentifierCString(), zlib_result, name);
3518 }
3519 if (zstream.msg) {
3520 OSKextLog(this,
3521 kOSKextLogErrorLevel |
3522 kOSKextLogArchiveFlag,
3523 "zlib error: %s.", zstream.msg);
3524 }
3525 goto finish;
3526 }
3527
3528 if (uncompressedSize != fullSize) {
3529 if (isKernel()) {
3530 OSKextLog(this,
3531 kOSKextLogErrorLevel |
3532 kOSKextLogArchiveFlag,
3533 "Mkext error; zlib inflate discrepancy for %s, "
3534 "uncompressed size != original size.", name);
3535 } else {
3536 OSKextLog(this,
3537 kOSKextLogErrorLevel |
3538 kOSKextLogArchiveFlag,
3539 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3540 "uncompressed size != original size.",
3541 getIdentifierCString(), name);
3542 }
3543 goto finish;
3544 }
3545
3546 result = os::move(uncompressedData);
3547
3548 finish:
3549 /* Don't bother checking return, nothing we can do on fail.
3550 */
3551 if (zstream_inited) {
3552 inflateEnd(&zstream);
3553 }
3554
3555 return result;
3556 }
3557
3558 /*********************************************************************
3559 *********************************************************************/
3560 /* static */
3561 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3562 OSKext::loadFromMkext(
3563 OSKextLogSpec clientLogFilter,
3564 char * mkextBuffer,
3565 uint32_t mkextBufferLength,
3566 char ** logInfoOut,
3567 uint32_t * logInfoLengthOut)
3568 {
3569 OSReturn result = kOSReturnError;
3570 OSReturn tempResult = kOSReturnError;
3571
3572 OSSharedPtr<OSData> mkextData;
3573 OSSharedPtr<OSDictionary> mkextPlist;
3574
3575 OSSharedPtr<OSArray> logInfoArray;
3576 OSSharedPtr<OSSerialize> serializer;
3577
3578 OSString * predicate = NULL; // do not release
3579 OSDictionary * requestArgs = NULL; // do not release
3580
3581 OSString * kextIdentifier = NULL; // do not release
3582 OSNumber * startKextExcludeNum = NULL; // do not release
3583 OSNumber * startMatchingExcludeNum = NULL; // do not release
3584 OSBoolean * delayAutounloadBool = NULL; // do not release
3585 OSArray * personalityNames = NULL; // do not release
3586
3587 /* Default values for these two options: regular autounload behavior,
3588 * load all kexts, send no personalities.
3589 */
3590 Boolean delayAutounload = false;
3591 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3592 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3593
3594 IORecursiveLockLock(sKextLock);
3595
3596 if (logInfoOut) {
3597 *logInfoOut = NULL;
3598 *logInfoLengthOut = 0;
3599 }
3600
3601 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3602
3603 OSKextLog(/* kext */ NULL,
3604 kOSKextLogDebugLevel |
3605 kOSKextLogIPCFlag,
3606 "Received kext load request from user space.");
3607
3608 /* Regardless of processing, the fact that we have gotten here means some
3609 * user-space program is up and talking to us, so we'll switch our kext
3610 * registration to reflect that.
3611 */
3612 if (!sUserLoadsActive) {
3613 OSKextLog(/* kext */ NULL,
3614 kOSKextLogProgressLevel |
3615 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3616 "Switching to late startup (user-space) kext loading policy.");
3617
3618 sUserLoadsActive = true;
3619 }
3620
3621 if (!sLoadEnabled) {
3622 OSKextLog(/* kext */ NULL,
3623 kOSKextLogErrorLevel |
3624 kOSKextLogLoadFlag,
3625 "Kext loading is disabled.");
3626 result = kOSKextReturnDisabled;
3627 goto finish;
3628 }
3629
3630 /* Note that we do not set a dealloc function on this OSData
3631 * object! No references to it can remain after the loadFromMkext()
3632 * call since we are in a MIG function, and will vm_deallocate()
3633 * the buffer.
3634 */
3635 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3636 mkextBufferLength);
3637 if (!mkextData) {
3638 OSKextLog(/* kext */ NULL,
3639 kOSKextLogErrorLevel |
3640 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3641 "Failed to create wrapper for kext load request.");
3642 result = kOSKextReturnNoMemory;
3643 goto finish;
3644 }
3645
3646 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3647 if (result != kOSReturnSuccess) {
3648 OSKextLog(/* kext */ NULL,
3649 kOSKextLogErrorLevel |
3650 kOSKextLogLoadFlag,
3651 "Failed to read kext load request.");
3652 goto finish;
3653 }
3654
3655 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3656 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3657 OSKextLog(/* kext */ NULL,
3658 kOSKextLogErrorLevel |
3659 kOSKextLogLoadFlag,
3660 "Received kext load request with no predicate; skipping.");
3661 result = kOSKextReturnInvalidArgument;
3662 goto finish;
3663 }
3664
3665 requestArgs = OSDynamicCast(OSDictionary,
3666 mkextPlist->getObject(kKextRequestArgumentsKey));
3667 if (!requestArgs || !requestArgs->getCount()) {
3668 OSKextLog(/* kext */ NULL,
3669 kOSKextLogErrorLevel |
3670 kOSKextLogLoadFlag,
3671 "Received kext load request with no arguments.");
3672 result = kOSKextReturnInvalidArgument;
3673 goto finish;
3674 }
3675
3676 kextIdentifier = OSDynamicCast(OSString,
3677 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3678
3679 if (!kextIdentifier) {
3680 OSKextLog(/* kext */ NULL,
3681 kOSKextLogErrorLevel |
3682 kOSKextLogLoadFlag,
3683 "Received kext load request with no kext identifier.");
3684 result = kOSKextReturnInvalidArgument;
3685 goto finish;
3686 }
3687
3688 startKextExcludeNum = OSDynamicCast(OSNumber,
3689 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3690 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3691 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3692 delayAutounloadBool = OSDynamicCast(OSBoolean,
3693 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3694 personalityNames = OSDynamicCast(OSArray,
3695 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3696
3697 if (delayAutounloadBool) {
3698 delayAutounload = delayAutounloadBool->getValue();
3699 }
3700 if (startKextExcludeNum) {
3701 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3702 }
3703 if (startMatchingExcludeNum) {
3704 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3705 }
3706
3707 OSKextLog(/* kext */ NULL,
3708 kOSKextLogProgressLevel |
3709 kOSKextLogIPCFlag,
3710 "Received request from user space to load kext %s.",
3711 kextIdentifier->getCStringNoCopy());
3712
3713 /* Load the kext, with no deferral, since this is a load from outside
3714 * the kernel.
3715 * xxx - Would like a better way to handle the default values for the
3716 * xxx - start/match opt args.
3717 */
3718 result = OSKext::loadKextWithIdentifier(
3719 kextIdentifier,
3720 /* kextRef */ NULL,
3721 /* allowDefer */ false,
3722 delayAutounload,
3723 startKextExcludeLevel,
3724 startMatchingExcludeLevel,
3725 personalityNames);
3726 if (result != kOSReturnSuccess) {
3727 goto finish;
3728 }
3729 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3730 * for matching via a separate IOKit calldown.
3731 */
3732
3733 finish:
3734
3735 /* Gather up the collected log messages for user space. Any
3736 * error messages past this call will not make it up as log messages
3737 * but will be in the system log.
3738 */
3739 logInfoArray = OSKext::clearUserSpaceLogFilter();
3740
3741 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3742 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3743 logInfoOut, logInfoLengthOut);
3744 if (tempResult != kOSReturnSuccess) {
3745 result = tempResult;
3746 }
3747 }
3748
3749 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3750
3751 IORecursiveLockUnlock(sKextLock);
3752
3753 /* Note: mkextDataObject will have been retained by every kext w/an
3754 * executable in it. That should all have been flushed out at the
3755 * and of the load operation, but you never know....
3756 */
3757 if (mkextData && mkextData->getRetainCount() > 1) {
3758 OSKextLog(/* kext */ NULL,
3759 kOSKextLogErrorLevel |
3760 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3761 "Kext load request buffer from user space still retained by a kext; "
3762 "probable memory leak.");
3763 }
3764
3765 return result;
3766 }
3767
3768 #endif // CONFIG_KXLD
3769
3770 /*********************************************************************
3771 *********************************************************************/
3772 /* static */
3773 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)3774 OSKext::serializeLogInfo(
3775 OSArray * logInfoArray,
3776 char ** logInfoOut,
3777 uint32_t * logInfoLengthOut)
3778 {
3779 OSReturn result = kOSReturnError;
3780 char * buffer = NULL;
3781 kern_return_t kmem_result = KERN_FAILURE;
3782 OSSharedPtr<OSSerialize> serializer;
3783 char * logInfo = NULL; // returned by reference
3784 uint32_t logInfoLength = 0;
3785
3786 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3787 OSKextLog(/* kext */ NULL,
3788 kOSKextLogErrorLevel |
3789 kOSKextLogIPCFlag,
3790 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3791 /* Bad programmer. */
3792 result = kOSKextReturnInvalidArgument;
3793 goto finish;
3794 }
3795
3796 serializer = OSSerialize::withCapacity(0);
3797 if (!serializer) {
3798 OSKextLog(/* kext */ NULL,
3799 kOSKextLogErrorLevel |
3800 kOSKextLogIPCFlag,
3801 "Failed to create serializer on log info for request from user space.");
3802 /* Incidental error; we're going to (try to) allow the request
3803 * itself to succeed. */
3804 }
3805
3806 if (!logInfoArray->serialize(serializer.get())) {
3807 OSKextLog(/* kext */ NULL,
3808 kOSKextLogErrorLevel |
3809 kOSKextLogIPCFlag,
3810 "Failed to serialize log info for request from user space.");
3811 /* Incidental error; we're going to (try to) allow the request
3812 * itself to succeed. */
3813 } else {
3814 logInfo = serializer->text();
3815 logInfoLength = serializer->getLength();
3816
3817 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3818 if (kmem_result != KERN_SUCCESS) {
3819 OSKextLog(/* kext */ NULL,
3820 kOSKextLogErrorLevel |
3821 kOSKextLogIPCFlag,
3822 "Failed to copy log info for request from user space.");
3823 /* Incidental error; we're going to (try to) allow the request
3824 * to succeed. */
3825 } else {
3826 /* 11981737 - clear uninitialized data in last page */
3827 bzero((void *)(buffer + logInfoLength),
3828 (round_page(logInfoLength) - logInfoLength));
3829 memcpy(buffer, logInfo, logInfoLength);
3830 *logInfoOut = buffer;
3831 *logInfoLengthOut = logInfoLength;
3832 }
3833 }
3834
3835 result = kOSReturnSuccess;
3836 finish:
3837 return result;
3838 }
3839
3840 #if PRAGMA_MARK
3841 #pragma mark Instance Management Methods
3842 #endif
3843 /*********************************************************************
3844 *********************************************************************/
3845 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)3846 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3847 {
3848 OSSharedPtr<OSKext> foundKext;
3849
3850 IORecursiveLockLock(sKextLock);
3851 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
3852 IORecursiveLockUnlock(sKextLock);
3853
3854 return foundKext;
3855 }
3856
3857 /*********************************************************************
3858 *********************************************************************/
3859 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)3860 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3861 {
3862 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3863 }
3864
3865 /*********************************************************************
3866 *********************************************************************/
3867 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)3868 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3869 {
3870 OSSharedPtr<OSKext> foundKext; // returned
3871 uint32_t i, j;
3872 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3873 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3874
3875 IORecursiveLockLock(sKextLock);
3876
3877 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3878 for (i = 0; i < count[j]; i++) {
3879 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3880 if (thisKext->getLoadTag() == aTag) {
3881 foundKext.reset(thisKext, OSRetain);
3882 goto finish;
3883 }
3884 }
3885 }
3886
3887 finish:
3888 IORecursiveLockUnlock(sKextLock);
3889
3890 return foundKext;
3891 }
3892
3893 /*********************************************************************
3894 *********************************************************************/
3895 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)3896 OSKext::lookupKextWithAddress(vm_address_t address)
3897 {
3898 OSSharedPtr<OSKext> foundKext; // returned
3899 uint32_t count, i;
3900 kmod_info_t *kmod_info;
3901 vm_address_t originalAddress;
3902 #if defined(__arm64__)
3903 uint64_t textExecBase;
3904 size_t textExecSize;
3905 #endif /* defined(__arm64__) */
3906
3907 originalAddress = address;
3908 #if __has_feature(ptrauth_calls)
3909 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3910 #endif /* __has_feature(ptrauth_calls) */
3911
3912 IORecursiveLockLock(sKextLock);
3913
3914 count = sLoadedKexts->getCount();
3915 for (i = 0; i < count; i++) {
3916 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3917 if (thisKext == sKernelKext) {
3918 continue;
3919 }
3920 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3921 kmod_info = thisKext->kmod_info;
3922 vm_address_t kext_start = kmod_info->address;
3923 vm_address_t kext_end = kext_start + kmod_info->size;
3924 if ((kext_start <= address) && (address < kext_end)) {
3925 foundKext.reset(thisKext, OSRetain);
3926 goto finish;
3927 }
3928 #if defined(__arm64__)
3929 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3930 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3931 foundKext.reset(thisKext, OSRetain);
3932 goto finish;
3933 }
3934 #endif /* defined (__arm64__) */
3935 }
3936 }
3937 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3938 foundKext.reset(sKernelKext, OSRetain);
3939 goto finish;
3940 }
3941 /*
3942 * DriverKit userspace executables do not have a kernel linkedExecutable,
3943 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3944 * here, so use the original address passed to this method.
3945 *
3946 * This is supposed to be used for logging reasons only. When logd
3947 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3948 * remove it here before checking it against the LoadTag.
3949 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3950 */
3951
3952 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
3953 count = sLoadedDriverKitKexts->getCount();
3954 for (i = 0; i < count; i++) {
3955 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
3956 if (thisKext->getLoadTag() == address) {
3957 foundKext.reset(thisKext, OSRetain);
3958 }
3959 }
3960
3961 finish:
3962 IORecursiveLockUnlock(sKextLock);
3963
3964 return foundKext;
3965 }
3966
3967 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)3968 OSKext::copyKextUUIDForAddress(OSNumber *address)
3969 {
3970 OSSharedPtr<OSData> uuid;
3971 OSSharedPtr<OSKext> kext;
3972
3973 if (!address) {
3974 return NULL;
3975 }
3976
3977 #if CONFIG_MACF
3978 /* Is the calling process allowed to query kext info? */
3979 if (current_task() != kernel_task) {
3980 int macCheckResult = 0;
3981 kauth_cred_t cred = NULL;
3982
3983 cred = kauth_cred_get_with_ref();
3984 macCheckResult = mac_kext_check_query(cred);
3985 kauth_cred_unref(&cred);
3986
3987 if (macCheckResult != 0) {
3988 OSKextLog(/* kext */ NULL,
3989 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3990 "Failed to query kext UUID (MAC policy error 0x%x).",
3991 macCheckResult);
3992 return NULL;
3993 }
3994 }
3995 #endif
3996
3997 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3998 if (slidAddress != 0) {
3999 kext = lookupKextWithAddress(slidAddress);
4000 if (kext) {
4001 uuid = kext->copyTextUUID();
4002 }
4003 }
4004
4005 if (!uuid) {
4006 /*
4007 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4008 * a kext. This might have happened because the log message came from a dext.
4009 *
4010 * Try again with the original address.
4011 */
4012 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4013 if (kext && kext->isDriverKit()) {
4014 uuid = kext->copyTextUUID();
4015 }
4016 }
4017
4018 return uuid;
4019 }
4020
4021 /*********************************************************************
4022 *********************************************************************/
4023 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4024 OSKext::lookupKextWithUUID(uuid_t wanted)
4025 {
4026 OSSharedPtr<OSKext> foundKext; // returned
4027 uint32_t j, i;
4028 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4029 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4030
4031
4032 IORecursiveLockLock(sKextLock);
4033
4034 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4035 for (i = 0; i < count[j]; i++) {
4036 OSKext * thisKext = NULL;
4037
4038 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4039 if (!thisKext) {
4040 continue;
4041 }
4042
4043 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4044 if (!uuid_data) {
4045 continue;
4046 }
4047
4048 uuid_t uuid;
4049 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4050
4051 if (0 == uuid_compare(wanted, uuid)) {
4052 foundKext.reset(thisKext, OSRetain);
4053 goto finish;
4054 }
4055 }
4056 }
4057 finish:
4058 IORecursiveLockUnlock(sKextLock);
4059
4060 return foundKext;
4061 }
4062
4063
4064
4065
4066 /*********************************************************************
4067 *********************************************************************/
4068 /* static */
4069 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4070 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4071 {
4072 bool result = false;
4073 OSKext * foundKext = NULL; // returned
4074
4075 IORecursiveLockLock(sKextLock);
4076
4077 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4078 if (foundKext && foundKext->isLoaded()) {
4079 result = true;
4080 }
4081
4082 IORecursiveLockUnlock(sKextLock);
4083
4084 return result;
4085 }
4086
4087 /*********************************************************************
4088 * xxx - should spawn a separate thread so a kext can safely have
4089 * xxx - itself unloaded.
4090 *********************************************************************/
4091 /* static */
4092 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4093 OSKext::removeKext(
4094 OSKext * aKext,
4095 #if CONFIG_EMBEDDED
4096 __unused
4097 #endif
4098 bool terminateServicesAndRemovePersonalitiesFlag)
4099 {
4100 #if CONFIG_EMBEDDED
4101 OSKextLog(aKext,
4102 kOSKextLogErrorLevel |
4103 kOSKextLogKextBookkeepingFlag,
4104 "removeKext() called for %s, not supported on embedded",
4105 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4106
4107 return kOSReturnSuccess;
4108 #else /* CONFIG_EMBEDDED */
4109
4110 OSReturn result = kOSKextReturnInUse;
4111 OSKext * checkKext = NULL; // do not release
4112 #if CONFIG_MACF
4113 int macCheckResult = 0;
4114 kauth_cred_t cred = NULL;
4115 #endif
4116
4117 IORecursiveLockLock(sKextLock);
4118
4119 /* If the kext has no identifier, it failed to init
4120 * so isn't in sKextsByID and it isn't loaded.
4121 */
4122 if (!aKext->getIdentifier()) {
4123 result = kOSReturnSuccess;
4124 goto finish;
4125 }
4126
4127 checkKext = OSDynamicCast(OSKext,
4128 sKextsByID->getObject(aKext->getIdentifier()));
4129 if (checkKext != aKext) {
4130 result = kOSKextReturnNotFound;
4131 goto finish;
4132 }
4133
4134 if (aKext->isLoaded()) {
4135 #if CONFIG_MACF
4136 if (current_task() != kernel_task) {
4137 cred = kauth_cred_get_with_ref();
4138 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4139 kauth_cred_unref(&cred);
4140 }
4141
4142 if (macCheckResult != 0) {
4143 result = kOSReturnError;
4144 OSKextLog(aKext,
4145 kOSKextLogErrorLevel |
4146 kOSKextLogKextBookkeepingFlag,
4147 "Failed to remove kext %s (MAC policy error 0x%x).",
4148 aKext->getIdentifierCString(), macCheckResult);
4149 goto finish;
4150 }
4151 #endif
4152
4153 /* make sure there are no resource requests in flight - 17187548 */
4154 if (aKext->countRequestCallbacks()) {
4155 goto finish;
4156 }
4157 if (aKext->flags.unloadUnsupported) {
4158 result = kOSKextReturnInUse;
4159 OSKextLog(aKext,
4160 kOSKextLogErrorLevel |
4161 kOSKextLogKextBookkeepingFlag,
4162 "Can't remove kext %s; unsupported by cache.",
4163 aKext->getIdentifierCString());
4164 goto finish;
4165 }
4166
4167 /* If we are terminating, send the request to the IOCatalogue
4168 * (which will actually call us right back but that's ok we have
4169 * a recursive lock don't you know) but do not ask the IOCatalogue
4170 * to call back with an unload, we'll do that right here.
4171 */
4172 if (terminateServicesAndRemovePersonalitiesFlag) {
4173 result = gIOCatalogue->terminateDriversForModule(
4174 aKext->getIdentifierCString(), /* unload */ false);
4175 if (result != kOSReturnSuccess) {
4176 OSKextLog(aKext,
4177 kOSKextLogErrorLevel |
4178 kOSKextLogKextBookkeepingFlag,
4179 "Can't remove kext %s; services failed to terminate - 0x%x.",
4180 aKext->getIdentifierCString(), result);
4181 goto finish;
4182 }
4183 }
4184
4185 result = aKext->unload();
4186 if (result != kOSReturnSuccess) {
4187 goto finish;
4188 }
4189 }
4190
4191 /* Remove personalities as requested. This is a bit redundant for a loaded
4192 * kext as IOCatalogue::terminateDriversForModule() removes driver
4193 * personalities, but it doesn't restart matching, which we always want
4194 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4195 * that happens.
4196 */
4197 if (terminateServicesAndRemovePersonalitiesFlag) {
4198 aKext->removePersonalitiesFromCatalog();
4199 }
4200
4201 if (aKext->isInFileset()) {
4202 OSKextLog(aKext,
4203 kOSKextLogProgressLevel |
4204 kOSKextLogKextBookkeepingFlag,
4205 "Fileset kext %s unloaded.",
4206 aKext->getIdentifierCString());
4207 } else {
4208 OSKextLog(aKext,
4209 kOSKextLogProgressLevel |
4210 kOSKextLogKextBookkeepingFlag,
4211 "Removing kext %s.",
4212 aKext->getIdentifierCString());
4213
4214 sKextsByID->removeObject(aKext->getIdentifier());
4215 }
4216 result = kOSReturnSuccess;
4217
4218 finish:
4219 IORecursiveLockUnlock(sKextLock);
4220 return result;
4221 #endif /* CONFIG_EMBEDDED */
4222 }
4223
4224 /*********************************************************************
4225 *********************************************************************/
4226 /* static */
4227 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4228 OSKext::removeKextWithIdentifier(
4229 const char * kextIdentifier,
4230 bool terminateServicesAndRemovePersonalitiesFlag)
4231 {
4232 OSReturn result = kOSReturnError;
4233
4234 IORecursiveLockLock(sKextLock);
4235
4236 OSKext * aKext = OSDynamicCast(OSKext,
4237 sKextsByID->getObject(kextIdentifier));
4238 if (!aKext) {
4239 result = kOSKextReturnNotFound;
4240 OSKextLog(/* kext */ NULL,
4241 kOSKextLogErrorLevel |
4242 kOSKextLogKextBookkeepingFlag,
4243 "Can't remove kext %s - not found.",
4244 kextIdentifier);
4245 goto finish;
4246 }
4247
4248 result = OSKext::removeKext(aKext,
4249 terminateServicesAndRemovePersonalitiesFlag);
4250
4251 finish:
4252 IORecursiveLockUnlock(sKextLock);
4253
4254 return result;
4255 }
4256
4257 /*********************************************************************
4258 *********************************************************************/
4259 /* static */
4260 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4261 OSKext::removeKextWithLoadTag(
4262 OSKextLoadTag loadTag,
4263 bool terminateServicesAndRemovePersonalitiesFlag)
4264 {
4265 OSReturn result = kOSReturnError;
4266 OSKext * foundKext = NULL;
4267 uint32_t i, j;
4268 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4269 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4270
4271
4272 IORecursiveLockLock(sKextLock);
4273
4274 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4275 for (i = 0; i < count[j]; i++) {
4276 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4277 if (thisKext->loadTag == loadTag) {
4278 foundKext = thisKext;
4279 break;
4280 }
4281 }
4282 }
4283
4284 if (!foundKext) {
4285 result = kOSKextReturnNotFound;
4286 OSKextLog(/* kext */ NULL,
4287 kOSKextLogErrorLevel |
4288 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4289 "Can't remove kext with load tag %d - not found.",
4290 loadTag);
4291 goto finish;
4292 }
4293
4294 result = OSKext::removeKext(foundKext,
4295 terminateServicesAndRemovePersonalitiesFlag);
4296
4297 finish:
4298 IORecursiveLockUnlock(sKextLock);
4299
4300 return result;
4301 }
4302
4303 /*********************************************************************
4304 *********************************************************************/
4305 OSSharedPtr<OSDictionary>
copyKexts(void)4306 OSKext::copyKexts(void)
4307 {
4308 OSSharedPtr<OSDictionary> result;
4309
4310 IORecursiveLockLock(sKextLock);
4311 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4312 IORecursiveLockUnlock(sKextLock);
4313
4314 return result;
4315 }
4316
4317 /*********************************************************************
4318 *********************************************************************/
4319 #define BOOTER_KEXT_PREFIX "Driver-"
4320
4321 typedef struct _DeviceTreeBuffer {
4322 uint32_t paddr;
4323 uint32_t length;
4324 } _DeviceTreeBuffer;
4325
4326 /*********************************************************************
4327 * Create a dictionary of excluded kexts from the given booter data.
4328 *********************************************************************/
4329 /* static */
4330 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4331 OSKext::createExcludeListFromBooterData(
4332 OSDictionary * theDictionary,
4333 OSCollectionIterator * theIterator )
4334 {
4335 OSString * deviceTreeName = NULL; // do not release
4336 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4337 char * booterDataPtr = NULL; // do not release
4338 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4339 char * infoDictAddr = NULL; // do not release
4340 OSSharedPtr<OSObject> parsedXML;
4341 OSDictionary * theInfoDict = NULL; // do not release
4342
4343 theIterator->reset();
4344
4345 /* look for AppleKextExcludeList.kext */
4346 while ((deviceTreeName =
4347 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4348 const char * devTreeNameCString;
4349 OSData * deviceTreeEntry; // do not release
4350 OSString * myBundleID; // do not release
4351
4352 deviceTreeEntry =
4353 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4354 if (!deviceTreeEntry) {
4355 continue;
4356 }
4357
4358 /* Make sure it is a kext */
4359 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4360 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4361 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4362 OSKextLog(NULL,
4363 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4364 "\"%s\" not a kext",
4365 devTreeNameCString);
4366 continue;
4367 }
4368
4369 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4370 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4371 if (!deviceTreeBuffer) {
4372 continue;
4373 }
4374
4375 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4376 if (!booterDataPtr) {
4377 continue;
4378 }
4379
4380 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4381 if (!kextFileInfo->infoDictPhysAddr ||
4382 !kextFileInfo->infoDictLength) {
4383 continue;
4384 }
4385
4386 infoDictAddr = (char *)
4387 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4388 if (!infoDictAddr) {
4389 continue;
4390 }
4391
4392 parsedXML = OSUnserializeXML(infoDictAddr);
4393 if (!parsedXML) {
4394 continue;
4395 }
4396
4397 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4398 if (!theInfoDict) {
4399 continue;
4400 }
4401
4402 myBundleID =
4403 OSDynamicCast(OSString,
4404 theInfoDict->getObject(kCFBundleIdentifierKey));
4405 if (myBundleID &&
4406 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4407 boolean_t updated = updateExcludeList(theInfoDict);
4408 if (!updated) {
4409 /* 25322874 */
4410 panic("Missing OSKextExcludeList dictionary");
4411 }
4412 break;
4413 }
4414 } // while ( (deviceTreeName = ...) )
4415
4416 return;
4417 }
4418
4419 /*********************************************************************
4420 * Create a dictionary of excluded kexts from the given prelink
4421 * info (kernelcache).
4422 *********************************************************************/
4423 /* static */
4424 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4425 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4426 {
4427 OSDictionary * myInfoDict = NULL; // do not release
4428 OSString * myBundleID; // do not release
4429 u_int i;
4430
4431 /* Find the Apple Kext Exclude List. */
4432 for (i = 0; i < theInfoArray->getCount(); i++) {
4433 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4434 if (!myInfoDict) {
4435 continue;
4436 }
4437 myBundleID =
4438 OSDynamicCast(OSString,
4439 myInfoDict->getObject(kCFBundleIdentifierKey));
4440 if (myBundleID &&
4441 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4442 boolean_t updated = updateExcludeList(myInfoDict);
4443 if (!updated) {
4444 /* 25322874 */
4445 panic("Missing OSKextExcludeList dictionary");
4446 }
4447 break;
4448 }
4449 } // for (i = 0; i < theInfoArray->getCount()...
4450
4451 return;
4452 }
4453
4454 /* static */
4455 boolean_t
updateExcludeList(OSDictionary * infoDict)4456 OSKext::updateExcludeList(OSDictionary *infoDict)
4457 {
4458 OSDictionary *myTempDict = NULL; // do not free
4459 OSString *myTempString = NULL; // do not free
4460 OSKextVersion newVersion = 0;
4461 boolean_t updated = false;
4462
4463 if (!infoDict) {
4464 return false;
4465 }
4466
4467 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4468 if (!myTempDict) {
4469 return false;
4470 }
4471
4472 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4473 if (!myTempString) {
4474 return false;
4475 }
4476
4477 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4478 if (newVersion == 0) {
4479 return false;
4480 }
4481
4482 IORecursiveLockLock(sKextLock);
4483
4484 if (newVersion > sExcludeListVersion) {
4485 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4486 sExcludeListVersion = newVersion;
4487 updated = true;
4488 }
4489
4490 IORecursiveLockUnlock(sKextLock);
4491 return updated;
4492 }
4493
4494 #if PRAGMA_MARK
4495 #pragma mark Accessors
4496 #endif
4497 /*********************************************************************
4498 *********************************************************************/
4499 const OSSymbol *
getIdentifier(void)4500 OSKext::getIdentifier(void)
4501 {
4502 return bundleID.get();
4503 }
4504
4505 /*********************************************************************
4506 * A kext must have a bundle identifier to even survive initialization;
4507 * this is guaranteed to exist past then.
4508 *********************************************************************/
4509 const char *
getIdentifierCString(void)4510 OSKext::getIdentifierCString(void)
4511 {
4512 return bundleID->getCStringNoCopy();
4513 }
4514
4515 /*********************************************************************
4516 *********************************************************************/
4517 OSKextVersion
getVersion(void)4518 OSKext::getVersion(void)
4519 {
4520 return version;
4521 }
4522
4523 /*********************************************************************
4524 *********************************************************************/
4525 OSKextVersion
getCompatibleVersion(void)4526 OSKext::getCompatibleVersion(void)
4527 {
4528 return compatibleVersion;
4529 }
4530
4531 /*********************************************************************
4532 *********************************************************************/
4533 bool
isLibrary(void)4534 OSKext::isLibrary(void)
4535 {
4536 return getCompatibleVersion() > 0;
4537 }
4538
4539 /*********************************************************************
4540 *********************************************************************/
4541 bool
isCompatibleWithVersion(OSKextVersion aVersion)4542 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4543 {
4544 if ((compatibleVersion > -1 && version > -1) &&
4545 (compatibleVersion <= version && aVersion <= version)) {
4546 return true;
4547 }
4548 return false;
4549 }
4550
4551 /*********************************************************************
4552 *********************************************************************/
4553 bool
declaresExecutable(void)4554 OSKext::declaresExecutable(void)
4555 {
4556 if (isDriverKit()) {
4557 return false;
4558 }
4559 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4560 }
4561
4562 /*********************************************************************
4563 *********************************************************************/
4564 OSData *
getExecutable(void)4565 OSKext::getExecutable(void)
4566 {
4567 OSData * result = NULL;
4568 OSSharedPtr<OSData> extractedExecutable;
4569
4570 if (flags.builtin) {
4571 return sKernelKext->linkedExecutable.get();
4572 }
4573
4574 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4575 if (result) {
4576 return result;
4577 }
4578
4579 #if CONFIG_KXLD
4580 OSData * mkextExecutableRef = NULL; // do not release
4581 mkextExecutableRef = OSDynamicCast(OSData,
4582 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4583
4584 if (mkextExecutableRef) {
4585 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4586 mkextExecutableRef->getBytesNoCopy();
4587 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4588 if (mkextVersion == MKEXT_VERS_2) {
4589 mkext2_file_entry * fileinfo =
4590 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4591 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4592 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4593 extractedExecutable = extractMkext2FileData(
4594 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4595 compressedSize, fullSize);
4596 } else {
4597 OSKextLog(this, kOSKextLogErrorLevel |
4598 kOSKextLogArchiveFlag,
4599 "Kext %s - unknown mkext version 0x%x for executable.",
4600 getIdentifierCString(), mkextVersion);
4601 }
4602
4603 /* Regardless of success, remove the mkext executable,
4604 * and drop one reference on the mkext. (setExecutable() does not
4605 * replace, it removes, or panics if asked to replace.)
4606 */
4607 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4608 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4609
4610 if (extractedExecutable && extractedExecutable->getLength()) {
4611 if (!setExecutable(extractedExecutable.get())) {
4612 goto finish;
4613 }
4614 result = extractedExecutable.get();
4615 } else {
4616 goto finish;
4617 }
4618 }
4619
4620 finish:
4621 #endif // CONFIG_KXLD
4622 return result;
4623 }
4624
4625 /*********************************************************************
4626 *********************************************************************/
4627 bool
isInterface(void)4628 OSKext::isInterface(void)
4629 {
4630 return flags.interface;
4631 }
4632
4633 /*********************************************************************
4634 *********************************************************************/
4635 bool
isKernel(void)4636 OSKext::isKernel(void)
4637 {
4638 return this == sKernelKext;
4639 }
4640
4641 /*********************************************************************
4642 *********************************************************************/
4643 bool
isKernelComponent(void)4644 OSKext::isKernelComponent(void)
4645 {
4646 return flags.kernelComponent ? true : false;
4647 }
4648
4649 /*********************************************************************
4650 *********************************************************************/
4651 bool
isExecutable(void)4652 OSKext::isExecutable(void)
4653 {
4654 return !isKernel() && !isInterface() && declaresExecutable();
4655 }
4656
4657 /*********************************************************************
4658 * We might want to check this recursively for all dependencies,
4659 * since a subtree of dependencies could get loaded before we hit
4660 * a dependency that isn't safe-boot-loadable.
4661 *
4662 * xxx - Might want to return false if OSBundleEnableKextLogging or
4663 * OSBundleDebugLevel
4664 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4665 * the point except it's usually development drivers, which might
4666 * cause panics on startup, that have those properties). Heh; could
4667 * use a "kx" boot-arg!
4668 *********************************************************************/
4669 bool
isLoadableInSafeBoot(void)4670 OSKext::isLoadableInSafeBoot(void)
4671 {
4672 bool result = false;
4673 OSString * required = NULL; // do not release
4674
4675 if (isKernel()) {
4676 result = true;
4677 goto finish;
4678 }
4679
4680 if (isDriverKit()) {
4681 result = true;
4682 goto finish;
4683 }
4684
4685 required = OSDynamicCast(OSString,
4686 getPropertyForHostArch(kOSBundleRequiredKey));
4687 if (!required) {
4688 goto finish;
4689 }
4690 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4691 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4692 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4693 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4694 required->isEqualTo(kOSBundleRequiredConsole)) {
4695 result = true;
4696 }
4697
4698 finish:
4699 return result;
4700 }
4701
4702 /*********************************************************************
4703 *********************************************************************/
4704 bool
isPrelinked(void)4705 OSKext::isPrelinked(void)
4706 {
4707 return flags.prelinked ? true : false;
4708 }
4709
4710 /*********************************************************************
4711 *********************************************************************/
4712 bool
isLoaded(void)4713 OSKext::isLoaded(void)
4714 {
4715 return flags.loaded ? true : false;
4716 }
4717
4718 /*********************************************************************
4719 *********************************************************************/
4720 bool
isStarted(void)4721 OSKext::isStarted(void)
4722 {
4723 return flags.started ? true : false;
4724 }
4725
4726 /*********************************************************************
4727 *********************************************************************/
4728 bool
isCPPInitialized(void)4729 OSKext::isCPPInitialized(void)
4730 {
4731 return flags.CPPInitialized;
4732 }
4733
4734 /*********************************************************************
4735 *********************************************************************/
4736 void
setCPPInitialized(bool initialized)4737 OSKext::setCPPInitialized(bool initialized)
4738 {
4739 flags.CPPInitialized = initialized;
4740 }
4741
4742 /*********************************************************************
4743 *********************************************************************/
4744 uint32_t
getLoadTag(void)4745 OSKext::getLoadTag(void)
4746 {
4747 return loadTag;
4748 }
4749
4750 /*********************************************************************
4751 *********************************************************************/
4752 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)4753 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4754 {
4755 if (linkedExecutable) {
4756 *loadSize = linkedExecutable->getLength();
4757
4758 /* If we have a kmod_info struct, calculated the wired size
4759 * from that. Otherwise it's the full load size.
4760 */
4761 if (kmod_info) {
4762 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
4763 } else {
4764 *wiredSize = *loadSize;
4765 }
4766 } else {
4767 *wiredSize = 0;
4768 *loadSize = 0;
4769 }
4770 }
4771
4772 /*********************************************************************
4773 *********************************************************************/
4774 OSSharedPtr<OSData>
copyUUID(void)4775 OSKext::copyUUID(void)
4776 {
4777 OSSharedPtr<OSData> result;
4778 OSData * theExecutable = NULL; // do not release
4779 const kernel_mach_header_t * header;
4780
4781 /* An interface kext doesn't have a linked executable with an LC_UUID,
4782 * we create one when it's linked.
4783 */
4784 if (interfaceUUID) {
4785 result = interfaceUUID;
4786 goto finish;
4787 }
4788
4789 if (flags.builtin || isInterface()) {
4790 return sKernelKext->copyUUID();
4791 }
4792
4793 if (isDriverKit() && infoDict) {
4794 return driverKitUUID;
4795 }
4796
4797 /* For real kexts, try to get the UUID from the linked executable,
4798 * or if is hasn't been linked yet, the unrelocated executable.
4799 */
4800 theExecutable = linkedExecutable.get();
4801 if (!theExecutable) {
4802 theExecutable = getExecutable();
4803 }
4804
4805 if (!theExecutable) {
4806 goto finish;
4807 }
4808
4809 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4810 result = copyMachoUUID(header);
4811
4812 finish:
4813 return result;
4814 }
4815
4816 /*********************************************************************
4817 *********************************************************************/
4818 OSSharedPtr<OSData>
copyTextUUID(void)4819 OSKext::copyTextUUID(void)
4820 {
4821 if (flags.builtin) {
4822 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4823 }
4824 return copyUUID();
4825 }
4826
4827 /*********************************************************************
4828 *********************************************************************/
4829 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)4830 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4831 {
4832 OSSharedPtr<OSData> result;
4833 const struct load_command * load_cmd = NULL;
4834 const struct uuid_command * uuid_cmd = NULL;
4835 uint32_t i;
4836
4837 load_cmd = (const struct load_command *)&header[1];
4838
4839 if (header->magic != MH_MAGIC_KERNEL) {
4840 OSKextLog(NULL,
4841 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4842 "%s: bad header %p",
4843 __func__,
4844 header);
4845 goto finish;
4846 }
4847
4848 for (i = 0; i < header->ncmds; i++) {
4849 if (load_cmd->cmd == LC_UUID) {
4850 uuid_cmd = (struct uuid_command *)load_cmd;
4851 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4852 goto finish;
4853 }
4854 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4855 }
4856
4857 finish:
4858 return result;
4859 }
4860
4861 void
setDriverKitUUID(OSData * uuid)4862 OSKext::setDriverKitUUID(OSData *uuid)
4863 {
4864 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4865 OSSafeReleaseNULL(uuid);
4866 }
4867 }
4868
4869 /*********************************************************************
4870 *********************************************************************/
4871 #if defined (__arm__)
4872 #include <arm/arch.h>
4873 #endif
4874
4875 #if defined (__x86_64__)
4876 #define ARCHNAME "x86_64"
4877 #elif defined (__arm64__)
4878 #define ARCHNAME "arm64"
4879 #elif defined (__arm__)
4880
4881 #if defined (__ARM_ARCH_7S__)
4882 #define ARCHNAME "armv7s"
4883 #elif defined (__ARM_ARCH_7F__)
4884 #define ARCHNAME "armv7f"
4885 #elif defined (__ARM_ARCH_7K__)
4886 #define ARCHNAME "armv7k"
4887 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4888 #define ARCHNAME "armv7"
4889 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4890 #define ARCHNAME "armv6"
4891 #endif
4892
4893 #elif defined (__arm64__)
4894 #define ARCHNAME "arm64"
4895 #else
4896 #error architecture not supported
4897 #endif
4898
4899 #define ARCH_SEPARATOR_CHAR '_'
4900
4901 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)4902 makeHostArchKey(const char * key, size_t * keySizeOut)
4903 {
4904 char * result = NULL;
4905 size_t keyLength = strlen(key);
4906 size_t keySize;
4907
4908 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4909 */
4910 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4911 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4912
4913 if (!result) {
4914 goto finish;
4915 }
4916 strlcpy(result, key, keySize);
4917 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4918 result[keyLength] = '\0';
4919 strlcat(result, ARCHNAME, keySize);
4920 *keySizeOut = keySize;
4921
4922 finish:
4923 return result;
4924 }
4925
4926 /*********************************************************************
4927 *********************************************************************/
4928 OSObject *
getPropertyForHostArch(const char * key)4929 OSKext::getPropertyForHostArch(const char * key)
4930 {
4931 OSObject * result = NULL;// do not release
4932 size_t hostArchKeySize = 0;
4933 char * hostArchKey = NULL;// must kfree
4934
4935 if (!key || !infoDict) {
4936 goto finish;
4937 }
4938
4939 /* Some properties are not allowed to be arch-variant:
4940 * - Any CFBundle... property.
4941 * - OSBundleIsInterface.
4942 * - OSKernelResource.
4943 */
4944 if (STRING_HAS_PREFIX(key, "OS") ||
4945 STRING_HAS_PREFIX(key, "IO")) {
4946 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4947 if (!hostArchKey) {
4948 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4949 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4950 "Allocation failure.");
4951 goto finish;
4952 }
4953 result = infoDict->getObject(hostArchKey);
4954 }
4955
4956 if (!result) {
4957 result = infoDict->getObject(key);
4958 }
4959
4960 finish:
4961 if (hostArchKey) {
4962 kfree_data(hostArchKey, hostArchKeySize);
4963 }
4964 return result;
4965 }
4966
4967 #if PRAGMA_MARK
4968 #pragma mark Load/Start/Stop/Unload
4969 #endif
4970
4971 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4972
4973 /*********************************************************************
4974 * sExcludeListByID is a dictionary with keys / values of:
4975 * key = bundleID string of kext we will not allow to load
4976 * value = version string(s) of the kext that is to be denied loading.
4977 * The version strings can be comma delimited. For example if kext
4978 * com.foocompany.fookext has two versions that we want to deny
4979 * loading then the version strings might look like:
4980 * 1.0.0, 1.0.1
4981 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4982 * not load the kext.
4983 *
4984 * Value may also be in the form of "LE 2.0.0" (version numbers
4985 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4986 * number less than 2.0.0 will not load)
4987 *
4988 * NOTE - we cannot use the characters "<=" or "<" because we have code
4989 * that serializes plists and treats '<' as a special character.
4990 *********************************************************************/
4991 bool
isInExcludeList(void)4992 OSKext::isInExcludeList(void)
4993 {
4994 OSString * versionString = NULL; // do not release
4995 char * versionCString = NULL; // do not free
4996 size_t i;
4997 boolean_t wantLessThan = false;
4998 boolean_t wantLessThanEqualTo = false;
4999 boolean_t isInExcludeList = true;
5000 char myBuffer[32];
5001
5002 IORecursiveLockLock(sKextLock);
5003
5004 if (!sExcludeListByID) {
5005 isInExcludeList = false;
5006 } else {
5007 /* look up by bundleID in our exclude list and if found get version
5008 * string (or strings) that we will not allow to load
5009 */
5010 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5011 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5012 isInExcludeList = false;
5013 }
5014 }
5015
5016 IORecursiveLockUnlock(sKextLock);
5017
5018 if (!isInExcludeList) {
5019 return false;
5020 }
5021
5022 /* parse version strings */
5023 versionCString = (char *) versionString->getCStringNoCopy();
5024
5025 /* look for "LT" or "LE" form of version string, must be in first two
5026 * positions.
5027 */
5028 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5029 wantLessThan = true;
5030 versionCString += 2;
5031 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5032 wantLessThanEqualTo = true;
5033 versionCString += 2;
5034 }
5035
5036 for (i = 0; *versionCString != 0x00; versionCString++) {
5037 /* skip whitespace */
5038 if (isWhiteSpace(*versionCString)) {
5039 continue;
5040 }
5041
5042 /* peek ahead for version string separator or null terminator */
5043 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5044 /* OK, we have a version string */
5045 myBuffer[i++] = *versionCString;
5046 myBuffer[i] = 0x00;
5047
5048 OSKextVersion excludeVers;
5049 excludeVers = OSKextParseVersionString(myBuffer);
5050
5051 if (wantLessThanEqualTo) {
5052 if (version <= excludeVers) {
5053 return true;
5054 }
5055 } else if (wantLessThan) {
5056 if (version < excludeVers) {
5057 return true;
5058 }
5059 } else if (version == excludeVers) {
5060 return true;
5061 }
5062
5063 /* reset for the next (if any) version string */
5064 i = 0;
5065 wantLessThan = false;
5066 wantLessThanEqualTo = false;
5067 } else {
5068 /* save valid version character */
5069 myBuffer[i++] = *versionCString;
5070
5071 /* make sure bogus version string doesn't overrun local buffer */
5072 if (i >= sizeof(myBuffer)) {
5073 break;
5074 }
5075 }
5076 }
5077
5078 return false;
5079 }
5080
5081 /*********************************************************************
5082 * sNonLoadableKextsByID is a dictionary with keys / values of:
5083 * key = bundleID string of kext we will not allow to load
5084 * value = boolean (true == loadable, false == not loadable)
5085 *
5086 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5087 * i.e., the value for the kext's bundleID will be false. All kexts in
5088 * the primary and system KCs will always be marked as "loadable."
5089 *
5090 * This list ultimately comes from kexts which have been uninstalled
5091 * in user space by deleting the kext from disk, but which have not
5092 * yet been removed from the AuxKC. Because the user could choose to
5093 * re-install the exact same version of the kext, we need to keep
5094 * a dictionary of boolean values so that user space only needs to
5095 * keep a simple list of "uninstalled" or "missing" bundles. When
5096 * a bundle is re-installed, the iokit daemon can use the
5097 * AucKCBundleAvailable predicate to set the individual kext's
5098 * availability to true.
5099 *********************************************************************/
5100 bool
isLoadable(void)5101 OSKext::isLoadable(void)
5102 {
5103 bool isLoadable = true;
5104
5105 if (kc_type != KCKindAuxiliary) {
5106 /* this filtering only applies to kexts in the auxkc */
5107 return true;
5108 }
5109
5110 IORecursiveLockLock(sKextLock);
5111
5112 if (sNonLoadableKextsByID) {
5113 /* look up by bundleID in our exclude list and if found get version
5114 * string (or strings) that we will not allow to load
5115 */
5116 OSBoolean *loadableVal;
5117 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5118 if (loadableVal && !loadableVal->getValue()) {
5119 isLoadable = false;
5120 }
5121 }
5122 IORecursiveLockUnlock(sKextLock);
5123
5124 return isLoadable;
5125 }
5126
5127 /*********************************************************************
5128 *********************************************************************/
5129 /* static */
5130 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5131 OSKext::loadKextWithIdentifier(
5132 const char * kextIdentifierCString,
5133 Boolean allowDeferFlag,
5134 Boolean delayAutounloadFlag,
5135 OSKextExcludeLevel startOpt,
5136 OSKextExcludeLevel startMatchingOpt,
5137 OSArray * personalityNames)
5138 {
5139 OSReturn result = kOSReturnError;
5140 OSSharedPtr<OSString> kextIdentifier;
5141
5142 kextIdentifier = OSString::withCString(kextIdentifierCString);
5143 if (!kextIdentifier) {
5144 result = kOSKextReturnNoMemory;
5145 goto finish;
5146 }
5147 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5148 NULL /* kextRef */,
5149 allowDeferFlag, delayAutounloadFlag,
5150 startOpt, startMatchingOpt, personalityNames);
5151
5152 finish:
5153 return result;
5154 }
5155
5156 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5157 OSKext::loadKextWithIdentifier(
5158 OSString * kextIdentifier,
5159 OSSharedPtr<OSObject> &kextRef,
5160 Boolean allowDeferFlag,
5161 Boolean delayAutounloadFlag,
5162 OSKextExcludeLevel startOpt,
5163 OSKextExcludeLevel startMatchingOpt,
5164 OSArray * personalityNames)
5165 {
5166 OSObject * kextRefRaw = NULL;
5167 OSReturn result;
5168
5169 result = loadKextWithIdentifier(kextIdentifier,
5170 &kextRefRaw,
5171 allowDeferFlag,
5172 delayAutounloadFlag,
5173 startOpt,
5174 startMatchingOpt,
5175 personalityNames);
5176 if ((kOSReturnSuccess == result) && kextRefRaw) {
5177 kextRef.reset(kextRefRaw, OSNoRetain);
5178 }
5179 return result;
5180 }
5181
5182 /*********************************************************************
5183 *********************************************************************/
5184 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5185 OSKext::loadKextWithIdentifier(
5186 OSString * kextIdentifier,
5187 OSObject ** kextRef,
5188 Boolean allowDeferFlag,
5189 Boolean delayAutounloadFlag,
5190 OSKextExcludeLevel startOpt,
5191 OSKextExcludeLevel startMatchingOpt,
5192 OSArray * personalityNames)
5193 {
5194 OSReturn result = kOSReturnError;
5195 OSReturn pingResult = kOSReturnError;
5196 OSKext * theKext = NULL; // do not release
5197 OSSharedPtr<OSDictionary> loadRequest;
5198 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5199
5200 if (kextRef) {
5201 *kextRef = NULL;
5202 }
5203
5204 IORecursiveLockLock(sKextLock);
5205
5206 if (!kextIdentifier) {
5207 result = kOSKextReturnInvalidArgument;
5208 goto finish;
5209 }
5210
5211 OSKext::recordIdentifierRequest(kextIdentifier);
5212
5213 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5214 if (!theKext) {
5215 if (!allowDeferFlag) {
5216 OSKextLog(/* kext */ NULL,
5217 kOSKextLogErrorLevel |
5218 kOSKextLogLoadFlag,
5219 "Can't load kext %s - not found.",
5220 kextIdentifier->getCStringNoCopy());
5221 goto finish;
5222 }
5223
5224 if (!sKernelRequestsEnabled) {
5225 OSKextLog(theKext,
5226 kOSKextLogErrorLevel |
5227 kOSKextLogLoadFlag,
5228 "Can't load kext %s - requests to user space are disabled.",
5229 kextIdentifier->getCStringNoCopy());
5230 result = kOSKextReturnDisabled;
5231 goto finish;
5232 }
5233
5234 /* Create a new request unless one is already sitting
5235 * in sKernelRequests for this bundle identifier
5236 */
5237 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5238 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5239 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5240 loadRequest);
5241 if (result != kOSReturnSuccess) {
5242 goto finish;
5243 }
5244 if (!_OSKextSetRequestArgument(loadRequest.get(),
5245 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5246 result = kOSKextReturnNoMemory;
5247 goto finish;
5248 }
5249 if (!sKernelRequests->setObject(loadRequest.get())) {
5250 result = kOSKextReturnNoMemory;
5251 goto finish;
5252 }
5253
5254 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5255 result = kOSKextReturnNoMemory;
5256 goto finish;
5257 }
5258
5259 OSKextLog(theKext,
5260 kOSKextLogDebugLevel |
5261 kOSKextLogLoadFlag,
5262 "Kext %s not found; queued load request to user space.",
5263 kextIdentifier->getCStringNoCopy());
5264 }
5265
5266 pingResult = OSKext::pingIOKitDaemon();
5267 if (pingResult == kOSKextReturnDisabled) {
5268 OSKextLog(/* kext */ NULL,
5269 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5270 kOSKextLogLoadFlag,
5271 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5272 kextIdentifier->getCStringNoCopy());
5273 }
5274
5275 result = kOSKextReturnDeferred;
5276 goto finish;
5277 }
5278
5279 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5280
5281 if (result != kOSReturnSuccess) {
5282 OSKextLog(theKext,
5283 kOSKextLogErrorLevel |
5284 kOSKextLogLoadFlag,
5285 "Failed to load kext %s (error 0x%x).",
5286 kextIdentifier->getCStringNoCopy(), (int)result);
5287
5288 if (theKext->kc_type == KCKindUnknown) {
5289 OSKext::removeKext(theKext,
5290 /* terminateService/removePersonalities */ true);
5291 }
5292 goto finish;
5293 }
5294
5295 if (delayAutounloadFlag) {
5296 OSKextLog(theKext,
5297 kOSKextLogProgressLevel |
5298 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5299 "Setting delayed autounload for %s.",
5300 kextIdentifier->getCStringNoCopy());
5301 theKext->flags.delayAutounload = 1;
5302 }
5303
5304 finish:
5305 if ((kOSReturnSuccess == result) && kextRef) {
5306 *kextRef = theKext;
5307 theKext->matchingRefCount++;
5308 theKext->retain();
5309 }
5310
5311 IORecursiveLockUnlock(sKextLock);
5312
5313 return result;
5314 }
5315
5316 /*********************************************************************
5317 *********************************************************************/
5318 /* static */
5319 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)5320 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5321 {
5322 OSReturn result = kOSReturnError;
5323
5324 OSBoolean *delayAutounloadBool = NULL; // do not release
5325 OSNumber *startKextExcludeNum = NULL; // do not release
5326 OSNumber *startMatchingExcludeNum = NULL; // do not release
5327 OSArray *personalityNames = NULL; // do not release
5328
5329 /*
5330 * Default values for these options:
5331 * regular autounload behavior
5332 * start the kext
5333 * send all personalities to the catalog
5334 */
5335 Boolean delayAutounload = false;
5336 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5337 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5338
5339 IORecursiveLockLock(sKextLock);
5340
5341 OSKextLog(/* kext */ NULL,
5342 kOSKextLogDebugLevel |
5343 kOSKextLogIPCFlag,
5344 "Received kext KC load request from user space.");
5345
5346 /* Regardless of processing, the fact that we have gotten here means some
5347 * user-space program is up and talking to us, so we'll switch our kext
5348 * registration to reflect that.
5349 */
5350 if (!sUserLoadsActive) {
5351 OSKextLog(/* kext */ NULL,
5352 kOSKextLogProgressLevel |
5353 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5354 "Switching to late startup (user-space) kext loading policy.");
5355 sUserLoadsActive = true;
5356 }
5357
5358 delayAutounloadBool = OSDynamicCast(OSBoolean,
5359 _OSKextGetRequestArgument(requestDict,
5360 kKextRequestArgumentDelayAutounloadKey));
5361 startKextExcludeNum = OSDynamicCast(OSNumber,
5362 _OSKextGetRequestArgument(requestDict,
5363 kKextRequestArgumentStartExcludeKey));
5364 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5365 _OSKextGetRequestArgument(requestDict,
5366 kKextRequestArgumentStartMatchingExcludeKey));
5367 personalityNames = OSDynamicCast(OSArray,
5368 _OSKextGetRequestArgument(requestDict,
5369 kKextRequestArgumentPersonalityNamesKey));
5370
5371 if (delayAutounloadBool) {
5372 delayAutounload = delayAutounloadBool->getValue();
5373 }
5374 if (startKextExcludeNum) {
5375 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5376 }
5377 if (startMatchingExcludeNum) {
5378 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5379 }
5380
5381 OSKextLog(/* kext */ NULL,
5382 kOSKextLogProgressLevel |
5383 kOSKextLogIPCFlag,
5384 "Received request from user space to load KC kext %s.",
5385 theKext->getIdentifierCString());
5386
5387 /* this could be in the Auxiliary KC, so record the load request */
5388 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5389
5390 /*
5391 * Load the kext
5392 */
5393 result = theKext->load(startKextExcludeLevel,
5394 startMatchingExcludeLevel, personalityNames);
5395
5396 if (result != kOSReturnSuccess) {
5397 OSKextLog(theKext,
5398 kOSKextLogErrorLevel |
5399 kOSKextLogLoadFlag,
5400 "Failed to load kext %s (error 0x%x).",
5401 theKext->getIdentifierCString(), (int)result);
5402
5403 OSKext::removeKext(theKext,
5404 /* terminateService/removePersonalities */ true);
5405 goto finish;
5406 } else {
5407 OSKextLog(theKext,
5408 kOSKextLogProgressLevel |
5409 kOSKextLogLoadFlag,
5410 "Kext %s Loaded successfully from %s KC",
5411 theKext->getIdentifierCString(), theKext->getKCTypeString());
5412 }
5413
5414 if (delayAutounload) {
5415 OSKextLog(theKext,
5416 kOSKextLogProgressLevel |
5417 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5418 "Setting delayed autounload for %s.",
5419 theKext->getIdentifierCString());
5420 theKext->flags.delayAutounload = 1;
5421 }
5422
5423 finish:
5424 IORecursiveLockUnlock(sKextLock);
5425
5426 return result;
5427 }
5428
5429 /*********************************************************************
5430 *********************************************************************/
5431 /* static */
5432 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)5433 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5434 {
5435 OSReturn result = kOSReturnError;
5436 OSDictionary *anInfoDict = NULL; // do not release
5437
5438 anInfoDict = OSDynamicCast(OSDictionary,
5439 _OSKextGetRequestArgument(requestDict,
5440 kKextRequestArgumentCodelessInfoKey));
5441 if (anInfoDict == NULL) {
5442 OSKextLog(/* kext */ NULL,
5443 kOSKextLogErrorLevel |
5444 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5445 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5446 kextIdentifier->getCStringNoCopy());
5447 return kOSKextReturnInvalidArgument;
5448 }
5449
5450 IORecursiveLockLock(sKextLock);
5451
5452 OSKextLog(/* kext */ NULL,
5453 kOSKextLogProgressLevel |
5454 kOSKextLogIPCFlag,
5455 "Received request from user space to load codeless kext %s.",
5456 kextIdentifier->getCStringNoCopy());
5457
5458 {
5459 // instantiate a new kext, and don't hold a reference
5460 // (the kext subsystem will hold one implicitly)
5461 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5462 if (!newKext) {
5463 OSKextLog(/* kext */ NULL,
5464 kOSKextLogErrorLevel |
5465 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5466 "Could not instantiate codeless kext.");
5467 result = kOSKextReturnNotLoadable;
5468 goto finish;
5469 }
5470 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5471 OSKextLog(/* kext */ NULL,
5472 kOSKextLogErrorLevel |
5473 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5474 "Codeless kext identifiers don't match '%s' != '%s'",
5475 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5476
5477 OSKext::removeKext(newKext.get(), false);
5478 result = kOSKextReturnInvalidArgument;
5479 goto finish;
5480 }
5481
5482 /* Record the request for the codeless kext */
5483 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5484
5485 result = kOSReturnSuccess;
5486 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5487 result = newKext->sendPersonalitiesToCatalog(true, NULL);
5488 }
5489
5490 finish:
5491 IORecursiveLockUnlock(sKextLock);
5492
5493 return result;
5494 }
5495
5496 /*********************************************************************
5497 *********************************************************************/
5498 /* static */
5499 void
dropMatchingReferences(OSSet * kexts)5500 OSKext::dropMatchingReferences(
5501 OSSet * kexts)
5502 {
5503 IORecursiveLockLock(sKextLock);
5504 kexts->iterateObjects(^bool (OSObject * obj) {
5505 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5506 if (!thisKext) {
5507 return false;
5508 }
5509 thisKext->matchingRefCount--;
5510 return false;
5511 });
5512 IORecursiveLockUnlock(sKextLock);
5513 }
5514
5515 /*********************************************************************
5516 *********************************************************************/
5517 /* static */
5518 void
recordIdentifierRequest(OSString * kextIdentifier)5519 OSKext::recordIdentifierRequest(
5520 OSString * kextIdentifier)
5521 {
5522 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5523 bool fail = false;
5524
5525 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5526 goto finish;
5527 }
5528
5529 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5530 if (!kextIdentifierSymbol) {
5531 // xxx - this is really a basic alloc failure
5532 fail = true;
5533 goto finish;
5534 }
5535
5536 IORecursiveLockLock(sKextLock);
5537 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5538 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5539 fail = true;
5540 } else {
5541 // xxx - need to find a way to associate this whole func w/the kext
5542 OSKextLog(/* kext */ NULL,
5543 // xxx - check level
5544 kOSKextLogStepLevel |
5545 kOSKextLogArchiveFlag,
5546 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5547 kextIdentifier->getCStringNoCopy());
5548 }
5549 }
5550 IORecursiveLockUnlock(sKextLock);
5551
5552 finish:
5553
5554 if (fail) {
5555 OSKextLog(/* kext */ NULL,
5556 kOSKextLogErrorLevel |
5557 kOSKextLogArchiveFlag,
5558 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5559 kextIdentifier->getCStringNoCopy());
5560 }
5561 return;
5562 }
5563
5564 /*********************************************************************
5565 *********************************************************************/
5566 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)5567 OSKext::load(
5568 OSKextExcludeLevel startOpt,
5569 OSKextExcludeLevel startMatchingOpt,
5570 OSArray * personalityNames)
5571 {
5572 OSReturn result = kOSReturnError;
5573 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5574 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5575 unsigned int i, count;
5576 Boolean alreadyLoaded = false;
5577 OSKext * lastLoadedKext = NULL; // do not release
5578
5579 if (isInExcludeList()) {
5580 OSKextLog(this,
5581 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5582 kOSKextLogLoadFlag,
5583 "Kext %s is in exclude list, not loadable",
5584 getIdentifierCString());
5585
5586 result = kOSKextReturnNotLoadable;
5587 goto finish;
5588 }
5589 if (!isLoadable()) {
5590 OSKextLog(this,
5591 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5592 kOSKextLogLoadFlag,
5593 "Kext %s is not loadable",
5594 getIdentifierCString());
5595
5596 result = kOSKextReturnNotLoadable;
5597 goto finish;
5598 }
5599
5600 if (isLoaded()) {
5601 alreadyLoaded = true;
5602 result = kOSReturnSuccess;
5603
5604 OSKextLog(this,
5605 kOSKextLogDebugLevel |
5606 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5607 "Kext %s is already loaded.",
5608 getIdentifierCString());
5609 goto loaded;
5610 }
5611
5612 #if CONFIG_MACF
5613 /*
5614 * On kxld and on embedded, only call into the MAC hook when on a
5615 * user thread, for access control over userspace kextloads.
5616 *
5617 * On non-kxld systems, additionally check the MAC hook for kexts in
5618 * the Pageable and Aux KCs, regardless of whether we are on a user
5619 * thread or not. This means on Apple silicon devices that the MAC
5620 * hook will only be useful to block 3rd party kexts loaded via
5621 * matching, and any kexts loaded from userspace kextloads.
5622 *
5623 * Note that this should _not_ be called on kexts loaded from the
5624 * kernel bootstrap thread as the kernel proc's cred struct is not
5625 * yet initialized! This won't happen on macOS because all the kexts
5626 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5627 */
5628 if (current_task() != kernel_task
5629 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
5630 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
5631 #endif
5632 ) {
5633 int macCheckResult = 0;
5634 kauth_cred_t cred = NULL;
5635
5636 cred = kauth_cred_get_with_ref();
5637 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5638 kauth_cred_unref(&cred);
5639
5640 if (macCheckResult != 0) {
5641 result = kOSReturnError;
5642 OSKextLog(this,
5643 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5644 "Failed to load kext %s (MAC policy error 0x%x).",
5645 getIdentifierCString(), macCheckResult);
5646 goto finish;
5647 }
5648 }
5649 #endif /* CONFIG_MACF */
5650
5651 if (!sLoadEnabled) {
5652 OSKextLog(this,
5653 kOSKextLogErrorLevel |
5654 kOSKextLogLoadFlag,
5655 "Kext loading is disabled (attempt to load kext %s).",
5656 getIdentifierCString());
5657 result = kOSKextReturnDisabled;
5658 goto finish;
5659 }
5660
5661 /* If we've pushed the next available load tag to the invalid value,
5662 * we can't load any more kexts.
5663 */
5664 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5665 OSKextLog(this,
5666 kOSKextLogErrorLevel |
5667 kOSKextLogLoadFlag,
5668 "Can't load kext %s - no more load tags to assign.",
5669 getIdentifierCString());
5670 result = kOSKextReturnNoResources;
5671 goto finish;
5672 }
5673
5674 /* This is a bit of a hack, because we shouldn't be handling
5675 * personalities within the load function.
5676 */
5677 if (!declaresExecutable()) {
5678 /* There is a special case where a non-executable kext can be loaded: the
5679 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5680 * load its metadata into the global data structures, if appropriate
5681 */
5682 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5683 boolean_t updated = updateExcludeList(infoDict.get());
5684 if (updated) {
5685 OSKextLog(this,
5686 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5687 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5688 }
5689 }
5690
5691 if (isDriverKit()) {
5692 if (loadTag == 0) {
5693 sLoadedDriverKitKexts->setObject(this);
5694 loadTag = sNextLoadTag++;
5695 }
5696 }
5697 result = kOSReturnSuccess;
5698 goto loaded;
5699 }
5700
5701 /* Are we in safe boot?
5702 */
5703 if (sSafeBoot && !isLoadableInSafeBoot()) {
5704 OSKextLog(this,
5705 kOSKextLogErrorLevel |
5706 kOSKextLogLoadFlag,
5707 "Can't load kext %s - not loadable during safe boot.",
5708 getIdentifierCString());
5709 result = kOSKextReturnBootLevel;
5710 goto finish;
5711 }
5712
5713 OSKextLog(this,
5714 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5715 "Loading kext %s.",
5716 getIdentifierCString());
5717
5718 #if !VM_MAPPED_KEXTS
5719 if (isPrelinked() == false) {
5720 OSKextLog(this,
5721 kOSKextLogErrorLevel |
5722 kOSKextLogLoadFlag,
5723 "Can't load kext %s - not in a kext collection.",
5724 getIdentifierCString());
5725 result = kOSKextReturnDisabled;
5726 goto finish;
5727 }
5728 #endif /* defined(__x86_64__) */
5729
5730 #if CONFIG_KXLD
5731 if (!sKxldContext) {
5732 kern_return_t kxldResult;
5733 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5734 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5735 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5736 if (kxldResult) {
5737 OSKextLog(this,
5738 kOSKextLogErrorLevel |
5739 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5740 "Can't load kext %s - failed to create link context.",
5741 getIdentifierCString());
5742 result = kOSKextReturnNoMemory;
5743 goto finish;
5744 }
5745 }
5746 #endif // CONFIG_KXLD
5747
5748 /* We only need to resolve dependencies once for the whole graph, but
5749 * resolveDependencies will just return if there's no work to do, so it's
5750 * safe to call it more than once.
5751 */
5752 if (!resolveDependencies()) {
5753 // xxx - check resolveDependencies() for log msg
5754 OSKextLog(this,
5755 kOSKextLogErrorLevel |
5756 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5757 "Can't load kext %s - failed to resolve library dependencies.",
5758 getIdentifierCString());
5759 result = kOSKextReturnDependencies;
5760 goto finish;
5761 }
5762
5763 /* If we are excluding just the kext being loaded now (and not its
5764 * dependencies), drop the exclusion level to none so dependencies
5765 * start and/or add their personalities.
5766 */
5767 if (dependenciesStartOpt == kOSKextExcludeKext) {
5768 dependenciesStartOpt = kOSKextExcludeNone;
5769 }
5770
5771 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5772 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5773 }
5774
5775 /* Load the dependencies, recursively.
5776 */
5777 count = getNumDependencies();
5778 for (i = 0; i < count; i++) {
5779 OSKext * dependency = OSDynamicCast(OSKext,
5780 dependencies->getObject(i));
5781 if (dependency == NULL) {
5782 OSKextLog(this,
5783 kOSKextLogErrorLevel |
5784 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5785 "Internal error loading kext %s; dependency disappeared.",
5786 getIdentifierCString());
5787 result = kOSKextReturnInternalError;
5788 goto finish;
5789 }
5790
5791 /* Dependencies must be started accorting to the opt,
5792 * but not given the personality names of the main kext.
5793 */
5794 result = dependency->load(dependenciesStartOpt,
5795 dependenciesStartMatchingOpt,
5796 /* personalityNames */ NULL);
5797 if (result != KERN_SUCCESS) {
5798 OSKextLog(this,
5799 kOSKextLogErrorLevel |
5800 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5801 "Dependency %s of kext %s failed to load.",
5802 dependency->getIdentifierCString(),
5803 getIdentifierCString());
5804
5805 OSKext::removeKext(dependency,
5806 /* terminateService/removePersonalities */ true);
5807 result = kOSKextReturnDependencyLoadError;
5808
5809 goto finish;
5810 }
5811 }
5812
5813 result = loadExecutable();
5814 if (result != KERN_SUCCESS) {
5815 goto finish;
5816 }
5817
5818 pendingPgoHead.next = &pendingPgoHead;
5819 pendingPgoHead.prev = &pendingPgoHead;
5820
5821 // The kernel PRNG is not initialized when the first kext is
5822 // loaded, so use early random
5823 uuid_generate_early_random(instance_uuid);
5824 account = IOMallocType(OSKextAccount);
5825
5826 account->loadTag = kmod_info->id;
5827 account->site.refcount = 0;
5828 account->site.flags = VM_TAG_KMOD;
5829
5830 #if DEVELOPMENT || DEBUG
5831 /* Setup the task reference group. */
5832 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
5833 "task_%s", getIdentifierCString());
5834 account->task_refgrp.grp_name = account->task_refgrp_name;
5835 account->task_refgrp.grp_parent = &task_external_refgrp;
5836 os_ref_log_init(&account->task_refgrp);
5837 #endif /* DEVELOPMENT || DEBUG */
5838
5839 account->kext = this;
5840 if (gIOSurfaceIdentifier == bundleID) {
5841 vm_tag_alloc(&account->site);
5842 gIOSurfaceTag = account->site.tag;
5843 }
5844
5845 flags.loaded = true;
5846
5847 /* Add the kext to the list of loaded kexts and update the kmod_info
5848 * struct to point to that of the last loaded kext (which is the way
5849 * it's always been done, though I'd rather do them in order now).
5850 */
5851 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5852 sLoadedKexts->setObject(this);
5853
5854 /* Keep the kernel itself out of the kmod list.
5855 */
5856 if (lastLoadedKext->isKernel()) {
5857 lastLoadedKext = NULL;
5858 }
5859
5860 if (lastLoadedKext) {
5861 kmod_info->next = lastLoadedKext->kmod_info;
5862 }
5863
5864 notifyKextLoadObservers(this, kmod_info);
5865
5866 /* Make the global kmod list point at the just-loaded kext. Note that the
5867 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5868 * although we do report it in kextstat these days by using the newer
5869 * OSArray of loaded kexts, which does contain it.
5870 *
5871 * (The OSKext object representing the kernel doesn't even have a kmod_info
5872 * struct, though I suppose we could stick a pointer to it from the
5873 * static struct in OSRuntime.cpp.)
5874 */
5875 kmod = kmod_info;
5876
5877 /* Save the list of loaded kexts in case we panic.
5878 */
5879 OSKext::saveLoadedKextPanicList();
5880
5881 if (isExecutable()) {
5882 OSKext::updateLoadedKextSummaries();
5883 savePanicString(/* isLoading */ true);
5884
5885 #if CONFIG_DTRACE
5886 registerWithDTrace();
5887 #else
5888 jettisonLinkeditSegment();
5889 #endif /* CONFIG_DTRACE */
5890
5891 #if !VM_MAPPED_KEXTS
5892 /* If there is a page (or more) worth of padding after the end
5893 * of the last data section but before the end of the data segment
5894 * then free it in the same manner the LinkeditSegment is freed
5895 */
5896 jettisonDATASegmentPadding();
5897 #endif
5898 }
5899
5900 loaded:
5901 if (isExecutable() && !flags.started) {
5902 if (startOpt == kOSKextExcludeNone) {
5903 result = start();
5904 if (result != kOSReturnSuccess) {
5905 OSKextLog(this,
5906 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5907 "Kext %s start failed (result 0x%x).",
5908 getIdentifierCString(), result);
5909 result = kOSKextReturnStartStopError;
5910 }
5911 }
5912 }
5913
5914 /* If not excluding matching, send the personalities to the kernel.
5915 * This never affects the result of the load operation.
5916 * This is a bit of a hack, because we shouldn't be handling
5917 * personalities within the load function.
5918 */
5919 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5920 result = sendPersonalitiesToCatalog(true, personalityNames);
5921 }
5922
5923 finish:
5924
5925 if (result != kOSReturnSuccess) {
5926 OSKextLog(this,
5927 kOSKextLogErrorLevel |
5928 kOSKextLogLoadFlag,
5929 "Kext %s failed to load (0x%x).",
5930 getIdentifierCString(), (int)result);
5931 } else if (!alreadyLoaded) {
5932 OSKextLog(this,
5933 kOSKextLogProgressLevel |
5934 kOSKextLogLoadFlag,
5935 "Kext %s loaded.",
5936 getIdentifierCString());
5937
5938 queueKextNotification(kKextRequestPredicateLoadNotification,
5939 OSDynamicCast(OSString, bundleID.get()));
5940 }
5941 return result;
5942 }
5943
5944 #if CONFIG_KXLD
5945 /*********************************************************************
5946 *
5947 *********************************************************************/
5948 static char *
strdup(const char * string)5949 strdup(const char * string)
5950 {
5951 char * result = NULL;
5952 size_t size;
5953
5954 if (!string) {
5955 goto finish;
5956 }
5957
5958 size = 1 + strlen(string);
5959 result = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, size,
5960 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5961 if (!result) {
5962 goto finish;
5963 }
5964
5965 memcpy(result, string, size);
5966
5967 finish:
5968 return result;
5969 }
5970 #endif // CONFIG_KXLD
5971
5972 /*********************************************************************
5973 *
5974 *********************************************************************/
5975
5976 kernel_section_t *
lookupSection(const char * segname,const char * secname)5977 OSKext::lookupSection(const char *segname, const char *secname)
5978 {
5979 kernel_section_t * found_section = NULL;
5980 kernel_mach_header_t * mh = NULL;
5981 kernel_segment_command_t * seg = NULL;
5982 kernel_section_t * sec = NULL;
5983
5984 if (!linkedExecutable) {
5985 return NULL;
5986 }
5987
5988 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5989
5990 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5991 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
5992 continue;
5993 }
5994
5995 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5996 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
5997 found_section = sec;
5998 goto out;
5999 }
6000 }
6001 }
6002
6003 out:
6004 return found_section;
6005 }
6006
6007 /*********************************************************************
6008 *
6009 *********************************************************************/
6010
6011 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6012 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6013 {
6014 OSReturn result = kOSKextReturnBadData;
6015 kernel_mach_header_t * mh = NULL;
6016 kernel_segment_command_t * seg = NULL;
6017 kernel_segment_command_t * linkeditSeg = NULL;
6018 kernel_section_t * sec = NULL;
6019 char * linkeditBase = NULL;
6020 bool haveLinkeditBase = false;
6021 char * relocBase = NULL;
6022 bool haveRelocBase = false;
6023 struct dysymtab_command * dysymtab = NULL;
6024 struct linkedit_data_command * segmentSplitInfo = NULL;
6025 struct symtab_command * symtab = NULL;
6026 kernel_nlist_t * sym = NULL;
6027 struct relocation_info * reloc = NULL;
6028 uint32_t i = 0;
6029 int reloc_size;
6030 vm_offset_t new_kextsize;
6031
6032 if (linkedExecutable == NULL || flags.builtin) {
6033 result = kOSReturnSuccess;
6034 goto finish;
6035 }
6036
6037 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6038 if (kernel_mach_header_is_in_fileset(mh)) {
6039 // kexts in filesets are slid as part of collection sliding
6040 result = kOSReturnSuccess;
6041 goto finish;
6042 }
6043
6044 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6045
6046 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6047 if (!seg->vmaddr) {
6048 continue;
6049 }
6050
6051 seg->vmaddr = ml_static_slide(seg->vmaddr);
6052
6053 #if KASLR_KEXT_DEBUG
6054 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6055 seg->segname,
6056 (unsigned long)ml_static_unslide(seg->vmaddr),
6057 (unsigned long)seg->vmaddr);
6058 #endif
6059
6060 if (!haveRelocBase) {
6061 relocBase = (char *) seg->vmaddr;
6062 haveRelocBase = true;
6063 }
6064 if (!strcmp(seg->segname, "__LINKEDIT")) {
6065 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6066 haveLinkeditBase = true;
6067 linkeditSeg = seg;
6068 }
6069 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6070 sec->addr = ml_static_slide(sec->addr);
6071
6072 #if KASLR_KEXT_DEBUG
6073 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6074 sec->sectname,
6075 (unsigned long)ml_static_unslide(sec->addr),
6076 (unsigned long)sec->addr);
6077 #endif
6078 }
6079 }
6080
6081 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6082
6083 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6084
6085 if (symtab != NULL && doCoalescedSlides == false) {
6086 /* Some pseudo-kexts have symbol tables without segments.
6087 * Ignore them. */
6088 if (symtab->nsyms > 0 && haveLinkeditBase) {
6089 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6090 for (i = 0; i < symtab->nsyms; i++) {
6091 if (sym[i].n_type & N_STAB) {
6092 continue;
6093 }
6094 sym[i].n_value = ml_static_slide(sym[i].n_value);
6095
6096 #if KASLR_KEXT_DEBUG
6097 #define MAX_SYMS_TO_LOG 5
6098 if (i < MAX_SYMS_TO_LOG) {
6099 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6100 (unsigned long)ml_static_unslide(sym[i].n_value),
6101 (unsigned long)sym[i].n_value);
6102 }
6103 #endif
6104 }
6105 }
6106 }
6107
6108 if (dysymtab != NULL && doCoalescedSlides == false) {
6109 if (dysymtab->nextrel > 0) {
6110 OSKextLog(this,
6111 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6112 kOSKextLogLinkFlag,
6113 "Sliding kext %s: External relocations found.",
6114 getIdentifierCString());
6115 goto finish;
6116 }
6117
6118 if (dysymtab->nlocrel > 0) {
6119 if (!haveLinkeditBase) {
6120 OSKextLog(this,
6121 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6122 kOSKextLogLinkFlag,
6123 "Sliding kext %s: No linkedit segment.",
6124 getIdentifierCString());
6125 goto finish;
6126 }
6127
6128 if (!haveRelocBase) {
6129 OSKextLog(this,
6130 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6131 kOSKextLogLinkFlag,
6132 #if __x86_64__
6133 "Sliding kext %s: No writable segments.",
6134 #else
6135 "Sliding kext %s: No segments.",
6136 #endif
6137 getIdentifierCString());
6138 goto finish;
6139 }
6140
6141 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6142 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6143
6144 for (i = 0; i < dysymtab->nlocrel; i++) {
6145 if (reloc[i].r_extern != 0
6146 || reloc[i].r_type != 0
6147 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6148 ) {
6149 OSKextLog(this,
6150 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6151 kOSKextLogLinkFlag,
6152 "Sliding kext %s: Unexpected relocation found.",
6153 getIdentifierCString());
6154 goto finish;
6155 }
6156 if (reloc[i].r_pcrel != 0) {
6157 continue;
6158 }
6159 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6160 *relocAddr = ml_static_slide(*relocAddr);
6161
6162 #if KASLR_KEXT_DEBUG
6163 #define MAX_DYSYMS_TO_LOG 5
6164 if (i < MAX_DYSYMS_TO_LOG) {
6165 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6166 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6167 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6168 }
6169 #endif
6170 }
6171
6172 /* We should free these relocations, not just delete the reference to them.
6173 * <rdar://problem/10535549> Free relocations from PIE kexts.
6174 *
6175 * For now, we do not free LINKEDIT for kexts with split segments.
6176 */
6177 new_kextsize = round_page(kmod_info->size - reloc_size);
6178 if (new_kextsize > UINT_MAX) {
6179 OSKextLog(this,
6180 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6181 kOSKextLogLinkFlag,
6182 "Kext %s: new kext size is too large.",
6183 getIdentifierCString());
6184 goto finish;
6185 }
6186 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6187 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6188 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6189 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6190 size_t bytes_remaining = endofkext - endofrelocInfo;
6191 OSSharedPtr<OSData> new_osdata;
6192
6193 /* fix up symbol offsets if they are after the dsymtab local relocs */
6194 if (symtab) {
6195 if (dysymtab->locreloff < symtab->symoff) {
6196 symtab->symoff -= reloc_size;
6197 }
6198 if (dysymtab->locreloff < symtab->stroff) {
6199 symtab->stroff -= reloc_size;
6200 }
6201 }
6202 if (dysymtab->locreloff < dysymtab->extreloff) {
6203 dysymtab->extreloff -= reloc_size;
6204 }
6205
6206 /* move data behind reloc info down to new offset */
6207 if (endofrelocInfo < endofkext) {
6208 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6209 }
6210
6211 /* Create a new OSData for the smaller kext object and reflect
6212 * new linkedit segment size.
6213 */
6214 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6215 linkeditSeg->filesize = linkeditSeg->vmsize;
6216
6217 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6218 if (new_osdata) {
6219 /* Fix up kmod info and linkedExecutable.
6220 */
6221 kmod_info->size = new_kextsize;
6222 #if VM_MAPPED_KEXTS
6223 new_osdata->setDeallocFunction(osdata_kext_free);
6224 #else
6225 new_osdata->setDeallocFunction(osdata_phys_free);
6226 #endif
6227 linkedExecutable->setDeallocFunction(NULL);
6228 linkedExecutable = os::move(new_osdata);
6229
6230 #if VM_MAPPED_KEXTS
6231 kext_free(new_endofkext, (endofkext - new_endofkext));
6232 #else
6233 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6234 #endif
6235 }
6236 }
6237 dysymtab->nlocrel = 0;
6238 dysymtab->locreloff = 0;
6239 }
6240 }
6241
6242 result = kOSReturnSuccess;
6243 finish:
6244 return result;
6245 }
6246
6247 /*********************************************************************
6248 * called only by load()
6249 *********************************************************************/
6250 OSReturn
loadExecutable()6251 OSKext::loadExecutable()
6252 {
6253 OSReturn result = kOSReturnError;
6254 OSSharedPtr<OSArray> linkDependencies;
6255 uint32_t num_kmod_refs = 0;
6256 OSData * theExecutable = NULL; // do not release
6257 OSString * versString = NULL; // do not release
6258 const char * versCString = NULL; // do not free
6259 const char * string = NULL; // do not free
6260
6261 #if CONFIG_KXLD
6262 unsigned int i;
6263 uint32_t numDirectDependencies = 0;
6264 kern_return_t kxldResult;
6265 KXLDDependency * kxlddeps = NULL; // must kfree
6266 uint32_t num_kxlddeps = 0;
6267 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6268 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6269 #endif // CONFIG_KXLD
6270
6271 /* We need the version string for a variety of bits below.
6272 */
6273 versString = OSDynamicCast(OSString,
6274 getPropertyForHostArch(kCFBundleVersionKey));
6275 if (!versString) {
6276 goto finish;
6277 }
6278 versCString = versString->getCStringNoCopy();
6279
6280 if (isKernelComponent()) {
6281 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6282 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6283 OSKextLog(this,
6284 kOSKextLogErrorLevel |
6285 kOSKextLogLoadFlag,
6286 "Kernel component %s has incorrect version %s; "
6287 "expected %s.",
6288 getIdentifierCString(),
6289 versCString, KERNEL6_VERSION);
6290 result = kOSKextReturnInternalError;
6291 goto finish;
6292 } else if (strcmp(versCString, osrelease)) {
6293 OSKextLog(this,
6294 kOSKextLogErrorLevel |
6295 kOSKextLogLoadFlag,
6296 "Kernel component %s has incorrect version %s; "
6297 "expected %s.",
6298 getIdentifierCString(),
6299 versCString, osrelease);
6300 result = kOSKextReturnInternalError;
6301 goto finish;
6302 }
6303 }
6304 }
6305
6306 #if defined(__x86_64__) || defined(__i386__)
6307 if (flags.resetSegmentsFromVnode) {
6308 /* Fixup the chains and slide the mach headers */
6309 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6310
6311 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6312 result = kOSKextReturnValidation;
6313 goto finish;
6314 }
6315 }
6316 #endif //(__x86_64__) || defined(__i386__)
6317
6318 if (isPrelinked()) {
6319 goto register_kmod;
6320 }
6321
6322 /* <rdar://problem/21444003> all callers must be entitled */
6323 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
6324 OSKextLog(this,
6325 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6326 "Not entitled to link kext '%s'",
6327 getIdentifierCString());
6328 result = kOSKextReturnNotPrivileged;
6329 goto finish;
6330 }
6331
6332 theExecutable = getExecutable();
6333 if (!theExecutable) {
6334 if (declaresExecutable()) {
6335 OSKextLog(this,
6336 kOSKextLogErrorLevel |
6337 kOSKextLogLoadFlag,
6338 "Can't load kext %s - executable is missing.",
6339 getIdentifierCString());
6340 result = kOSKextReturnValidation;
6341 goto finish;
6342 }
6343 goto register_kmod;
6344 }
6345
6346 if (isInterface()) {
6347 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6348 if (executableCopy) {
6349 setLinkedExecutable(executableCopy.get());
6350 }
6351 goto register_kmod;
6352 }
6353
6354 #if CONFIG_KXLD
6355 numDirectDependencies = getNumDependencies();
6356
6357 if (flags.hasBleedthrough) {
6358 linkDependencies = dependencies;
6359 } else {
6360 linkDependencies = OSArray::withArray(dependencies.get());
6361 if (!linkDependencies) {
6362 OSKextLog(this,
6363 kOSKextLogErrorLevel |
6364 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6365 "Can't allocate link dependencies to load kext %s.",
6366 getIdentifierCString());
6367 goto finish;
6368 }
6369
6370 for (i = 0; i < numDirectDependencies; ++i) {
6371 OSKext * dependencyKext = OSDynamicCast(OSKext,
6372 dependencies->getObject(i));
6373 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
6374 }
6375 }
6376
6377 num_kxlddeps = linkDependencies->getCount();
6378 if (!num_kxlddeps) {
6379 OSKextLog(this,
6380 kOSKextLogErrorLevel |
6381 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6382 "Can't load kext %s - it has no library dependencies.",
6383 getIdentifierCString());
6384 goto finish;
6385 }
6386
6387 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6388 if (!kxlddeps) {
6389 OSKextLog(this,
6390 kOSKextLogErrorLevel |
6391 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6392 "Can't allocate link context to load kext %s.",
6393 getIdentifierCString());
6394 goto finish;
6395 }
6396 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6397
6398 for (i = 0; i < num_kxlddeps; ++i) {
6399 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6400
6401 if (dependency->isInterface()) {
6402 OSKext *interfaceTargetKext = NULL; //do not release
6403 OSData * interfaceTarget = NULL; //do not release
6404
6405 if (dependency->isKernelComponent()) {
6406 interfaceTargetKext = sKernelKext;
6407 interfaceTarget = sKernelKext->linkedExecutable.get();
6408 } else {
6409 interfaceTargetKext = OSDynamicCast(OSKext,
6410 dependency->dependencies->getObject(0));
6411
6412 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
6413 }
6414
6415 if (!interfaceTarget) {
6416 // panic?
6417 goto finish;
6418 }
6419
6420 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6421 * it will be useful to have them in the debugger.
6422 * strdup() failing isn't critical right here so we don't check that.
6423 */
6424 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6425 kxlddeps[i].kext_size = interfaceTarget->getLength();
6426 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6427
6428 if (dependency->linkedExecutable != NULL) {
6429 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6430 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6431 } else {
6432 kxlddeps[i].interface = (u_char *) NULL;
6433 kxlddeps[i].interface_size = 0;
6434 }
6435 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6436 } else {
6437 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6438 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6439 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6440 }
6441
6442 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6443 }
6444
6445 kxldHeaderPtr = &kxld_header;
6446
6447 #if DEBUG
6448 OSKextLog(this,
6449 kOSKextLogExplicitLevel |
6450 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6451 "Kext %s - calling kxld_link_file:\n"
6452 " kxld_context: %p\n"
6453 " executable: %p executable_length: %d\n"
6454 " user_data: %p\n"
6455 " kxld_dependencies: %p num_dependencies: %d\n"
6456 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6457 getIdentifierCString(), sKxldContext,
6458 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6459 this, kxlddeps, num_kxlddeps,
6460 kxldHeaderPtr, &kmod_info);
6461 #endif
6462
6463 /* After this call, the linkedExecutable instance variable
6464 * should exist.
6465 */
6466 kxldResult = kxld_link_file(sKxldContext,
6467 (u_char *)theExecutable->getBytesNoCopy(),
6468 theExecutable->getLength(),
6469 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6470 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6471
6472 if (kxldResult != KERN_SUCCESS) {
6473 // xxx - add kxldResult here?
6474 OSKextLog(this,
6475 kOSKextLogErrorLevel |
6476 kOSKextLogLoadFlag,
6477 "Can't load kext %s - link failed.",
6478 getIdentifierCString());
6479 result = kOSKextReturnLinkError;
6480 goto finish;
6481 }
6482
6483 /* We've written data & instructions into kernel memory, so flush the data
6484 * cache and invalidate the instruction cache.
6485 * I/D caches are coherent on x86
6486 */
6487 #if !defined(__i386__) && !defined(__x86_64__)
6488 flush_dcache(kmod_info->address, kmod_info->size, false);
6489 invalidate_icache(kmod_info->address, kmod_info->size, false);
6490 #endif
6491
6492 #else // !CONFIG_KXLD
6493 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6494 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6495 result = kOSKextReturnLinkError;
6496 goto finish;
6497 #endif // CONFIG_KXLD
6498
6499 register_kmod:
6500
6501 if (isInterface()) {
6502 /* Whip up a fake kmod_info entry for the interface kext.
6503 */
6504 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
6505 if (!kmod_info) {
6506 result = KERN_MEMORY_ERROR;
6507 goto finish;
6508 }
6509
6510 /* A pseudokext has almost nothing in its kmod_info struct.
6511 */
6512 kmod_info->info_version = KMOD_INFO_VERSION;
6513
6514 /* An interface kext doesn't have a linkedExecutable, so save a
6515 * copy of the UUID out of the original executable via copyUUID()
6516 * while we still have the original executable.
6517 */
6518 interfaceUUID = copyUUID();
6519 }
6520
6521 kmod_info->id = loadTag = sNextLoadTag++;
6522 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
6523
6524 /* Stamp the bundle ID and version from the OSKext over anything
6525 * resident inside the kmod_info.
6526 */
6527 string = getIdentifierCString();
6528 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6529
6530 string = versCString;
6531 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6532
6533 /* Add the dependencies' kmod_info structs as kmod_references.
6534 */
6535 num_kmod_refs = getNumDependencies();
6536 if (num_kmod_refs) {
6537 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
6538 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
6539 if (!kmod_info->reference_list) {
6540 result = KERN_MEMORY_ERROR;
6541 goto finish;
6542 }
6543 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6544 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6545 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6546 ref->info = refKext->kmod_info;
6547 ref->info->reference_count++;
6548
6549 if (refIndex + 1 < num_kmod_refs) {
6550 ref->next = kmod_info->reference_list + refIndex + 1;
6551 }
6552 }
6553 }
6554
6555 if (kmod_info->hdr_size > UINT32_MAX) {
6556 OSKextLog(this,
6557 kOSKextLogErrorLevel |
6558 kOSKextLogLoadFlag,
6559 #if __LP64__
6560 "Kext %s header size is too large (%lu > UINT32_MAX).",
6561 #else
6562 "Kext %s header size is too large (%u > UINT32_MAX).",
6563 #endif
6564 kmod_info->name,
6565 kmod_info->hdr_size);
6566 result = KERN_FAILURE;
6567 goto finish;
6568 }
6569
6570 if (kmod_info->size > UINT32_MAX) {
6571 OSKextLog(this,
6572 kOSKextLogErrorLevel |
6573 kOSKextLogLoadFlag,
6574 #if __LP64__
6575 "Kext %s size is too large (%lu > UINT32_MAX).",
6576 #else
6577 "Kext %s size is too large (%u > UINT32_MAX).",
6578 #endif
6579 kmod_info->name,
6580 kmod_info->size);
6581 result = KERN_FAILURE;
6582 goto finish;
6583 }
6584
6585 if (!isInterface() && linkedExecutable) {
6586 OSKextLog(this,
6587 kOSKextLogProgressLevel |
6588 kOSKextLogLoadFlag,
6589 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6590 kmod_info->name,
6591 (unsigned)kmod_info->size / PAGE_SIZE,
6592 (unsigned long)ml_static_unslide(kmod_info->address),
6593 (unsigned)kmod_info->id);
6594 }
6595
6596 /* VM protections and wiring for the Aux KC are done at collection loading time */
6597 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6598 /* if prelinked and primary KC, VM protections are already set */
6599 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6600 if (result != KERN_SUCCESS) {
6601 goto finish;
6602 }
6603 }
6604
6605 #if KASAN
6606 if (linkedExecutable) {
6607 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6608 linkedExecutable->getLength(), getIdentifierCString());
6609 }
6610 #else
6611 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6612 OSKextLog(this,
6613 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6614 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6615 getIdentifierCString()
6616 );
6617 result = KERN_FAILURE;
6618 goto finish;
6619 }
6620 #endif
6621
6622 result = kOSReturnSuccess;
6623
6624 finish:
6625
6626 #if CONFIG_KXLD
6627 /* Clear up locally allocated dependency info.
6628 */
6629 for (i = 0; i < num_kxlddeps; ++i) {
6630 size_t size;
6631
6632 if (kxlddeps[i].kext_name) {
6633 size = 1 + strlen(kxlddeps[i].kext_name);
6634 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].kext_name, size);
6635 }
6636 if (kxlddeps[i].interface_name) {
6637 size = 1 + strlen(kxlddeps[i].interface_name);
6638 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].interface_name, size);
6639 }
6640 }
6641 if (kxlddeps) {
6642 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
6643 }
6644 #endif // CONFIG_KXLD
6645
6646 /* We no longer need the unrelocated executable (which the linker
6647 * has altered anyhow).
6648 */
6649 setExecutable(NULL);
6650
6651 if (result != kOSReturnSuccess) {
6652 OSKextLog(this,
6653 kOSKextLogErrorLevel |
6654 kOSKextLogLoadFlag,
6655 "Failed to load executable for kext %s.",
6656 getIdentifierCString());
6657
6658 if (kmod_info && kmod_info->reference_list) {
6659 kfree_type(kmod_reference_t, num_kmod_refs,
6660 kmod_info->reference_list);
6661 }
6662 if (isInterface()) {
6663 kfree_type(kmod_info_t, kmod_info);
6664 kmod_info = NULL;
6665 }
6666 if (kc_type == KCKindUnknown) {
6667 kmod_info = NULL;
6668 if (linkedExecutable) {
6669 linkedExecutable.reset();
6670 }
6671 }
6672 }
6673
6674 return result;
6675 }
6676
6677 /* static */
6678 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)6679 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6680 {
6681 kernel_segment_command_t *linkeditseg = NULL;
6682
6683 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6684 if (linkeditseg == NULL) {
6685 panic("FileSet booted with no Linkedit segment");
6686 }
6687
6688 #if VM_MAPPED_KEXTS
6689 /* BootKC on x86_64 is not vm mapped */
6690 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6691
6692 OSKextLog(/* kext */ NULL,
6693 kOSKextLogProgressLevel |
6694 kOSKextLogGeneralFlag,
6695 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6696 linkeditseg->vmaddr, linkeditseg->vmsize);
6697 #else
6698 /* BootKC on arm64 is not vm mapped, but is slid */
6699 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
6700
6701 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
6702
6703 OSKextLog(/* kext */ NULL,
6704 kOSKextLogProgressLevel |
6705 kOSKextLogGeneralFlag,
6706 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6707 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
6708 #endif /* VM_MAPPED_KEXTS */
6709 }
6710
6711 /*********************************************************************
6712 * The linkedit segment is used by the kext linker for dependency
6713 * resolution, and by dtrace for probe initialization. We can free it
6714 * for non-library kexts, since no kexts depend on non-library kexts
6715 * by definition, once dtrace has been initialized.
6716 *********************************************************************/
6717 void
jettisonLinkeditSegment(void)6718 OSKext::jettisonLinkeditSegment(void)
6719 {
6720 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6721 kernel_segment_command_t * linkedit = NULL;
6722 vm_offset_t start;
6723 vm_size_t linkeditsize, kextsize;
6724 OSSharedPtr<OSData> data;
6725
6726 if (isInFileset()) {
6727 return;
6728 }
6729
6730 #if NO_KEXTD
6731 /* We can free symbol tables for all embedded kexts because we don't
6732 * support runtime kext linking.
6733 */
6734 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6735 #else
6736 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6737 #endif
6738 goto finish;
6739 }
6740
6741 /* Find the linkedit segment. If it's not the last segment, then freeing
6742 * it will fragment the kext into multiple VM regions, which OSKext is not
6743 * designed to handle, so we'll have to skip it.
6744 */
6745 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6746 if (!linkedit) {
6747 goto finish;
6748 }
6749
6750 if (round_page(kmod_info->address + kmod_info->size) !=
6751 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6752 goto finish;
6753 }
6754
6755 /* Create a new OSData for the smaller kext object.
6756 */
6757 linkeditsize = round_page(linkedit->vmsize);
6758 kextsize = kmod_info->size - linkeditsize;
6759 start = linkedit->vmaddr;
6760
6761 if (kextsize > UINT_MAX) {
6762 goto finish;
6763 }
6764 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6765 if (!data) {
6766 goto finish;
6767 }
6768
6769 /* Fix the kmod info and linkedExecutable.
6770 */
6771 kmod_info->size = kextsize;
6772
6773 #if VM_MAPPED_KEXTS
6774 data->setDeallocFunction(osdata_kext_free);
6775 #else
6776 data->setDeallocFunction(osdata_phys_free);
6777 #endif
6778 linkedExecutable->setDeallocFunction(NULL);
6779 linkedExecutable = os::move(data);
6780 flags.jettisonLinkeditSeg = 1;
6781
6782 /* Free the linkedit segment.
6783 */
6784 #if VM_MAPPED_KEXTS
6785 kext_free(start, linkeditsize);
6786 #else
6787 ml_static_mfree(start, linkeditsize);
6788 #endif
6789
6790 finish:
6791 return;
6792 }
6793
6794 /*********************************************************************
6795 * If there are whole pages that are unused betweem the last section
6796 * of the DATA segment and the end of the DATA segment then we can free
6797 * them
6798 *********************************************************************/
6799 void
6800 OSKext::jettisonDATASegmentPadding(void)
6801 {
6802 kernel_mach_header_t * mh;
6803 kernel_segment_command_t * dataSeg;
6804 kernel_section_t * sec, * lastSec;
6805 vm_offset_t dataSegEnd, lastSecEnd;
6806 vm_size_t padSize;
6807
6808 if (flags.builtin) {
6809 return;
6810 }
6811 mh = (kernel_mach_header_t *)kmod_info->address;
6812
6813 if (isInFileset()) {
6814 return;
6815 }
6816
6817 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6818 if (dataSeg == NULL) {
6819 return;
6820 }
6821
6822 lastSec = NULL;
6823 sec = firstsect(dataSeg);
6824 while (sec != NULL) {
6825 lastSec = sec;
6826 sec = nextsect(dataSeg, sec);
6827 }
6828
6829 if (lastSec == NULL) {
6830 return;
6831 }
6832
6833 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6834 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6835 return;
6836 }
6837
6838 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6839 lastSecEnd = round_page(lastSec->addr + lastSec->size);
6840
6841 if (dataSegEnd <= lastSecEnd) {
6842 return;
6843 }
6844
6845 padSize = dataSegEnd - lastSecEnd;
6846
6847 if (padSize >= PAGE_SIZE) {
6848 #if VM_MAPPED_KEXTS
6849 kext_free(lastSecEnd, padSize);
6850 #else
6851 ml_static_mfree(lastSecEnd, padSize);
6852 #endif
6853 }
6854 }
6855
6856 /*********************************************************************
6857 *********************************************************************/
6858 void
6859 OSKext::setLinkedExecutable(OSData * anExecutable)
6860 {
6861 if (linkedExecutable) {
6862 panic("Attempt to set linked executable on kext "
6863 "that already has one (%s).\n",
6864 getIdentifierCString());
6865 }
6866 linkedExecutable.reset(anExecutable, OSRetain);
6867 return;
6868 }
6869
6870 #if CONFIG_DTRACE
6871 /*********************************************************************
6872 * Go through all loaded kexts and tell them to register with dtrace.
6873 * The instance method only registers if necessary.
6874 *********************************************************************/
6875 /* static */
6876 void
6877 OSKext::registerKextsWithDTrace(void)
6878 {
6879 uint32_t count = sLoadedKexts->getCount();
6880 uint32_t i;
6881
6882 IORecursiveLockLock(sKextLock);
6883
6884 for (i = 0; i < count; i++) {
6885 OSKext * thisKext = NULL; // do not release
6886
6887 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6888 if (!thisKext || !thisKext->isExecutable()) {
6889 continue;
6890 }
6891
6892 thisKext->registerWithDTrace();
6893 }
6894
6895 IORecursiveLockUnlock(sKextLock);
6896
6897 return;
6898 }
6899
6900 extern "C" {
6901 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6902 extern int (*dtrace_modunload)(struct kmod_info *);
6903 };
6904
6905 /*********************************************************************
6906 *********************************************************************/
6907 void
6908 OSKext::registerWithDTrace(void)
6909 {
6910 /* Register kext with dtrace. A dtrace_modload failure should not
6911 * prevent a kext from loading, so we ignore the return code.
6912 */
6913 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6914 uint32_t modflag = 0;
6915 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
6916
6917 #if XNU_TARGET_OS_OSX
6918 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6919 if (forceInit == kOSBooleanTrue) {
6920 OSKextLog(this,
6921 kOSKextLogBasicLevel |
6922 kOSKextLogGeneralFlag,
6923 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
6924 getIdentifierCString());
6925 forceInit = kOSBooleanFalse;
6926 }
6927 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6928 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6929 }
6930 #endif /* XNU_TARGET_OS_OSX */
6931 if (forceInit == kOSBooleanTrue) {
6932 modflag |= KMOD_DTRACE_FORCE_INIT;
6933 }
6934 if (flags.builtin) {
6935 modflag |= KMOD_DTRACE_STATIC_KEXT;
6936 }
6937
6938 (void)(*dtrace_modload)(kmod_info, modflag);
6939 flags.dtraceInitialized = true;
6940 jettisonLinkeditSegment();
6941 }
6942 return;
6943 }
6944 /*********************************************************************
6945 *********************************************************************/
6946 void
6947 OSKext::unregisterWithDTrace(void)
6948 {
6949 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6950 * prevent a kext from loading, so we ignore the return code.
6951 */
6952 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6953 (void)(*dtrace_modunload)(kmod_info);
6954 flags.dtraceInitialized = false;
6955 }
6956 return;
6957 }
6958 #endif /* CONFIG_DTRACE */
6959
6960
6961 /*********************************************************************
6962 * called only by loadExecutable()
6963 *********************************************************************/
6964 #if !VM_MAPPED_KEXTS
6965 #if defined(__arm__) || defined(__arm64__)
6966 static inline kern_return_t
6967 OSKext_protect(
6968 kernel_mach_header_t *kext_mh,
6969 vm_map_t map,
6970 vm_map_offset_t start,
6971 vm_map_offset_t end,
6972 vm_prot_t new_prot,
6973 boolean_t set_max,
6974 kc_kind_t kc_type)
6975 {
6976 #pragma unused(kext_mh,map,kc_type)
6977 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
6978 assert(start <= end);
6979 if (start >= end) {
6980 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6981 } else if (set_max) {
6982 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
6983 } else {
6984 return ml_static_protect(start, end - start, new_prot);
6985 }
6986 }
6987
6988 static inline kern_return_t
6989 OSKext_wire(
6990 kernel_mach_header_t *kext_mh,
6991 vm_map_t map,
6992 vm_map_offset_t start,
6993 vm_map_offset_t end,
6994 vm_prot_t access_type,
6995 boolean_t user_wire,
6996 kc_kind_t kc_type)
6997 {
6998 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6999 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7000 }
7001 #else
7002 #error Unrecognized architecture
7003 #endif
7004 #else
7005 static inline kern_return_t
7006 OSKext_protect(
7007 kernel_mach_header_t *kext_mh,
7008 vm_map_t map,
7009 vm_map_offset_t start,
7010 vm_map_offset_t end,
7011 vm_prot_t new_prot,
7012 boolean_t set_max,
7013 kc_kind_t kc_type)
7014 {
7015 if (start == end) { // 10538581
7016 return KERN_SUCCESS;
7017 }
7018 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7019 /*
7020 * XXX: This will probably need to be different for AuxKC and
7021 * pageableKC!
7022 */
7023 return ml_static_protect(start, end - start, new_prot);
7024 }
7025 return vm_map_protect(map, start, end, new_prot, set_max);
7026 }
7027
7028 static inline kern_return_t
7029 OSKext_wire(
7030 kernel_mach_header_t *kext_mh,
7031 vm_map_t map,
7032 vm_map_offset_t start,
7033 vm_map_offset_t end,
7034 vm_prot_t access_type,
7035 boolean_t user_wire,
7036 kc_kind_t kc_type)
7037 {
7038 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7039 /* TODO: we may need to hook this for the pageableKC */
7040 return KERN_SUCCESS;
7041 }
7042 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7043 }
7044 #endif
7045
7046 OSReturn
7047 OSKext::setVMAttributes(bool protect, bool wire)
7048 {
7049 vm_map_t kext_map = NULL;
7050 kernel_segment_command_t * seg = NULL;
7051 vm_map_offset_t start_protect = 0;
7052 vm_map_offset_t start_wire = 0;
7053 vm_map_offset_t end_protect = 0;
7054 vm_map_offset_t end_wire = 0;
7055 OSReturn result = kOSReturnError;
7056
7057 if (isInterface() || !declaresExecutable() || flags.builtin) {
7058 result = kOSReturnSuccess;
7059 goto finish;
7060 }
7061
7062 /* Get the kext's vm map */
7063 kext_map = kext_get_vm_map(kmod_info);
7064 if (!kext_map) {
7065 result = KERN_MEMORY_ERROR;
7066 goto finish;
7067 }
7068
7069 #if !VM_MAPPED_KEXTS
7070 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7071 /* This is a split kext in a prelinked kernelcache; we'll let the
7072 * platform code take care of protecting it. It is already wired.
7073 */
7074 /* TODO: Should this still allow protections for the first segment
7075 * to go through, in the event that we have a mix of split and
7076 * unsplit kexts?
7077 */
7078 result = KERN_SUCCESS;
7079 goto finish;
7080 }
7081
7082 if (isInFileset() && kc_type != KCKindPageable) {
7083 // kexts in filesets have protections setup as part of collection loading
7084 result = KERN_SUCCESS;
7085 goto finish;
7086 }
7087 #endif
7088
7089 /* Protect the headers as read-only; they do not need to be wired */
7090 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7091 kext_map, kmod_info->address,
7092 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7093 : KERN_SUCCESS;
7094 if (result != KERN_SUCCESS) {
7095 goto finish;
7096 }
7097
7098 /* Set the VM protections and wire down each of the segments */
7099 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7100 while (seg) {
7101 #if __arm__
7102 /* We build all ARM kexts, so we can ensure they are aligned */
7103 assert((seg->vmaddr & PAGE_MASK) == 0);
7104 assert((seg->vmsize & PAGE_MASK) == 0);
7105 #endif
7106
7107 /*
7108 * For the non page aligned segments, the range calculation for protection
7109 * and wiring differ as follows:
7110 *
7111 * Protection: The non page aligned data at the start or at the end of the
7112 * segment is excluded from the protection. This exclusion is needed to make
7113 * sure OSKext_protect is not called twice on same page, if the page is shared
7114 * between two segments.
7115 *
7116 * Wiring: The non page aligned data at the start or at the end of the
7117 * segment is included in the wiring range, this inclusion is needed to make sure
7118 * all the data of the segment is wired.
7119 */
7120 start_protect = round_page(seg->vmaddr);
7121 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7122
7123 start_wire = trunc_page(seg->vmaddr);
7124 end_wire = round_page(seg->vmaddr + seg->vmsize);
7125
7126 /*
7127 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7128 * across kexts and data from kexts is not page aligned
7129 */
7130 if (protect && (end_protect > start_protect) &&
7131 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7132 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7133 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7134 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7135 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7136 if (result != KERN_SUCCESS) {
7137 OSKextLog(this,
7138 kOSKextLogErrorLevel |
7139 kOSKextLogLoadFlag,
7140 "Kext %s failed to set maximum VM protections "
7141 "for segment %s - 0x%x.",
7142 getIdentifierCString(), seg->segname, (int)result);
7143 goto finish;
7144 }
7145
7146 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7147 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7148 if (result != KERN_SUCCESS) {
7149 OSKextLog(this,
7150 kOSKextLogErrorLevel |
7151 kOSKextLogLoadFlag,
7152 "Kext %s failed to set initial VM protections "
7153 "for segment %s - 0x%x.",
7154 getIdentifierCString(), seg->segname, (int)result);
7155 goto finish;
7156 }
7157 }
7158
7159 if (segmentShouldBeWired(seg) && wire) {
7160 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7161 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7162 if (result != KERN_SUCCESS) {
7163 goto finish;
7164 }
7165 }
7166
7167 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7168 }
7169
7170 finish:
7171 return result;
7172 }
7173
7174 /*********************************************************************
7175 *********************************************************************/
7176 boolean_t
7177 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7178 {
7179 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7180 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7181 }
7182
7183 /*********************************************************************
7184 *********************************************************************/
7185 OSReturn
7186 OSKext::validateKextMapping(bool startFlag)
7187 {
7188 OSReturn result = kOSReturnError;
7189 const char * whichOp = startFlag ? "start" : "stop";
7190 kern_return_t kern_result = 0;
7191 vm_map_t kext_map = NULL;
7192 kernel_segment_command_t * seg = NULL;
7193 mach_vm_address_t address = 0;
7194 mach_vm_size_t size = 0;
7195 uint32_t depth = 0;
7196 uint64_t kext_segbase = 0;
7197 uint64_t kext_segsize = 0;
7198 mach_msg_type_number_t count;
7199 vm_region_submap_short_info_data_64_t info;
7200 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7201
7202 if (flags.builtin) {
7203 return kOSReturnSuccess;
7204 }
7205
7206 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7207 bzero(&info, sizeof(info));
7208
7209 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7210 // xxx - sufficient?
7211
7212 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7213 */
7214 if (!kmod_info) {
7215 OSKextLog(this,
7216 kOSKextLogErrorLevel |
7217 kOSKextLogLoadFlag,
7218 "Kext %s - NULL kmod_info pointer.",
7219 getIdentifierCString());
7220 result = kOSKextReturnBadData;
7221 goto finish;
7222 }
7223
7224 if (startFlag) {
7225 address = (mach_vm_address_t)kmod_info->start;
7226 } else {
7227 address = (mach_vm_address_t)kmod_info->stop;
7228 }
7229
7230 if (!address) {
7231 OSKextLog(this,
7232 kOSKextLogErrorLevel |
7233 kOSKextLogLoadFlag,
7234 "Kext %s - NULL module %s pointer.",
7235 getIdentifierCString(), whichOp);
7236 result = kOSKextReturnBadData;
7237 goto finish;
7238 }
7239
7240 kext_map = kext_get_vm_map(kmod_info);
7241 depth = (kernel_map == kext_map) ? 1 : 2;
7242 if (isInFileset()) {
7243 #if defined(HAS_APPLE_PAC)
7244 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7245 #endif /* defined(HAS_APPLE_PAC) */
7246 }
7247
7248 /* Verify that the start/stop function lies within the kext's address range.
7249 */
7250 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7251 isInFileset()) {
7252 /* This will likely be how we deal with split kexts; walk the segments to
7253 * check that the function lies inside one of the segments of this kext.
7254 */
7255 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7256 seg != NULL;
7257 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7258 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7259 kext_segbase = seg->vmaddr;
7260 kext_segsize = seg->vmsize;
7261 break;
7262 }
7263 }
7264
7265 if (!seg) {
7266 OSKextLog(this,
7267 kOSKextLogErrorLevel |
7268 kOSKextLogLoadFlag,
7269 "Kext %s module %s pointer is outside of kext range "
7270 "(%s %p - kext starts at %p).",
7271 getIdentifierCString(),
7272 whichOp,
7273 whichOp,
7274 (void *)(((uintptr_t)address) - kext_slide),
7275 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7276 result = kOSKextReturnBadData;
7277 goto finish;
7278 }
7279
7280 seg = NULL;
7281 } else {
7282 if (address < kmod_info->address + kmod_info->hdr_size ||
7283 kmod_info->address + kmod_info->size <= address) {
7284 OSKextLog(this,
7285 kOSKextLogErrorLevel |
7286 kOSKextLogLoadFlag,
7287 "Kext %s module %s pointer is outside of kext range "
7288 "(%s %p - kext at %p-%p).",
7289 getIdentifierCString(),
7290 whichOp,
7291 whichOp,
7292 (void *)(((uintptr_t)address) - kext_slide),
7293 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7294 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7295 result = kOSKextReturnBadData;
7296 goto finish;
7297 }
7298 }
7299
7300 /* Only do these checks before calling the start function;
7301 * If anything goes wrong with the mapping while the kext is running,
7302 * we'll likely have panicked well before any attempt to stop the kext.
7303 */
7304 if (startFlag) {
7305 if (!isInFileset() || kc_type != KCKindPrimary) {
7306 /*
7307 * Verify that the start/stop function is executable.
7308 */
7309 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7310 (vm_region_recurse_info_t)&info, &count);
7311 if (kern_result != KERN_SUCCESS) {
7312 OSKextLog(this,
7313 kOSKextLogErrorLevel |
7314 kOSKextLogLoadFlag,
7315 "Kext %s - bad %s pointer %p.",
7316 getIdentifierCString(),
7317 whichOp, (void *)ml_static_unslide(address));
7318 result = kOSKextReturnBadData;
7319 goto finish;
7320 }
7321 } else {
7322 /*
7323 * Since kexts loaded from the primary KC are held in memory
7324 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7325 * discover that memory's protection flags. Instead, we need to
7326 * get that information from the kernel pmap itself. Above, we
7327 * (potentially) saved the size of the segment in which the address
7328 * in question was located. If we have a non-zero size, verify
7329 * that all pages in the (address, address + kext_segsize) range
7330 * are marked executable. If we somehow did not record the size
7331 * (or the base) just verify the single page that includes the address.
7332 */
7333 if (kext_segbase == 0 || kext_segsize == 0) {
7334 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7335 kext_segsize = PAGE_SIZE;
7336 }
7337 }
7338
7339 #if VM_MAPPED_KEXTS
7340 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7341 ((isInFileset() && kc_type == KCKindPrimary) &&
7342 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
7343 OSKextLog(this,
7344 kOSKextLogErrorLevel |
7345 kOSKextLogLoadFlag,
7346 "Kext %s - memory region containing module %s function "
7347 "is not executable.",
7348 getIdentifierCString(), whichOp);
7349 result = kOSKextReturnBadData;
7350 goto finish;
7351 }
7352 #endif
7353
7354 /* Verify that the kext's segments are backed by physical memory.
7355 */
7356 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7357 while (seg) {
7358 if (!verifySegmentMapping(seg)) {
7359 result = kOSKextReturnBadData;
7360 goto finish;
7361 }
7362
7363 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7364 }
7365 }
7366
7367 result = kOSReturnSuccess;
7368 finish:
7369 return result;
7370 }
7371
7372 /*********************************************************************
7373 *********************************************************************/
7374 boolean_t
7375 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7376 {
7377 mach_vm_address_t address = 0;
7378
7379 if (seg->vmsize > UINT32_MAX) {
7380 return false;
7381 }
7382
7383 if (!segmentShouldBeWired(seg)) {
7384 return true;
7385 }
7386
7387 for (address = seg->vmaddr;
7388 address < round_page(seg->vmaddr + seg->vmsize);
7389 address += PAGE_SIZE) {
7390 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7391 OSKextLog(this,
7392 kOSKextLogErrorLevel |
7393 kOSKextLogLoadFlag,
7394 "Kext %s - page %p is not backed by physical memory.",
7395 getIdentifierCString(),
7396 (void *)address);
7397 return false;
7398 }
7399 }
7400
7401 return true;
7402 }
7403
7404 /*********************************************************************
7405 *********************************************************************/
7406 static void
7407 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7408 {
7409 uint64_t stamp = 0;
7410 firehose_tracepoint_id_u trace_id;
7411 struct firehose_trace_uuid_info_s uuid_info_s;
7412 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7413 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
7414 OSSharedPtr<OSData> uuid_data;
7415
7416 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7417 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
7418
7419 uuid_data = aKext->copyTextUUID();
7420 if (uuid_data) {
7421 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
7422 }
7423
7424 uuid_info->ftui_size = size;
7425 if (aKext->isDriverKit()) {
7426 uuid_info->ftui_address = address;
7427 } else {
7428 uuid_info->ftui_address = ml_static_unslide(address);
7429 }
7430 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7431 return;
7432 }
7433
7434 void
7435 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7436 {
7437 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7438 }
7439
7440 /*********************************************************************
7441 *********************************************************************/
7442 OSReturn
7443 OSKext::start(bool startDependenciesFlag)
7444 {
7445 OSReturn result = kOSReturnError;
7446 kern_return_t (* startfunc)(kmod_info_t *, void *);
7447 unsigned int i, count;
7448 void * kmodStartData = NULL;
7449
7450 if (isStarted() || isInterface() || isKernelComponent()) {
7451 result = kOSReturnSuccess;
7452 goto finish;
7453 }
7454
7455 if (!isLoaded()) {
7456 OSKextLog(this,
7457 kOSKextLogErrorLevel |
7458 kOSKextLogLoadFlag,
7459 "Attempt to start nonloaded kext %s.",
7460 getIdentifierCString());
7461 result = kOSKextReturnInvalidArgument;
7462 goto finish;
7463 }
7464
7465 if (!sLoadEnabled) {
7466 OSKextLog(this,
7467 kOSKextLogErrorLevel |
7468 kOSKextLogLoadFlag,
7469 "Kext loading is disabled (attempt to start kext %s).",
7470 getIdentifierCString());
7471 result = kOSKextReturnDisabled;
7472 goto finish;
7473 }
7474
7475 result = validateKextMapping(/* start? */ true);
7476 if (result != kOSReturnSuccess) {
7477 goto finish;
7478 }
7479
7480 startfunc = kmod_info->start;
7481
7482 count = getNumDependencies();
7483 for (i = 0; i < count; i++) {
7484 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7485 if (dependency == NULL) {
7486 OSKextLog(this,
7487 kOSKextLogErrorLevel |
7488 kOSKextLogLoadFlag,
7489 "Kext %s start - internal error, dependency disappeared.",
7490 getIdentifierCString());
7491 goto finish;
7492 }
7493 if (!dependency->isStarted()) {
7494 if (startDependenciesFlag) {
7495 OSReturn dependencyResult =
7496 dependency->start(startDependenciesFlag);
7497 if (dependencyResult != KERN_SUCCESS) {
7498 OSKextLog(this,
7499 kOSKextLogErrorLevel |
7500 kOSKextLogLoadFlag,
7501 "Kext %s start - dependency %s failed to start (error 0x%x).",
7502 getIdentifierCString(),
7503 dependency->getIdentifierCString(),
7504 dependencyResult);
7505 goto finish;
7506 }
7507 } else {
7508 OSKextLog(this,
7509 kOSKextLogErrorLevel |
7510 kOSKextLogLoadFlag,
7511 "Not starting %s - dependency %s not started yet.",
7512 getIdentifierCString(),
7513 dependency->getIdentifierCString());
7514 result = kOSKextReturnStartStopError; // xxx - make new return?
7515 goto finish;
7516 }
7517 }
7518 }
7519
7520 OSKextLog(this,
7521 kOSKextLogDetailLevel |
7522 kOSKextLogLoadFlag,
7523 "Kext %s calling module start function.",
7524 getIdentifierCString());
7525
7526 flags.starting = 1;
7527
7528 // Drop a log message so logd can grab the needed information to decode this kext
7529 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7530 result = OSRuntimeInitializeCPP(this);
7531 if (result == KERN_SUCCESS) {
7532 result = startfunc(kmod_info, kmodStartData);
7533 }
7534
7535 flags.starting = 0;
7536
7537 /* On success overlap the setting of started/starting. On failure just
7538 * clear starting.
7539 */
7540 if (result == KERN_SUCCESS) {
7541 flags.started = 1;
7542
7543 // xxx - log start error from kernel?
7544 OSKextLog(this,
7545 kOSKextLogProgressLevel |
7546 kOSKextLogLoadFlag,
7547 "Kext %s is now started.",
7548 getIdentifierCString());
7549 } else {
7550 invokeOrCancelRequestCallbacks(
7551 /* result not actually used */ kOSKextReturnStartStopError,
7552 /* invokeFlag */ false);
7553 OSKextLog(this,
7554 kOSKextLogWarningLevel |
7555 kOSKextLogLoadFlag,
7556 "Kext %s did not start (return code 0x%x).",
7557 getIdentifierCString(), result);
7558 }
7559
7560 finish:
7561 return result;
7562 }
7563
7564 /*********************************************************************
7565 *********************************************************************/
7566 /* static */
7567 bool
7568 OSKext::canUnloadKextWithIdentifier(
7569 OSString * kextIdentifier,
7570 bool checkClassesFlag)
7571 {
7572 bool result = false;
7573 OSKext * aKext = NULL; // do not release
7574
7575 IORecursiveLockLock(sKextLock);
7576
7577 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7578
7579 if (!aKext) {
7580 goto finish; // can't unload what's not loaded
7581 }
7582
7583 if (aKext->isLoaded()) {
7584 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7585 goto finish;
7586 }
7587 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7588 goto finish;
7589 }
7590 }
7591
7592 result = true;
7593
7594 finish:
7595 IORecursiveLockUnlock(sKextLock);
7596 return result;
7597 }
7598
7599 /*********************************************************************
7600 *********************************************************************/
7601 OSReturn
7602 OSKext::stop(void)
7603 {
7604 OSReturn result = kOSReturnError;
7605 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7606
7607 if (!isStarted() || isInterface()) {
7608 result = kOSReturnSuccess;
7609 goto finish;
7610 }
7611
7612 if (!isLoaded()) {
7613 OSKextLog(this,
7614 kOSKextLogErrorLevel |
7615 kOSKextLogLoadFlag,
7616 "Attempt to stop nonloaded kext %s.",
7617 getIdentifierCString());
7618 result = kOSKextReturnInvalidArgument;
7619 goto finish;
7620 }
7621
7622 /* Refuse to stop if we have clients or instances. It is up to
7623 * the caller to make sure those aren't true.
7624 */
7625 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7626 OSKextLog(this,
7627 kOSKextLogErrorLevel |
7628 kOSKextLogLoadFlag,
7629 "Kext %s - C++ instances; can't stop.",
7630 getIdentifierCString());
7631 result = kOSKextReturnInUse;
7632 goto finish;
7633 }
7634
7635 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7636 OSKextLog(this,
7637 kOSKextLogErrorLevel |
7638 kOSKextLogLoadFlag,
7639 "Kext %s - has references (linkage or tracking object); "
7640 "can't stop.",
7641 getIdentifierCString());
7642 result = kOSKextReturnInUse;
7643 goto finish;
7644 }
7645
7646 /* Note: If validateKextMapping fails on the stop & unload path,
7647 * we are in serious trouble and a kernel panic is likely whether
7648 * we stop & unload the kext or not.
7649 */
7650 result = validateKextMapping(/* start? */ false);
7651 if (result != kOSReturnSuccess) {
7652 goto finish;
7653 }
7654
7655 stopfunc = kmod_info->stop;
7656 if (stopfunc) {
7657 OSKextLog(this,
7658 kOSKextLogDetailLevel |
7659 kOSKextLogLoadFlag,
7660 "Kext %s calling module stop function.",
7661 getIdentifierCString());
7662
7663 flags.stopping = 1;
7664
7665 result = stopfunc(kmod_info, /* userData */ NULL);
7666 if (result == KERN_SUCCESS) {
7667 result = OSRuntimeFinalizeCPP(this);
7668 }
7669
7670 flags.stopping = 0;
7671
7672 if (result == KERN_SUCCESS) {
7673 flags.started = 0;
7674
7675 OSKextLog(this,
7676 kOSKextLogDetailLevel |
7677 kOSKextLogLoadFlag,
7678 "Kext %s is now stopped and ready to unload.",
7679 getIdentifierCString());
7680 } else {
7681 OSKextLog(this,
7682 kOSKextLogErrorLevel |
7683 kOSKextLogLoadFlag,
7684 "Kext %s did not stop (return code 0x%x).",
7685 getIdentifierCString(), result);
7686 result = kOSKextReturnStartStopError;
7687 }
7688 }
7689
7690 finish:
7691 // Drop a log message so logd can update this kext's metadata
7692 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7693 return result;
7694 }
7695
7696 /*********************************************************************
7697 *********************************************************************/
7698 OSReturn
7699 OSKext::unload(void)
7700 {
7701 OSReturn result = kOSReturnError;
7702 unsigned int index;
7703 uint32_t num_kmod_refs = 0;
7704 OSKextAccount * freeAccount;
7705 bool in_fileset = false;
7706
7707 if (!sUnloadEnabled) {
7708 OSKextLog(this,
7709 kOSKextLogErrorLevel |
7710 kOSKextLogLoadFlag,
7711 "Kext unloading is disabled (%s).",
7712 this->getIdentifierCString());
7713
7714 result = kOSKextReturnDisabled;
7715 goto finish;
7716 }
7717
7718 // cache this result so we don't need to access the kmod_info after
7719 // it's been potentially free'd
7720 in_fileset = isInFileset();
7721
7722 /* Refuse to unload if we have clients or instances. It is up to
7723 * the caller to make sure those aren't true.
7724 */
7725 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7726 // xxx - Don't log under errors? this is more of an info thing
7727 OSKextLog(this,
7728 kOSKextLogErrorLevel |
7729 kOSKextLogKextBookkeepingFlag,
7730 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7731 getIdentifierCString());
7732 result = kOSKextReturnInUse;
7733 goto finish;
7734 }
7735
7736 if (isDriverKit()) {
7737 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7738 if (index != (unsigned int)-1) {
7739 sLoadedDriverKitKexts->removeObject(index);
7740 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7741 loadTag = 0;
7742 }
7743 }
7744
7745 if (!isLoaded()) {
7746 result = kOSReturnSuccess;
7747 goto finish;
7748 }
7749
7750 if (isKernelComponent()) {
7751 result = kOSKextReturnInvalidArgument;
7752 goto finish;
7753 }
7754
7755 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
7756 OSKextLog(this,
7757 kOSKextLogErrorLevel |
7758 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7759 "Can't unload kext %s; classes have instances:",
7760 getIdentifierCString());
7761 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7762 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7763 result = kOSKextReturnInUse;
7764 goto finish;
7765 }
7766
7767 /* Note that the kext is unloading before running any code that
7768 * might be in the kext (request callbacks, module stop function).
7769 * We will deny certain requests made against a kext in the process
7770 * of unloading.
7771 */
7772 flags.unloading = 1;
7773
7774 /* Update the string describing the last kext to unload in case we panic.
7775 */
7776 savePanicString(/* isLoading */ false);
7777
7778 if (isStarted()) {
7779 result = stop();
7780 if (result != KERN_SUCCESS) {
7781 OSKextLog(this,
7782 kOSKextLogErrorLevel |
7783 kOSKextLogLoadFlag,
7784 "Kext %s can't unload - module stop returned 0x%x.",
7785 getIdentifierCString(), (unsigned)result);
7786 result = kOSKextReturnStartStopError;
7787 goto finish;
7788 }
7789 }
7790
7791 OSKextLog(this,
7792 kOSKextLogProgressLevel |
7793 kOSKextLogLoadFlag,
7794 "Kext %s unloading.",
7795 getIdentifierCString());
7796
7797 {
7798 struct list_head *p;
7799 struct list_head *prev;
7800 struct list_head *next;
7801 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7802 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7803 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7804 prev = p->prev;
7805 next = p->next;
7806 prev->next = next;
7807 next->prev = prev;
7808 p->prev = p;
7809 p->next = p;
7810 IORecursiveLockWakeup(sKextLock, s, false);
7811 }
7812 }
7813
7814
7815 /* Even if we don't call the stop function, we want to be sure we
7816 * have no OSMetaClass references before unloading the kext executable
7817 * from memory. OSMetaClasses may have pointers into the kext executable
7818 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7819 */
7820 if (metaClasses) {
7821 metaClasses->flushCollection();
7822 }
7823 (void) OSRuntimeFinalizeCPP(this);
7824
7825 /* Remove the kext from the list of loaded kexts, patch the gap
7826 * in the kmod_info_t linked list, and reset "kmod" to point to the
7827 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7828 */
7829 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7830 if (index != (unsigned int)-1) {
7831 sLoadedKexts->removeObject(index);
7832
7833 OSKext * nextKext = OSDynamicCast(OSKext,
7834 sLoadedKexts->getObject(index));
7835
7836 if (nextKext) {
7837 if (index > 0) {
7838 OSKext * gapKext = OSDynamicCast(OSKext,
7839 sLoadedKexts->getObject(index - 1));
7840
7841 nextKext->kmod_info->next = gapKext->kmod_info;
7842 } else { /* index == 0 */
7843 nextKext->kmod_info->next = NULL;
7844 }
7845 }
7846
7847 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7848 if (lastKext && !lastKext->isKernel()) {
7849 kmod = lastKext->kmod_info;
7850 } else {
7851 kmod = NULL; // clear the global kmod variable
7852 }
7853 }
7854
7855 /* Clear out the kmod references that we're keeping for compatibility
7856 * with current panic backtrace code & kgmacros.
7857 * xxx - will want to update those bits sometime and remove this.
7858 */
7859 num_kmod_refs = getNumDependencies();
7860 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7861 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7862 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7863 ref->info->reference_count--;
7864 }
7865 kfree_type(kmod_reference_t, num_kmod_refs,
7866 kmod_info->reference_list);
7867 }
7868
7869 #if CONFIG_DTRACE
7870 unregisterWithDTrace();
7871 #endif /* CONFIG_DTRACE */
7872
7873 notifyKextUnloadObservers(this);
7874
7875 freeAccount = NULL;
7876 IOSimpleLockLock(sKextAccountsLock);
7877 account->kext = NULL;
7878 if (account->site.tag) {
7879 account->site.flags |= VM_TAG_UNLOAD;
7880 } else {
7881 freeAccount = account;
7882 }
7883
7884 #if DEVELOPMENT || DEBUG
7885 assertf(account->task_refgrp.grp_count == 0,
7886 "unloading a kext with active task references");
7887 #endif /* DEVELOPMENT || DEBUG */
7888
7889 IOSimpleLockUnlock(sKextAccountsLock);
7890 if (freeAccount) {
7891 IOFreeType(freeAccount, OSKextAccount);
7892 }
7893
7894 /* Unwire and free the linked executable.
7895 */
7896 if (linkedExecutable) {
7897 #if KASAN
7898 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
7899 #endif
7900
7901 #if VM_MAPPED_KEXTS
7902 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
7903 kernel_segment_command_t *seg = NULL;
7904 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7905
7906 if (!kext_map) {
7907 OSKextLog(this,
7908 kOSKextLogErrorLevel |
7909 kOSKextLogLoadFlag,
7910 "Failed to free kext %s; couldn't find the kext map.",
7911 getIdentifierCString());
7912 result = kOSKextReturnInternalError;
7913 goto finish;
7914 }
7915
7916 OSKextLog(this,
7917 kOSKextLogProgressLevel |
7918 kOSKextLogLoadFlag,
7919 "Kext %s unwiring and unmapping linked executable.",
7920 getIdentifierCString());
7921
7922 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7923 while (seg) {
7924 if (segmentShouldBeWired(seg)) {
7925 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7926 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7927
7928 result = vm_map_unwire(kext_map, start_wire,
7929 end_wire, FALSE);
7930 if (result != KERN_SUCCESS) {
7931 OSKextLog(this,
7932 kOSKextLogErrorLevel |
7933 kOSKextLogLoadFlag,
7934 "Failed to unwire kext %s.",
7935 getIdentifierCString());
7936 result = kOSKextReturnInternalError;
7937 goto finish;
7938 }
7939 }
7940
7941 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7942 }
7943 #if defined(__x86_64__) || defined(__i386__)
7944 if (in_fileset && flags.resetSegmentsFromVnode) {
7945 IORecursiveLockLock(sKextLock);
7946 resetKCFileSetSegments();
7947 IORecursiveLockUnlock(sKextLock);
7948 }
7949 #endif // (__x86_64__) || defined(__i386__)
7950 }
7951 #endif /* VM_MAPPED_KEXTS */
7952 if (flags.resetSegmentsFromImmutableCopy) {
7953 result = resetMutableSegments();
7954 if (result != kOSReturnSuccess) {
7955 OSKextLog(this,
7956 kOSKextLogErrorLevel |
7957 kOSKextLogLoadFlag,
7958 "Failed to reset kext %s.",
7959 getIdentifierCString());
7960 result = kOSKextReturnInternalError;
7961 goto finish;
7962 }
7963 }
7964 if (kc_type == KCKindUnknown) {
7965 linkedExecutable.reset();
7966 }
7967 }
7968
7969 /* An interface kext has a fake kmod_info that was allocated,
7970 * so we have to free it.
7971 */
7972 if (isInterface()) {
7973 kfree_type(kmod_info_t, kmod_info);
7974 kmod_info = NULL;
7975 }
7976
7977 if (!in_fileset) {
7978 kmod_info = NULL;
7979 }
7980
7981 flags.loaded = false;
7982 flushDependencies();
7983
7984 /* save a copy of the bundle ID for us to check when deciding to
7985 * rebuild the kernel cache file. If a kext was already in the kernel
7986 * cache and unloaded then later loaded we do not need to rebuild the
7987 * kernel cache. 9055303
7988 */
7989 if (isPrelinked()) {
7990 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
7991 IORecursiveLockLock(sKextLock);
7992 if (sUnloadedPrelinkedKexts) {
7993 sUnloadedPrelinkedKexts->setObject(bundleID.get());
7994 }
7995 IORecursiveLockUnlock(sKextLock);
7996 }
7997 }
7998
7999 OSKextLog(this,
8000 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8001 "Kext %s unloaded.", getIdentifierCString());
8002
8003 queueKextNotification(kKextRequestPredicateUnloadNotification,
8004 OSDynamicCast(OSString, bundleID.get()));
8005
8006 finish:
8007 OSKext::saveLoadedKextPanicList();
8008 OSKext::updateLoadedKextSummaries();
8009
8010 flags.unloading = 0;
8011 return result;
8012 }
8013
8014 /*********************************************************************
8015 * Assumes sKextLock is held.
8016 *********************************************************************/
8017 /* static */
8018 OSReturn
8019 OSKext::queueKextNotification(
8020 const char * notificationName,
8021 OSString * kextIdentifier)
8022 {
8023 OSReturn result = kOSReturnError;
8024 OSSharedPtr<OSDictionary> loadRequest;
8025
8026 if (!kextIdentifier) {
8027 result = kOSKextReturnInvalidArgument;
8028 goto finish;
8029 }
8030
8031 /* Create a new request unless one is already sitting
8032 * in sKernelRequests for this bundle identifier
8033 */
8034 result = _OSKextCreateRequest(notificationName, loadRequest);
8035 if (result != kOSReturnSuccess) {
8036 goto finish;
8037 }
8038 if (!_OSKextSetRequestArgument(loadRequest.get(),
8039 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8040 result = kOSKextReturnNoMemory;
8041 goto finish;
8042 }
8043 if (!sKernelRequests->setObject(loadRequest.get())) {
8044 result = kOSKextReturnNoMemory;
8045 goto finish;
8046 }
8047
8048 /* We might want to only queue the notification if the IOKit daemon is active,
8049 * but that wouldn't work for embedded. Note that we don't care if
8050 * the ping immediately succeeds here so don't do anything with the
8051 * result of this call.
8052 */
8053 OSKext::pingIOKitDaemon();
8054
8055 result = kOSReturnSuccess;
8056
8057 finish:
8058 return result;
8059 }
8060
8061
8062 #if CONFIG_KXLD
8063 /*********************************************************************
8064 *********************************************************************/
8065 static void
8066 _OSKextConsiderDestroyingLinkContext(
8067 __unused thread_call_param_t p0,
8068 __unused thread_call_param_t p1)
8069 {
8070 /* Take multiple locks in the correct order.
8071 */
8072 IORecursiveLockLock(sKextLock);
8073 IORecursiveLockLock(sKextInnerLock);
8074
8075 /* The first time we destroy the kxldContext is in the first
8076 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8077 * before calling this function. Thereafter any call to this function
8078 * will actually destroy the context.
8079 */
8080 if (sConsiderUnloadsCalled && sKxldContext) {
8081 kxld_destroy_context(sKxldContext);
8082 sKxldContext = NULL;
8083 }
8084
8085 /* Free the thread_call that was allocated to execute this function.
8086 */
8087 if (sDestroyLinkContextThread) {
8088 if (!thread_call_free(sDestroyLinkContextThread)) {
8089 OSKextLog(/* kext */ NULL,
8090 kOSKextLogErrorLevel |
8091 kOSKextLogGeneralFlag,
8092 "thread_call_free() failed for kext link context.");
8093 }
8094 sDestroyLinkContextThread = NULL;
8095 }
8096
8097 IORecursiveLockUnlock(sKextInnerLock);
8098 IORecursiveLockUnlock(sKextLock);
8099
8100 return;
8101 }
8102
8103 /*********************************************************************
8104 * Destroying the kxldContext requires checking variables under both
8105 * sKextInnerLock and sKextLock, so we do it on a separate thread
8106 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8107 * call relationship.
8108 *
8109 * This function must be invoked with sKextInnerLock held.
8110 * Do not call any function that takes sKextLock here!
8111 *********************************************************************/
8112 /* static */
8113 void
8114 OSKext::considerDestroyingLinkContext(void)
8115 {
8116 IORecursiveLockLock(sKextInnerLock);
8117
8118 /* If we have already queued a thread to destroy the link context,
8119 * don't bother resetting; that thread will take care of it.
8120 */
8121 if (sDestroyLinkContextThread) {
8122 goto finish;
8123 }
8124
8125 /* The function to be invoked in the thread will deallocate
8126 * this thread_call, so don't share it around.
8127 */
8128 sDestroyLinkContextThread = thread_call_allocate(
8129 &_OSKextConsiderDestroyingLinkContext, NULL);
8130 if (!sDestroyLinkContextThread) {
8131 OSKextLog(/* kext */ NULL,
8132 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8133 "Can't create thread to destroy kext link context.");
8134 goto finish;
8135 }
8136
8137 thread_call_enter(sDestroyLinkContextThread);
8138
8139 finish:
8140 IORecursiveLockUnlock(sKextInnerLock);
8141 return;
8142 }
8143
8144 #else // !CONFIG_KXLD
8145
8146 /* static */
8147 void
8148 OSKext::considerDestroyingLinkContext(void)
8149 {
8150 return;
8151 }
8152
8153 #endif // CONFIG_KXLD
8154
8155 #if PRAGMA_MARK
8156 #pragma mark Autounload
8157 #endif
8158 /*********************************************************************
8159 * This is a static method because the kext will be deallocated if it
8160 * does unload!
8161 *********************************************************************/
8162 /* static */
8163 OSReturn
8164 OSKext::autounloadKext(OSKext * aKext)
8165 {
8166 OSReturn result = kOSKextReturnInUse;
8167
8168 #if NO_KEXTD
8169 /*
8170 * Do not unload prelinked kexts on platforms that do not have an
8171 * IOKit daemon as there is no way to reload the kext or restart
8172 * matching.
8173 */
8174 if (aKext->isPrelinked()) {
8175 goto finish;
8176 }
8177 #endif /* defined(__x86_64__) */
8178
8179 /* Check for external references to this kext (usu. dependents),
8180 * instances of defined classes (or classes derived from them),
8181 * outstanding requests.
8182 */
8183 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8184 !aKext->flags.autounloadEnabled ||
8185 aKext->isKernelComponent()) {
8186 goto finish;
8187 }
8188
8189 /* Skip a delay-autounload kext, once.
8190 */
8191 if (aKext->flags.delayAutounload) {
8192 OSKextLog(aKext,
8193 kOSKextLogProgressLevel |
8194 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8195 "Kext %s has delayed autounload set; skipping and clearing flag.",
8196 aKext->getIdentifierCString());
8197 aKext->flags.delayAutounload = 0;
8198 goto finish;
8199 }
8200
8201 if (aKext->hasOSMetaClassInstances() ||
8202 aKext->countRequestCallbacks()) {
8203 goto finish;
8204 }
8205
8206 result = OSKext::removeKext(aKext);
8207
8208 finish:
8209 return result;
8210 }
8211
8212 /*********************************************************************
8213 *********************************************************************/
8214 void
8215 _OSKextConsiderUnloads(
8216 __unused thread_call_param_t p0,
8217 __unused thread_call_param_t p1)
8218 {
8219 bool didUnload = false;
8220 unsigned int count, i;
8221
8222 /* Take multiple locks in the correct order
8223 * (note also sKextSummaries lock further down).
8224 */
8225 IORecursiveLockLock(sKextLock);
8226 IORecursiveLockLock(sKextInnerLock);
8227
8228 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8229
8230 /* If the system is powering down, don't try to unload anything.
8231 */
8232 if (sSystemSleep) {
8233 goto finish;
8234 }
8235
8236 OSKextLog(/* kext */ NULL,
8237 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8238 "Checking for unused kexts to autounload.");
8239
8240 /*****
8241 * Remove any request callbacks marked as stale,
8242 * and mark as stale any currently in flight.
8243 */
8244 count = sRequestCallbackRecords->getCount();
8245 if (count) {
8246 i = count - 1;
8247 do {
8248 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8249 sRequestCallbackRecords->getObject(i));
8250 OSBoolean * stale = OSDynamicCast(OSBoolean,
8251 callbackRecord->getObject(kKextRequestStaleKey));
8252
8253 if (stale == kOSBooleanTrue) {
8254 OSKext::invokeRequestCallback(callbackRecord,
8255 kOSKextReturnTimeout);
8256 } else {
8257 callbackRecord->setObject(kKextRequestStaleKey,
8258 kOSBooleanTrue);
8259 }
8260 } while (i--);
8261 }
8262
8263 /*****
8264 * Make multiple passes through the array of loaded kexts until
8265 * we don't unload any. This handles unwinding of dependency
8266 * chains. We have to go *backwards* through the array because
8267 * kexts are removed from it when unloaded, and we cannot make
8268 * a copy or we'll mess up the retain counts we rely on to
8269 * check whether a kext will unload. If only we could have
8270 * nonretaining collections like CF has....
8271 */
8272 do {
8273 didUnload = false;
8274
8275 count = sLoadedKexts->getCount();
8276 if (count) {
8277 i = count - 1;
8278 do {
8279 OSKext * thisKext = OSDynamicCast(OSKext,
8280 sLoadedKexts->getObject(i));
8281 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8282 } while (i--);
8283 }
8284 } while (didUnload);
8285
8286 finish:
8287 sConsiderUnloadsPending = false;
8288 sConsiderUnloadsExecuted = true;
8289
8290 (void) OSKext::considerRebuildOfPrelinkedKernel();
8291
8292 IORecursiveLockUnlock(sKextInnerLock);
8293 IORecursiveLockUnlock(sKextLock);
8294
8295 return;
8296 }
8297
8298 /*********************************************************************
8299 * Do not call any function that takes sKextLock here!
8300 *********************************************************************/
8301 void
8302 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8303 {
8304 AbsoluteTime when;
8305
8306 IORecursiveLockLock(sKextInnerLock);
8307
8308 if (!sUnloadCallout) {
8309 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8310 }
8311
8312 /* we only reset delay value for unloading if we already have something
8313 * pending. rescheduleOnlyFlag should not start the count down.
8314 */
8315 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8316 goto finish;
8317 }
8318
8319 thread_call_cancel(sUnloadCallout);
8320 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8321 #if !NO_KEXTD
8322 && sIOKitDaemonActive
8323 #endif
8324 ) {
8325 clock_interval_to_deadline(sConsiderUnloadDelay,
8326 1000 * 1000 * 1000, &when);
8327
8328 OSKextLog(/* kext */ NULL,
8329 kOSKextLogProgressLevel |
8330 kOSKextLogLoadFlag,
8331 "%scheduling %sscan for unused kexts in %lu seconds.",
8332 sConsiderUnloadsPending ? "Res" : "S",
8333 sConsiderUnloadsCalled ? "" : "initial ",
8334 (unsigned long)sConsiderUnloadDelay);
8335
8336 sConsiderUnloadsPending = true;
8337 thread_call_enter_delayed(sUnloadCallout, when);
8338 }
8339
8340 finish:
8341 /* The kxld context should be reused throughout boot. We mark the end of
8342 * period as the first time considerUnloads() is called, and we destroy
8343 * the first kxld context in that function. Afterwards, it will be
8344 * destroyed in flushNonloadedKexts.
8345 */
8346 if (!sConsiderUnloadsCalled) {
8347 sConsiderUnloadsCalled = true;
8348 OSKext::considerDestroyingLinkContext();
8349 }
8350
8351 IORecursiveLockUnlock(sKextInnerLock);
8352 return;
8353 }
8354
8355 /*********************************************************************
8356 * Do not call any function that takes sKextLock here!
8357 *********************************************************************/
8358 extern "C" {
8359 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
8360 IOReturn
8361 OSKextSystemSleepOrWake(UInt32 messageType)
8362 {
8363 IORecursiveLockLock(sKextInnerLock);
8364
8365 /* If the system is going to sleep, cancel the reaper thread timer,
8366 * and note that we're in a sleep state in case it just fired but hasn't
8367 * taken the lock yet. If we are coming back from sleep, just
8368 * clear the sleep flag; IOService's normal operation will cause
8369 * unloads to be considered soon enough.
8370 */
8371 if (messageType == kIOMessageSystemWillSleep) {
8372 if (sUnloadCallout) {
8373 thread_call_cancel(sUnloadCallout);
8374 }
8375 sSystemSleep = true;
8376 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8377 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8378 sSystemSleep = false;
8379 clock_get_uptime(&sLastWakeTime);
8380 }
8381 IORecursiveLockUnlock(sKextInnerLock);
8382
8383 return kIOReturnSuccess;
8384 }
8385 };
8386
8387
8388 #if PRAGMA_MARK
8389 #pragma mark Prelinked Kernel
8390 #endif
8391
8392 #ifdef CONFIG_KXLD
8393 /*********************************************************************
8394 * Do not access sConsiderUnloads... variables other than
8395 * sConsiderUnloadsExecuted in this function. They are guarded by a
8396 * different lock.
8397 *********************************************************************/
8398 /* static */
8399 void
8400 OSKext::considerRebuildOfPrelinkedKernel(void)
8401 {
8402 static bool requestedPrelink = false;
8403 OSReturn checkResult = kOSReturnError;
8404 OSSharedPtr<OSDictionary> prelinkRequest;
8405 OSSharedPtr<OSCollectionIterator> kextIterator;
8406 const OSSymbol * thisID = NULL; // do not release
8407 bool doRebuild = false;
8408 AbsoluteTime my_abstime;
8409 UInt64 my_ns;
8410 SInt32 delta_secs;
8411
8412 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8413 if (requestedPrelink || !sPrelinkBoot) {
8414 return;
8415 }
8416
8417 /* no direct return from this point */
8418 IORecursiveLockLock(sKextLock);
8419
8420 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8421 * and any new startup kexts loaded.
8422 */
8423 if (!sConsiderUnloadsExecuted ||
8424 !sDeferredLoadSucceeded) {
8425 goto finish;
8426 }
8427
8428 /* we really only care about boot / system start up related kexts so bail
8429 * if we're here after REBUILD_MAX_TIME.
8430 */
8431 if (!_OSKextInPrelinkRebuildWindow()) {
8432 OSKextLog(/* kext */ NULL,
8433 kOSKextLogArchiveFlag,
8434 "%s prebuild rebuild has expired",
8435 __FUNCTION__);
8436 requestedPrelink = true;
8437 goto finish;
8438 }
8439
8440 /* we do not want to trigger a rebuild if we get here too close to waking
8441 * up. (see radar 10233768)
8442 */
8443 IORecursiveLockLock(sKextInnerLock);
8444
8445 clock_get_uptime(&my_abstime);
8446 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8447 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8448 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8449 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8450 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8451 }
8452 IORecursiveLockUnlock(sKextInnerLock);
8453
8454 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8455 /* too close to time of last wake from sleep */
8456 goto finish;
8457 }
8458 requestedPrelink = true;
8459
8460 /* Now it's time to see if we have a reason to rebuild. We may have done
8461 * some loads and unloads but the kernel cache didn't actually change.
8462 * We will rebuild if any kext is not marked prelinked AND is not in our
8463 * list of prelinked kexts that got unloaded. (see radar 9055303)
8464 */
8465 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
8466 if (!kextIterator) {
8467 goto finish;
8468 }
8469
8470 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
8471 OSKext * thisKext; // do not release
8472
8473 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8474 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8475 continue;
8476 }
8477
8478 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
8479 continue;
8480 }
8481 /* kext is loaded and was not in current kernel cache so let's rebuild
8482 */
8483 doRebuild = true;
8484 OSKextLog(/* kext */ NULL,
8485 kOSKextLogArchiveFlag,
8486 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8487 thisKext->bundleID->getCStringNoCopy());
8488 break;
8489 }
8490 sUnloadedPrelinkedKexts->flushCollection();
8491
8492 if (!doRebuild) {
8493 goto finish;
8494 }
8495
8496 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
8497 prelinkRequest);
8498 if (checkResult != kOSReturnSuccess) {
8499 goto finish;
8500 }
8501
8502 if (!sKernelRequests->setObject(prelinkRequest.get())) {
8503 goto finish;
8504 }
8505
8506 OSKext::pingIOKitDaemon();
8507
8508 finish:
8509 IORecursiveLockUnlock(sKextLock);
8510
8511 return;
8512 }
8513
8514 #else /* !CONFIG_KXLD */
8515
8516 void
8517 OSKext::considerRebuildOfPrelinkedKernel(void)
8518 {
8519 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8520 return;
8521 }
8522
8523 #endif /* CONFIG_KXLD */
8524
8525 #if PRAGMA_MARK
8526 #pragma mark Dependencies
8527 #endif
8528 /*********************************************************************
8529 *********************************************************************/
8530 bool
8531 OSKext::resolveDependencies(
8532 OSArray * loopStack)
8533 {
8534 bool result = false;
8535 OSSharedPtr<OSArray> localLoopStack;
8536 bool addedToLoopStack = false;
8537 OSDictionary * libraries = NULL; // do not release
8538 OSSharedPtr<OSCollectionIterator> libraryIterator;
8539 OSString * libraryID = NULL; // do not release
8540 OSKext * libraryKext = NULL; // do not release
8541 bool hasRawKernelDependency = false;
8542 bool hasKernelDependency = false;
8543 bool hasKPIDependency = false;
8544 bool hasPrivateKPIDependency = false;
8545 unsigned int count;
8546
8547 #if CONFIG_KXLD
8548 OSString * infoString = NULL; // do not release
8549 OSString * readableString = NULL; // do not release
8550 #endif // CONFIG_KXLD
8551
8552 /* A kernel component will automatically have this flag set,
8553 * and a loaded kext should also have it set (as should all its
8554 * loaded dependencies).
8555 */
8556 if (flags.hasAllDependencies) {
8557 result = true;
8558 goto finish;
8559 }
8560
8561 /* Check for loops in the dependency graph.
8562 */
8563 if (loopStack) {
8564 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8565 OSKextLog(this,
8566 kOSKextLogErrorLevel |
8567 kOSKextLogDependenciesFlag,
8568 "Kext %s has a dependency loop; can't resolve dependencies.",
8569 getIdentifierCString());
8570 goto finish;
8571 }
8572 } else {
8573 OSKextLog(this,
8574 kOSKextLogStepLevel |
8575 kOSKextLogDependenciesFlag,
8576 "Kext %s resolving dependencies.",
8577 getIdentifierCString());
8578
8579 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8580 if (!localLoopStack) {
8581 OSKextLog(this,
8582 kOSKextLogErrorLevel |
8583 kOSKextLogDependenciesFlag,
8584 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8585 getIdentifierCString());
8586 goto finish;
8587 }
8588 loopStack = localLoopStack.get();
8589 }
8590 if (!loopStack->setObject(this)) {
8591 OSKextLog(this,
8592 kOSKextLogErrorLevel |
8593 kOSKextLogDependenciesFlag,
8594 "Kext %s - internal error resolving dependencies.",
8595 getIdentifierCString());
8596 goto finish;
8597 }
8598 addedToLoopStack = true;
8599
8600 /* Purge any existing kexts in the dependency list and start over.
8601 */
8602 flushDependencies();
8603 if (dependencies) {
8604 OSKextLog(this,
8605 kOSKextLogErrorLevel |
8606 kOSKextLogDependenciesFlag,
8607 "Kext %s - internal error resolving dependencies.",
8608 getIdentifierCString());
8609 }
8610
8611 libraries = OSDynamicCast(OSDictionary,
8612 getPropertyForHostArch(kOSBundleLibrariesKey));
8613 if (libraries == NULL || libraries->getCount() == 0) {
8614 OSKextLog(this,
8615 kOSKextLogErrorLevel |
8616 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8617 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8618 getIdentifierCString(), kOSBundleLibrariesKey);
8619 goto finish;
8620 }
8621
8622 /* Make a new array to hold the dependencies (flush freed the old one).
8623 */
8624 dependencies = OSArray::withCapacity(libraries->getCount());
8625 if (!dependencies) {
8626 OSKextLog(this,
8627 kOSKextLogErrorLevel |
8628 kOSKextLogDependenciesFlag,
8629 "Kext %s - can't allocate dependencies array.",
8630 getIdentifierCString());
8631 goto finish;
8632 }
8633
8634 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8635 // xxx - compat: if none were declared.
8636
8637 libraryIterator = OSCollectionIterator::withCollection(libraries);
8638 if (!libraryIterator) {
8639 OSKextLog(this,
8640 kOSKextLogErrorLevel |
8641 kOSKextLogDependenciesFlag,
8642 "Kext %s - can't allocate dependencies iterator.",
8643 getIdentifierCString());
8644 goto finish;
8645 }
8646
8647 while ((libraryID = OSDynamicCast(OSString,
8648 libraryIterator->getNextObject()))) {
8649 const char * library_id = libraryID->getCStringNoCopy();
8650
8651 OSString * libraryVersion = OSDynamicCast(OSString,
8652 libraries->getObject(libraryID));
8653 if (libraryVersion == NULL) {
8654 OSKextLog(this,
8655 kOSKextLogErrorLevel |
8656 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8657 "Kext %s - illegal type in OSBundleLibraries.",
8658 getIdentifierCString());
8659 goto finish;
8660 }
8661
8662 OSKextVersion libraryVers =
8663 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8664 if (libraryVers == -1) {
8665 OSKextLog(this,
8666 kOSKextLogErrorLevel |
8667 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8668 "Kext %s - invalid library version %s.",
8669 getIdentifierCString(),
8670 libraryVersion->getCStringNoCopy());
8671 goto finish;
8672 }
8673
8674 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8675 if (libraryKext == NULL) {
8676 OSKextLog(this,
8677 kOSKextLogErrorLevel |
8678 kOSKextLogDependenciesFlag,
8679 "Kext %s - library kext %s not found.",
8680 getIdentifierCString(), library_id);
8681 goto finish;
8682 }
8683
8684 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8685 OSKextLog(this,
8686 kOSKextLogErrorLevel |
8687 kOSKextLogDependenciesFlag,
8688 "Kext %s - library kext %s not compatible "
8689 "with requested version %s.",
8690 getIdentifierCString(), library_id,
8691 libraryVersion->getCStringNoCopy());
8692 goto finish;
8693 }
8694
8695 /* If a nonprelinked library somehow got into the mix for a
8696 * prelinked kext, at any point in the chain, we must fail
8697 * because the prelinked relocs for the library will be all wrong.
8698 */
8699 if (this->isPrelinked() &&
8700 libraryKext->declaresExecutable() &&
8701 !libraryKext->isPrelinked()) {
8702 OSKextLog(this,
8703 kOSKextLogErrorLevel |
8704 kOSKextLogDependenciesFlag,
8705 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8706 getIdentifierCString(), library_id,
8707 libraryVersion->getCStringNoCopy());
8708 goto finish;
8709 }
8710
8711 if (!libraryKext->resolveDependencies(loopStack)) {
8712 goto finish;
8713 }
8714
8715 /* Add the library directly only if it has an executable to link.
8716 * Otherwise it's just used to collect other dependencies, so put
8717 * *its* dependencies on the list for this kext.
8718 */
8719 // xxx - We are losing info here; would like to make fake entries or
8720 // xxx - keep these in the dependency graph for loaded kexts.
8721 // xxx - I really want to make kernel components not a special case!
8722 if (libraryKext->declaresExecutable() ||
8723 libraryKext->isInterface()) {
8724 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8725 dependencies->setObject(libraryKext);
8726
8727 OSKextLog(this,
8728 kOSKextLogDetailLevel |
8729 kOSKextLogDependenciesFlag,
8730 "Kext %s added dependency %s.",
8731 getIdentifierCString(),
8732 libraryKext->getIdentifierCString());
8733 }
8734 } else {
8735 int numLibDependencies = libraryKext->getNumDependencies();
8736 OSArray * libraryDependencies = libraryKext->getDependencies();
8737 int index;
8738
8739 if (numLibDependencies) {
8740 // xxx - this msg level should be 1 lower than the per-kext one
8741 OSKextLog(this,
8742 kOSKextLogDetailLevel |
8743 kOSKextLogDependenciesFlag,
8744 "Kext %s pulling %d dependencies from codeless library %s.",
8745 getIdentifierCString(),
8746 numLibDependencies,
8747 libraryKext->getIdentifierCString());
8748 }
8749 for (index = 0; index < numLibDependencies; index++) {
8750 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8751 libraryDependencies->getObject(index));
8752 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8753 dependencies->setObject(thisLibDependency);
8754 OSKextLog(this,
8755 kOSKextLogDetailLevel |
8756 kOSKextLogDependenciesFlag,
8757 "Kext %s added dependency %s from codeless library %s.",
8758 getIdentifierCString(),
8759 thisLibDependency->getIdentifierCString(),
8760 libraryKext->getIdentifierCString());
8761 }
8762 }
8763 }
8764
8765 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8766 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8767 hasRawKernelDependency = true;
8768 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8769 hasKernelDependency = true;
8770 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8771 hasKPIDependency = true;
8772 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8773 hasPrivateKPIDependency = true;
8774 }
8775 }
8776 }
8777
8778 if (hasRawKernelDependency) {
8779 OSKextLog(this,
8780 kOSKextLogErrorLevel |
8781 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8782 "Error - kext %s declares a dependency on %s, which is not permitted.",
8783 getIdentifierCString(), KERNEL_LIB);
8784 goto finish;
8785 }
8786 #if __LP64__
8787 if (hasKernelDependency) {
8788 OSKextLog(this,
8789 kOSKextLogErrorLevel |
8790 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8791 "Error - kext %s declares %s dependencies. "
8792 "Only %s* dependencies are supported for 64-bit kexts.",
8793 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8794 goto finish;
8795 }
8796 if (!hasKPIDependency) {
8797 OSKextLog(this,
8798 kOSKextLogWarningLevel |
8799 kOSKextLogDependenciesFlag,
8800 "Warning - kext %s declares no %s* dependencies. "
8801 "If it uses any KPIs, the link may fail with undefined symbols.",
8802 getIdentifierCString(), KPI_LIB_PREFIX);
8803 }
8804 #else /* __LP64__ */
8805 // xxx - will change to flatly disallow "kernel" dependencies at some point
8806 // xxx - is it invalid to do both "com.apple.kernel" and any
8807 // xxx - "com.apple.kernel.*"?
8808
8809 if (hasKernelDependency && hasKPIDependency) {
8810 OSKextLog(this,
8811 kOSKextLogWarningLevel |
8812 kOSKextLogDependenciesFlag,
8813 "Warning - kext %s has immediate dependencies on both "
8814 "%s* and %s* components; use only one style.",
8815 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8816 }
8817
8818 if (!hasKernelDependency && !hasKPIDependency) {
8819 // xxx - do we want to use validation flag for these too?
8820 OSKextLog(this,
8821 kOSKextLogWarningLevel |
8822 kOSKextLogDependenciesFlag,
8823 "Warning - %s declares no kernel dependencies; using %s.",
8824 getIdentifierCString(), KERNEL6_LIB);
8825 OSKext * kernelKext = OSDynamicCast(OSKext,
8826 sKextsByID->getObject(KERNEL6_LIB));
8827 if (kernelKext) {
8828 dependencies->setObject(kernelKext);
8829 } else {
8830 OSKextLog(this,
8831 kOSKextLogErrorLevel |
8832 kOSKextLogDependenciesFlag,
8833 "Error - Library %s not found for %s.",
8834 KERNEL6_LIB, getIdentifierCString());
8835 }
8836 }
8837
8838 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8839 * its indirect dependencies to simulate old-style linking. XXX - Should
8840 * check for duplicates.
8841 */
8842 if (!hasKPIDependency) {
8843 unsigned int i;
8844
8845 flags.hasBleedthrough = true;
8846
8847 count = getNumDependencies();
8848
8849 /* We add to the dependencies array in this loop, but do not iterate
8850 * past its original count.
8851 */
8852 for (i = 0; i < count; i++) {
8853 OSKext * dependencyKext = OSDynamicCast(OSKext,
8854 dependencies->getObject(i));
8855 dependencyKext->addBleedthroughDependencies(dependencies.get());
8856 }
8857 }
8858 #endif /* __LP64__ */
8859
8860 #if CONFIG_KXLD
8861 /*
8862 * If we're not dynamically linking kexts, then we don't need to check
8863 * copyright strings. The linker in user space has already done this.
8864 */
8865 if (hasPrivateKPIDependency) {
8866 bool hasApplePrefix = false;
8867 bool infoCopyrightIsValid = false;
8868 bool readableCopyrightIsValid = false;
8869
8870 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8871 APPLE_KEXT_PREFIX);
8872
8873 infoString = OSDynamicCast(OSString,
8874 getPropertyForHostArch("CFBundleGetInfoString"));
8875 if (infoString) {
8876 infoCopyrightIsValid =
8877 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8878 }
8879
8880 readableString = OSDynamicCast(OSString,
8881 getPropertyForHostArch("NSHumanReadableCopyright"));
8882 if (readableString) {
8883 readableCopyrightIsValid =
8884 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8885 }
8886
8887 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8888 OSKextLog(this,
8889 kOSKextLogErrorLevel |
8890 kOSKextLogDependenciesFlag,
8891 "Error - kext %s declares a dependency on %s. "
8892 "Only Apple kexts may declare a dependency on %s.",
8893 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8894 goto finish;
8895 }
8896 }
8897 #endif // CONFIG_KXLD
8898
8899 result = true;
8900 flags.hasAllDependencies = 1;
8901
8902 finish:
8903
8904 if (addedToLoopStack) {
8905 count = loopStack->getCount();
8906 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8907 loopStack->removeObject(count - 1);
8908 } else {
8909 OSKextLog(this,
8910 kOSKextLogErrorLevel |
8911 kOSKextLogDependenciesFlag,
8912 "Kext %s - internal error resolving dependencies.",
8913 getIdentifierCString());
8914 }
8915 }
8916
8917 if (result && localLoopStack) {
8918 OSKextLog(this,
8919 kOSKextLogStepLevel |
8920 kOSKextLogDependenciesFlag,
8921 "Kext %s successfully resolved dependencies.",
8922 getIdentifierCString());
8923 }
8924
8925 return result;
8926 }
8927
8928 /*********************************************************************
8929 *********************************************************************/
8930 bool
8931 OSKext::addBleedthroughDependencies(OSArray * anArray)
8932 {
8933 bool result = false;
8934 unsigned int dependencyIndex, dependencyCount;
8935
8936 dependencyCount = getNumDependencies();
8937
8938 for (dependencyIndex = 0;
8939 dependencyIndex < dependencyCount;
8940 dependencyIndex++) {
8941 OSKext * dependency = OSDynamicCast(OSKext,
8942 dependencies->getObject(dependencyIndex));
8943 if (!dependency) {
8944 OSKextLog(this,
8945 kOSKextLogErrorLevel |
8946 kOSKextLogDependenciesFlag,
8947 "Kext %s - internal error propagating compatibility dependencies.",
8948 getIdentifierCString());
8949 goto finish;
8950 }
8951 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8952 anArray->setObject(dependency);
8953 }
8954 dependency->addBleedthroughDependencies(anArray);
8955 }
8956
8957 result = true;
8958
8959 finish:
8960 return result;
8961 }
8962
8963 /*********************************************************************
8964 *********************************************************************/
8965 bool
8966 OSKext::flushDependencies(bool forceFlag)
8967 {
8968 bool result = false;
8969
8970 /* Only clear the dependencies if the kext isn't loaded;
8971 * we need the info for loaded kexts to track references.
8972 */
8973 if (!isLoaded() || forceFlag) {
8974 if (dependencies) {
8975 // xxx - check level
8976 OSKextLog(this,
8977 kOSKextLogProgressLevel |
8978 kOSKextLogDependenciesFlag,
8979 "Kext %s flushing dependencies.",
8980 getIdentifierCString());
8981 dependencies.reset();
8982 }
8983 if (!isKernelComponent()) {
8984 flags.hasAllDependencies = 0;
8985 }
8986 result = true;
8987 }
8988
8989 return result;
8990 }
8991
8992 /*********************************************************************
8993 *********************************************************************/
8994 uint32_t
8995 OSKext::getNumDependencies(void)
8996 {
8997 if (!dependencies) {
8998 return 0;
8999 }
9000 return dependencies->getCount();
9001 }
9002
9003 /*********************************************************************
9004 *********************************************************************/
9005 OSArray *
9006 OSKext::getDependencies(void)
9007 {
9008 return dependencies.get();
9009 }
9010
9011 bool
9012 OSKext::hasDependency(const OSSymbol * depID)
9013 {
9014 bool result __block;
9015
9016 if (depID == getIdentifier()) {
9017 return true;
9018 }
9019 if (!dependencies) {
9020 return false;
9021 }
9022 result = false;
9023 dependencies->iterateObjects(^bool (OSObject * obj) {
9024 OSKext * kext;
9025 kext = OSDynamicCast(OSKext, obj);
9026 if (!kext) {
9027 return false;
9028 }
9029 result = (depID == kext->getIdentifier());
9030 return result;
9031 });
9032 return result;
9033 }
9034
9035 #if PRAGMA_MARK
9036 #pragma mark OSMetaClass Support
9037 #endif
9038 /*********************************************************************
9039 *********************************************************************/
9040 OSReturn
9041 OSKext::addClass(
9042 OSMetaClass * aClass,
9043 uint32_t numClasses)
9044 {
9045 OSReturn result = kOSMetaClassNoInsKModSet;
9046
9047 if (!metaClasses) {
9048 metaClasses = OSSet::withCapacity(numClasses);
9049 if (!metaClasses) {
9050 goto finish;
9051 }
9052 }
9053
9054 if (metaClasses->containsObject(aClass)) {
9055 OSKextLog(this,
9056 kOSKextLogWarningLevel |
9057 kOSKextLogLoadFlag,
9058 "Notice - kext %s has already registered class %s.",
9059 getIdentifierCString(),
9060 aClass->getClassName());
9061 result = kOSReturnSuccess;
9062 goto finish;
9063 }
9064
9065 if (!metaClasses->setObject(aClass)) {
9066 goto finish;
9067 } else {
9068 OSKextLog(this,
9069 kOSKextLogDetailLevel |
9070 kOSKextLogLoadFlag,
9071 "Kext %s registered class %s.",
9072 getIdentifierCString(),
9073 aClass->getClassName());
9074 }
9075
9076 if (!flags.autounloadEnabled) {
9077 const OSMetaClass * metaScan = NULL; // do not release
9078
9079 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9080 if (metaScan == OSTypeID(IOService)) {
9081 OSKextLog(this,
9082 kOSKextLogProgressLevel |
9083 kOSKextLogLoadFlag,
9084 "Kext %s has IOService subclass %s; enabling autounload.",
9085 getIdentifierCString(),
9086 aClass->getClassName());
9087
9088 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9089 break;
9090 }
9091 }
9092 }
9093
9094 notifyAddClassObservers(this, aClass, flags);
9095
9096 result = kOSReturnSuccess;
9097
9098 finish:
9099 if (result != kOSReturnSuccess) {
9100 OSKextLog(this,
9101 kOSKextLogErrorLevel |
9102 kOSKextLogLoadFlag,
9103 "Kext %s failed to register class %s.",
9104 getIdentifierCString(),
9105 aClass->getClassName());
9106 }
9107
9108 return result;
9109 }
9110
9111 /*********************************************************************
9112 *********************************************************************/
9113 OSReturn
9114 OSKext::removeClass(
9115 OSMetaClass * aClass)
9116 {
9117 OSReturn result = kOSMetaClassNoKModSet;
9118
9119 if (!metaClasses) {
9120 goto finish;
9121 }
9122
9123 if (!metaClasses->containsObject(aClass)) {
9124 OSKextLog(this,
9125 kOSKextLogWarningLevel |
9126 kOSKextLogLoadFlag,
9127 "Notice - kext %s asked to unregister unknown class %s.",
9128 getIdentifierCString(),
9129 aClass->getClassName());
9130 result = kOSReturnSuccess;
9131 goto finish;
9132 }
9133
9134 OSKextLog(this,
9135 kOSKextLogDetailLevel |
9136 kOSKextLogLoadFlag,
9137 "Kext %s unregistering class %s.",
9138 getIdentifierCString(),
9139 aClass->getClassName());
9140
9141 metaClasses->removeObject(aClass);
9142
9143 notifyRemoveClassObservers(this, aClass, flags);
9144
9145 result = kOSReturnSuccess;
9146
9147 finish:
9148 if (result != kOSReturnSuccess) {
9149 OSKextLog(this,
9150 kOSKextLogErrorLevel |
9151 kOSKextLogLoadFlag,
9152 "Failed to unregister kext %s class %s.",
9153 getIdentifierCString(),
9154 aClass->getClassName());
9155 }
9156 return result;
9157 }
9158
9159 /*********************************************************************
9160 *********************************************************************/
9161 OSSet *
9162 OSKext::getMetaClasses(void)
9163 {
9164 return metaClasses.get();
9165 }
9166
9167 /*********************************************************************
9168 *********************************************************************/
9169 bool
9170 OSKext::hasOSMetaClassInstances(void)
9171 {
9172 bool result = false;
9173 OSSharedPtr<OSCollectionIterator> classIterator;
9174 OSMetaClass * checkClass = NULL; // do not release
9175
9176 if (!metaClasses) {
9177 goto finish;
9178 }
9179
9180 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9181 if (!classIterator) {
9182 // xxx - log alloc failure?
9183 goto finish;
9184 }
9185 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9186 if (checkClass->getInstanceCount()) {
9187 result = true;
9188 goto finish;
9189 }
9190 }
9191
9192 finish:
9193 return result;
9194 }
9195
9196 /*********************************************************************
9197 *********************************************************************/
9198 /* static */
9199 void
9200 OSKext::reportOSMetaClassInstances(
9201 const char * kextIdentifier,
9202 OSKextLogSpec msgLogSpec)
9203 {
9204 OSSharedPtr<OSKext> theKext;
9205
9206 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9207 if (!theKext) {
9208 goto finish;
9209 }
9210
9211 theKext->reportOSMetaClassInstances(msgLogSpec);
9212 finish:
9213 return;
9214 }
9215
9216 /*********************************************************************
9217 *********************************************************************/
9218 void
9219 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9220 {
9221 OSSharedPtr<OSCollectionIterator> classIterator;
9222 OSMetaClass * checkClass = NULL; // do not release
9223
9224 if (!metaClasses) {
9225 goto finish;
9226 }
9227
9228 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9229 if (!classIterator) {
9230 goto finish;
9231 }
9232 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9233 if (checkClass->getInstanceCount()) {
9234 OSKextLog(this,
9235 msgLogSpec,
9236 " Kext %s class %s has %d instance%s.",
9237 getIdentifierCString(),
9238 checkClass->getClassName(),
9239 checkClass->getInstanceCount(),
9240 checkClass->getInstanceCount() == 1 ? "" : "s");
9241 }
9242 }
9243
9244 finish:
9245 return;
9246 }
9247
9248 #if PRAGMA_MARK
9249 #pragma mark User-Space Requests
9250 #endif
9251
9252 static kern_return_t
9253 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9254 {
9255 OSReturn result = kOSReturnSuccess;
9256 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9257 OSDictionary * request = NULL; //do not release
9258 IOUserServerCheckInToken * token = NULL; //do not release
9259 OSString * requestPredicate = NULL; //do not release
9260 OSSharedPtr<OSNumber> portNameNumber;
9261 mach_port_name_t portName = 0;
9262 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9263 if (!request) {
9264 OSKextLog(/* kext */ NULL,
9265 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9266 "Elements of request should be of type OSDictionary");
9267 result = kOSKextReturnInternalError;
9268 goto finish;
9269 }
9270 requestPredicate = _OSKextGetRequestPredicate(request);
9271 if (!requestPredicate) {
9272 OSKextLog(/* kext */ NULL,
9273 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9274 "Failed to get request predicate");
9275 result = kOSKextReturnInternalError;
9276 goto finish;
9277 }
9278 // is this a dext launch?
9279 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9280 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9281 if (!token) {
9282 OSKextLog(/* kext */ NULL,
9283 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9284 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9285 result = kOSKextReturnInternalError;
9286 goto finish;
9287 }
9288 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9289 if (portName == 0 || portName == MACH_PORT_DEAD) {
9290 OSKextLog(/* kext */ NULL,
9291 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9292 "Could not create send right for object.");
9293 result = kOSKextReturnInternalError;
9294 goto finish;
9295 }
9296 // Store the mach port name as a OSNumber
9297 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9298 if (!portNameNumber) {
9299 OSKextLog(/* kext */ NULL,
9300 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9301 "Could not create OSNumber object.");
9302 result = kOSKextReturnNoMemory;
9303 goto finish;
9304 }
9305 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9306 OSKextLog(/* kext */ NULL,
9307 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9308 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9309 result = kOSKextReturnNoMemory;
9310 goto finish;
9311 }
9312 }
9313 finish:
9314 if (result != kOSReturnSuccess) {
9315 break;
9316 }
9317 }
9318 return result;
9319 }
9320
9321 /*********************************************************************
9322 * XXX - this function is a big ugly mess
9323 *********************************************************************/
9324 /* static */
9325 OSReturn
9326 OSKext::handleRequest(
9327 host_priv_t hostPriv,
9328 OSKextLogSpec clientLogFilter,
9329 char * requestBuffer,
9330 uint32_t requestLength,
9331 char ** responseOut,
9332 uint32_t * responseLengthOut,
9333 char ** logInfoOut,
9334 uint32_t * logInfoLengthOut)
9335 {
9336 OSReturn result = kOSReturnError;
9337 kern_return_t kmem_result = KERN_FAILURE;
9338
9339 char * response = NULL; // returned by reference
9340 uint32_t responseLength = 0;
9341
9342 bool taskCanManageAllKCs = false;
9343 bool taskOnlyManagesBootKC = false;
9344
9345 OSSharedPtr<OSObject> parsedXML;
9346 OSDictionary * requestDict = NULL; // do not release
9347 OSSharedPtr<OSString> errorString;
9348
9349 OSSharedPtr<OSObject> responseObject;
9350
9351 OSSharedPtr<OSSerialize> serializer;
9352
9353 OSSharedPtr<OSArray> logInfoArray;
9354
9355 OSString * predicate = NULL; // do not release
9356 OSString * kextIdentifier = NULL; // do not release
9357 OSArray * kextIdentifiers = NULL; // do not release
9358 OSKext * theKext = NULL; // do not release
9359 OSBoolean * boolArg = NULL; // do not release
9360
9361 IORecursiveLockLock(sKextLock);
9362
9363 if (responseOut) {
9364 *responseOut = NULL;
9365 *responseLengthOut = 0;
9366 }
9367 if (logInfoOut) {
9368 *logInfoOut = NULL;
9369 *logInfoLengthOut = 0;
9370 }
9371
9372 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9373
9374 /* XML must be nul-terminated.
9375 */
9376 if (requestBuffer[requestLength - 1] != '\0') {
9377 OSKextLog(/* kext */ NULL,
9378 kOSKextLogErrorLevel |
9379 kOSKextLogIPCFlag,
9380 "Invalid request from user space (not nul-terminated).");
9381 result = kOSKextReturnBadData;
9382 goto finish;
9383 }
9384 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
9385 if (parsedXML) {
9386 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
9387 }
9388 if (!requestDict) {
9389 const char * errorCString = "(unknown error)";
9390
9391 if (errorString && errorString->getCStringNoCopy()) {
9392 errorCString = errorString->getCStringNoCopy();
9393 } else if (parsedXML) {
9394 errorCString = "not a dictionary";
9395 }
9396 OSKextLog(/* kext */ NULL,
9397 kOSKextLogErrorLevel |
9398 kOSKextLogIPCFlag,
9399 "Error unserializing request from user space: %s.",
9400 errorCString);
9401 result = kOSKextReturnSerialization;
9402 goto finish;
9403 }
9404
9405 predicate = _OSKextGetRequestPredicate(requestDict);
9406 if (!predicate) {
9407 OSKextLog(/* kext */ NULL,
9408 kOSKextLogErrorLevel |
9409 kOSKextLogIPCFlag,
9410 "Recieved kext request from user space with no predicate.");
9411 result = kOSKextReturnInvalidArgument;
9412 goto finish;
9413 }
9414
9415 OSKextLog(/* kext */ NULL,
9416 kOSKextLogDebugLevel |
9417 kOSKextLogIPCFlag,
9418 "Received '%s' request from user space.",
9419 predicate->getCStringNoCopy());
9420
9421 /*
9422 * All management of file sets requires an entitlement
9423 */
9424 result = kOSKextReturnNotPrivileged;
9425 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9426 predicate->isEqualTo(kKextRequestPredicateStart) ||
9427 predicate->isEqualTo(kKextRequestPredicateStop) ||
9428 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9429 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9430 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9431 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9432 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9433 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9434 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9435 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9436 if (hostPriv == HOST_PRIV_NULL) {
9437 OSKextLog(/* kext */ NULL,
9438 kOSKextLogErrorLevel |
9439 kOSKextLogIPCFlag,
9440 "Access Failure - must be root user.");
9441 goto finish;
9442 }
9443 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
9444 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9445
9446 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9447 OSKextLog(/* kext */ NULL,
9448 kOSKextLogErrorLevel |
9449 kOSKextLogIPCFlag,
9450 "Access Failure - client not entitled to manage file sets.");
9451 goto finish;
9452 }
9453
9454 /*
9455 * The OnlyBootKC entitlement restricts the
9456 * collection-management entitlement to only managing kexts in
9457 * the BootKC. All other predicates that alter global state or
9458 * add new KCs are disallowed.
9459 */
9460 if (taskOnlyManagesBootKC &&
9461 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9462 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9463 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9464 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9465 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9466 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9467 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9468 OSKextLog(/* kext */ NULL,
9469 kOSKextLogErrorLevel |
9470 kOSKextLogIPCFlag,
9471 "Access Failure - client not entitled to manage non-primary KCs");
9472 goto finish;
9473 }
9474
9475 /*
9476 * If we get here, then the process either has the full KC
9477 * management entitlement, or it has the BootKC-only
9478 * entitlement and the request is about the BootKC.
9479 */
9480 }
9481
9482 /* Get common args in anticipation of use.
9483 */
9484 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9485 requestDict, kKextRequestArgumentBundleIdentifierKey));
9486 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9487 requestDict, kKextRequestArgumentBundleIdentifierKey));
9488 if (kextIdentifier) {
9489 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9490 }
9491 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9492 requestDict, kKextRequestArgumentValueKey));
9493
9494 if (taskOnlyManagesBootKC &&
9495 theKext &&
9496 theKext->isInFileset() &&
9497 theKext->kc_type != KCKindPrimary) {
9498 OSKextLog(/* kext */ NULL,
9499 kOSKextLogErrorLevel |
9500 kOSKextLogIPCFlag,
9501 "Access Failure - client not entitled to manage kext in non-primary KC");
9502 result = kOSKextReturnNotPrivileged;
9503 goto finish;
9504 }
9505
9506 result = kOSKextReturnInvalidArgument;
9507
9508 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9509 if (!kextIdentifier) {
9510 OSKextLog(/* kext */ NULL,
9511 kOSKextLogErrorLevel |
9512 kOSKextLogIPCFlag,
9513 "Invalid arguments to kext start request.");
9514 } else if (!theKext) {
9515 OSKextLog(/* kext */ NULL,
9516 kOSKextLogErrorLevel |
9517 kOSKextLogIPCFlag,
9518 "Kext %s not found for start request.",
9519 kextIdentifier->getCStringNoCopy());
9520 result = kOSKextReturnNotFound;
9521 } else {
9522 result = theKext->start();
9523 }
9524 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9525 if (!kextIdentifier) {
9526 OSKextLog(/* kext */ NULL,
9527 kOSKextLogErrorLevel |
9528 kOSKextLogIPCFlag,
9529 "Invalid arguments to kext stop request.");
9530 } else if (!theKext) {
9531 OSKextLog(/* kext */ NULL,
9532 kOSKextLogErrorLevel |
9533 kOSKextLogIPCFlag,
9534 "Kext %s not found for stop request.",
9535 kextIdentifier->getCStringNoCopy());
9536 result = kOSKextReturnNotFound;
9537 } else {
9538 result = theKext->stop();
9539 }
9540 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9541 result = OSKext::setMissingAuxKCBundles(requestDict);
9542 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9543 if (!kextIdentifier) {
9544 OSKextLog(/* kext */ NULL,
9545 kOSKextLogErrorLevel |
9546 kOSKextLogIPCFlag,
9547 "Invalid arguments to AuxKC Bundle Available request.");
9548 } else {
9549 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9550 }
9551 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9552 if (!kextIdentifier) {
9553 OSKextLog(/* kext */ NULL,
9554 kOSKextLogErrorLevel |
9555 kOSKextLogIPCFlag,
9556 "Invalid arguments to kext load from KC request.");
9557 } else if (!theKext) {
9558 OSKextLog(/* kext */ NULL,
9559 kOSKextLogErrorLevel |
9560 kOSKextLogIPCFlag,
9561 "Kext %s not found for load from KC request.",
9562 kextIdentifier->getCStringNoCopy());
9563 result = kOSKextReturnNotFound;
9564 } else if (!theKext->isInFileset()) {
9565 OSKextLog(/* kext */ NULL,
9566 kOSKextLogErrorLevel |
9567 kOSKextLogIPCFlag,
9568 "Kext %s does not exist in a KC: refusing to load.",
9569 kextIdentifier->getCStringNoCopy());
9570 result = kOSKextReturnNotLoadable;
9571 } else {
9572 result = OSKext::loadKextFromKC(theKext, requestDict);
9573 }
9574 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9575 if (!kextIdentifier) {
9576 OSKextLog(/* kext */ NULL,
9577 kOSKextLogErrorLevel |
9578 kOSKextLogIPCFlag,
9579 "Invalid arguments to codeless kext load interface (missing identifier).");
9580 } else {
9581 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9582 }
9583 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9584 if (!kextIdentifier) {
9585 OSKextLog(/* kext */ NULL,
9586 kOSKextLogErrorLevel |
9587 kOSKextLogIPCFlag,
9588 "Invalid arguments to kext unload request.");
9589 } else if (!theKext) {
9590 OSKextLog(/* kext */ NULL,
9591 kOSKextLogErrorLevel |
9592 kOSKextLogIPCFlag,
9593 "Kext %s not found for unload request.",
9594 kextIdentifier->getCStringNoCopy());
9595 result = kOSKextReturnNotFound;
9596 } else {
9597 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9598 _OSKextGetRequestArgument(requestDict,
9599 kKextRequestArgumentTerminateIOServicesKey));
9600 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9601 }
9602 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9603 result = OSKext::dispatchResource(requestDict);
9604 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9605 OSNumber *lookupNum = NULL;
9606 lookupNum = OSDynamicCast(OSNumber,
9607 _OSKextGetRequestArgument(requestDict,
9608 kKextRequestArgumentLookupAddressKey));
9609
9610 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9611 if (responseObject) {
9612 result = kOSReturnSuccess;
9613 } else {
9614 goto finish;
9615 }
9616 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
9617 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9618 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9619 OSBoolean * delayAutounloadBool = NULL;
9620 OSObject * infoKeysRaw = NULL;
9621 OSArray * infoKeys = NULL;
9622 uint32_t infoKeysCount = 0;
9623
9624 delayAutounloadBool = OSDynamicCast(OSBoolean,
9625 _OSKextGetRequestArgument(requestDict,
9626 kKextRequestArgumentDelayAutounloadKey));
9627
9628 /* If asked to delay autounload, reset the timer if it's currently set.
9629 * (That is, don't schedule an unload if one isn't already pending.
9630 */
9631 if (delayAutounloadBool == kOSBooleanTrue) {
9632 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9633 }
9634
9635 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9636 kKextRequestArgumentInfoKeysKey);
9637 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9638 if (infoKeysRaw && !infoKeys) {
9639 OSKextLog(/* kext */ NULL,
9640 kOSKextLogErrorLevel |
9641 kOSKextLogIPCFlag,
9642 "Invalid arguments to kext info request.");
9643 goto finish;
9644 }
9645
9646 if (infoKeys) {
9647 infoKeysCount = infoKeys->getCount();
9648 for (uint32_t i = 0; i < infoKeysCount; i++) {
9649 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9650 OSKextLog(/* kext */ NULL,
9651 kOSKextLogErrorLevel |
9652 kOSKextLogIPCFlag,
9653 "Invalid arguments to kext info request.");
9654 goto finish;
9655 }
9656 }
9657 }
9658
9659 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9660 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9661 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9662 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
9663 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9664 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
9665 }
9666
9667 if (!responseObject) {
9668 result = kOSKextReturnInternalError;
9669 } else {
9670 OSKextLog(/* kext */ NULL,
9671 kOSKextLogDebugLevel |
9672 kOSKextLogIPCFlag,
9673 "Returning loaded kext info.");
9674 result = kOSReturnSuccess;
9675 }
9676 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9677 /* Hand the current sKernelRequests array to the caller
9678 * (who must release it), and make a new one.
9679 */
9680 responseObject = os::move(sKernelRequests);
9681 sKernelRequests = OSArray::withCapacity(0);
9682 sPostedKextLoadIdentifiers->flushCollection();
9683 OSKextLog(/* kext */ NULL,
9684 kOSKextLogDebugLevel |
9685 kOSKextLogIPCFlag,
9686 "Returning kernel requests.");
9687 result = kOSReturnSuccess;
9688 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9689 /* Return the set of all requested bundle identifiers */
9690 responseObject = sAllKextLoadIdentifiers;
9691 OSKextLog(/* kext */ NULL,
9692 kOSKextLogDebugLevel |
9693 kOSKextLogIPCFlag,
9694 "Returning load requests.");
9695 result = kOSReturnSuccess;
9696 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9697 printf("KextLog: Loading FileSet KC(s)\n");
9698 result = OSKext::loadFileSetKexts(requestDict);
9699 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9700 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9701 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
9702 } else {
9703 OSKextLog(/* kext */ NULL,
9704 kOSKextLogDebugLevel |
9705 kOSKextLogIPCFlag,
9706 "Received '%s' invalid request from user space.",
9707 predicate->getCStringNoCopy());
9708 goto finish;
9709 }
9710
9711 /**********
9712 * Now we have handle the request, or not. Gather up the response & logging
9713 * info to ship to user space.
9714 *********/
9715
9716 /* Note: Nothing in OSKext is supposed to retain requestDict,
9717 * but you never know....
9718 */
9719 if (requestDict->getRetainCount() > 1) {
9720 OSKextLog(/* kext */ NULL,
9721 kOSKextLogWarningLevel |
9722 kOSKextLogIPCFlag,
9723 "Request from user space still retained by a kext; "
9724 "probable memory leak.");
9725 }
9726
9727 if (responseOut && responseObject) {
9728 serializer = OSSerialize::withCapacity(0);
9729 if (!serializer) {
9730 result = kOSKextReturnNoMemory;
9731 goto finish;
9732 }
9733 /*
9734 * Before serializing the kernel requests, patch the dext launch requests so
9735 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9736 * IOUserServerCheckInToken kernel object.
9737 */
9738 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9739 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9740 task_t calling_task = current_task();
9741 if (!requests) {
9742 OSKextLog(/* kext */ NULL,
9743 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9744 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9745 result = kOSKextReturnInternalError;
9746 goto finish;
9747 }
9748 result = patchDextLaunchRequests(calling_task, requests);
9749 if (result != kOSReturnSuccess) {
9750 OSKextLog(/* kext */ NULL,
9751 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9752 "Failed to patch dext launch requests.");
9753 goto finish;
9754 }
9755 }
9756
9757 if (!responseObject->serialize(serializer.get())) {
9758 OSKextLog(/* kext */ NULL,
9759 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9760 "Failed to serialize response to request from user space.");
9761 result = kOSKextReturnSerialization;
9762 goto finish;
9763 }
9764
9765 response = (char *)serializer->text();
9766 responseLength = serializer->getLength();
9767 }
9768
9769 if (responseOut && response) {
9770 char * buffer;
9771
9772 /* This kmem_alloc sets the return value of the function.
9773 */
9774 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9775 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
9776 if (kmem_result != KERN_SUCCESS) {
9777 OSKextLog(/* kext */ NULL,
9778 kOSKextLogErrorLevel |
9779 kOSKextLogIPCFlag,
9780 "Failed to copy response to request from user space.");
9781 result = kmem_result;
9782 goto finish;
9783 } else {
9784 /* 11981737 - clear uninitialized data in last page */
9785 bzero((void *)(buffer + responseLength),
9786 (round_page(responseLength) - responseLength));
9787 memcpy(buffer, response, responseLength);
9788 *responseOut = buffer;
9789 *responseLengthOut = responseLength;
9790 }
9791 }
9792
9793 finish:
9794
9795 /* Gather up the collected log messages for user space. Any messages
9796 * messages past this call will not make it up as log messages but
9797 * will be in the system log. Note that we ignore the return of the
9798 * serialize; it has no bearing on the operation at hand even if we
9799 * fail to get the log messages.
9800 */
9801 logInfoArray = OSKext::clearUserSpaceLogFilter();
9802
9803 if (logInfoArray && logInfoOut && logInfoLengthOut) {
9804 (void)OSKext::serializeLogInfo(logInfoArray.get(),
9805 logInfoOut, logInfoLengthOut);
9806 }
9807
9808 IORecursiveLockUnlock(sKextLock);
9809
9810 return result;
9811 }
9812
9813 #if PRAGMA_MARK
9814 #pragma mark Linked Kext Collection Support
9815 #endif
9816
9817 static int
9818 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9819 {
9820 for (int i = 0; i < segCount; i++) {
9821 vm_offset_t segStart = segAddrs[i];
9822 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9823
9824 if (theAddr >= segStart && theAddr < segEnd) {
9825 return i;
9826 }
9827 }
9828 return -1;
9829 }
9830
9831 static void
9832 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
9833 kernel_segment_command_t *kextTextSeg,
9834 OSData *kaslrOffsets)
9835 {
9836 static const char *plk_segNames[] = {
9837 "__TEXT",
9838 "__TEXT_EXEC",
9839 "__DATA",
9840 "__DATA_CONST",
9841 "__LINKEDIT",
9842 "__PRELINK_TEXT",
9843 "__PLK_TEXT_EXEC",
9844 "__PRELINK_DATA",
9845 "__PLK_DATA_CONST",
9846 "__PLK_LLVM_COV",
9847 "__PLK_LINKEDIT",
9848 "__PRELINK_INFO"
9849 };
9850 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9851
9852 unsigned long plk_segSizes[num_plk_seg];
9853 vm_offset_t plk_segAddrs[num_plk_seg];
9854
9855 for (size_t i = 0; i < num_plk_seg; i++) {
9856 plk_segSizes[i] = 0;
9857 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9858 }
9859
9860 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9861
9862 int slidKextAddrCount = 0;
9863 int badSlideAddr = 0;
9864 int badSlideTarget = 0;
9865
9866 struct kaslrPackedOffsets {
9867 uint32_t count; /* number of offsets */
9868 uint32_t offsetsArray[]; /* offsets to slide */
9869 };
9870 const struct kaslrPackedOffsets *myOffsets = NULL;
9871 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9872
9873 for (uint32_t j = 0; j < myOffsets->count; j++) {
9874 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9875 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9876 int slideAddrSegIndex = -1;
9877 int addrToSlideSegIndex = -1;
9878
9879 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9880 if (slideAddrSegIndex >= 0) {
9881 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9882 if (addrToSlideSegIndex < 0) {
9883 badSlideTarget++;
9884 continue;
9885 }
9886 } else {
9887 badSlideAddr++;
9888 continue;
9889 }
9890
9891 slidKextAddrCount++;
9892 *slideAddr = ml_static_slide(*slideAddr);
9893 } // for ...
9894 }
9895
9896
9897
9898 /********************************************************************
9899 * addKextsFromKextCollection
9900 *
9901 * Input: MachO header of kext collection. The MachO is assumed to
9902 * have a section named 'info_seg_name,info_sect_name' that
9903 * contains a serialized XML info dictionary. This dictionary
9904 * contains a UUID, possibly a set of relocations (for older
9905 * kxld-built binaries), and an array of kext personalities.
9906 *
9907 ********************************************************************/
9908 bool
9909 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9910 OSDictionary *infoDict, const char *text_seg_name,
9911 OSData **kcUUID, kc_kind_t type)
9912 {
9913 bool result = false;
9914
9915 OSArray *kextArray = NULL; // do not release
9916 OSData *infoDictKCUUID = NULL; // do not release
9917 OSData *kaslrOffsets = NULL; // do not release
9918
9919 IORegistryEntry *registryRoot = NULL; // do not release
9920 OSSharedPtr<OSNumber> kcKextCount;
9921
9922 /* extract the KC UUID from the dictionary */
9923 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9924 if (infoDictKCUUID) {
9925 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9926 panic("kcUUID length is %d, expected %lu",
9927 infoDictKCUUID->getLength(), sizeof(uuid_t));
9928 }
9929 }
9930
9931 /* locate the array of kext dictionaries */
9932 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9933 if (!kextArray) {
9934 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9935 "The given KC has no kext info dictionaries");
9936 goto finish;
9937 }
9938
9939 /*
9940 * old-style KASLR offsets may be present in the info dictionary. If
9941 * we find them, use them and eventually slide them.
9942 */
9943 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9944
9945 /*
9946 * Before processing any kexts, locate the special kext bundle which
9947 * contains a list of kexts that we are to prevent from loading.
9948 */
9949 createExcludeListFromPrelinkInfo(kextArray);
9950
9951 /*
9952 * Create OSKext objects for each kext we find in the array of kext
9953 * info plist dictionaries.
9954 */
9955 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9956 OSDictionary *kextDict = NULL;
9957 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9958 if (!kextDict) {
9959 OSKextLog(/* kext */ NULL,
9960 kOSKextLogErrorLevel |
9961 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9962 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9963 continue;
9964 }
9965
9966 /*
9967 * Create the kext for the entry, then release it, because the
9968 * kext system keeps a reference around until the kext is
9969 * explicitly removed. Any creation/registration failures are
9970 * already logged for us.
9971 */
9972 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9973 }
9974
9975 /*
9976 * slide old-style kxld relocations
9977 * NOTE: this is still used on embedded KCs built with kcgen
9978 * TODO: Remove this once we use the new kext linker everywhere!
9979 */
9980 if (kaslrOffsets && vm_kernel_slide > 0) {
9981 kernel_segment_command_t *text_segment = NULL;
9982 text_segment = getsegbynamefromheader(mh, text_seg_name);
9983 if (!text_segment) {
9984 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9985 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9986 goto finish;
9987 }
9988
9989 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9990 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9991 setAllVMAttributes();
9992 }
9993
9994 /* Store the number of prelinked kexts in the registry so we can tell
9995 * when the system has been started from a prelinked kernel.
9996 */
9997 registryRoot = IORegistryEntry::getRegistryRoot();
9998 assert(registryRoot);
9999
10000 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10001 assert(kcKextCount);
10002 if (kcKextCount) {
10003 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10004 OSNumber *num;
10005 num = OSDynamicCast(OSNumber, prop.get());
10006 if (num) {
10007 kcKextCount->addValue(num->unsigned64BitValue());
10008 }
10009 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10010 }
10011
10012 OSKextLog(/* kext */ NULL,
10013 kOSKextLogProgressLevel |
10014 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10015 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10016 "%u prelinked kexts", infoDict->getCount());
10017
10018
10019 if (kcUUID && infoDictKCUUID) {
10020 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10021 }
10022
10023 result = true;
10024
10025 finish:
10026 return result;
10027 }
10028
10029 bool
10030 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10031 OSDictionary *infoDict, const char *text_seg_name,
10032 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10033 {
10034 OSData *result = NULL;
10035 bool success = addKextsFromKextCollection(mh,
10036 infoDict,
10037 text_seg_name,
10038 &result,
10039 type);
10040 if (success) {
10041 kcUUID.reset(result, OSNoRetain);
10042 }
10043 return success;
10044 }
10045
10046 static OSSharedPtr<OSObject> deferredAuxKCXML;
10047 bool
10048 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
10049 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
10050 {
10051 if (type != KCKindAuxiliary) {
10052 return false;
10053 }
10054
10055 kernel_mach_header_t *_mh;
10056 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
10057 if (!_mh || _mh != mh) {
10058 return false;
10059 }
10060
10061 if (deferredAuxKCXML) {
10062 /* only allow this to be called once */
10063 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10064 "An Aux KC has already been registered for deferred processing.");
10065 return false;
10066 }
10067
10068 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
10069 if (!infoDict) {
10070 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10071 "The Aux KC has info dictionary");
10072 return false;
10073 }
10074
10075 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10076 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10077 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10078 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10079 return false;
10080 }
10081
10082 /*
10083 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10084 * sysctl can return the UUID to user space which will check this
10085 * value for errors.
10086 */
10087 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10088 kcUUID->getLength());
10089 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10090 auxkc_uuid_valid = TRUE;
10091
10092 deferredAuxKCXML = parsedXML;
10093
10094 return true;
10095 }
10096
10097 OSSharedPtr<OSObject>
10098 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10099 {
10100 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10101 return NULL;
10102 }
10103
10104 return os::move(deferredAuxKCXML);
10105 }
10106
10107 #if PRAGMA_MARK
10108 #pragma mark Profile-Guided-Optimization Support
10109 #endif
10110
10111 // #include <InstrProfiling.h>
10112 extern "C" {
10113 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10114 const char *DataEnd,
10115 const char *CountersBegin,
10116 const char *CountersEnd,
10117 const char *NamesBegin,
10118 const char *NamesEnd);
10119 int __llvm_profile_write_buffer_internal(char *Buffer,
10120 const char *DataBegin,
10121 const char *DataEnd,
10122 const char *CountersBegin,
10123 const char *CountersEnd,
10124 const char *NamesBegin,
10125 const char *NamesEnd);
10126 }
10127
10128
10129 static
10130 void
10131 OSKextPgoMetadataPut(char *pBuffer,
10132 size_t *position,
10133 size_t bufferSize,
10134 uint32_t *num_pairs,
10135 const char *key,
10136 const char *value)
10137 {
10138 size_t strlen_key = strlen(key);
10139 size_t strlen_value = strlen(value);
10140 size_t len = strlen(key) + 1 + strlen(value) + 1;
10141 char *pos = pBuffer + *position;
10142 *position += len;
10143 if (pBuffer && bufferSize && *position <= bufferSize) {
10144 memcpy(pos, key, strlen_key); pos += strlen_key;
10145 *(pos++) = '=';
10146 memcpy(pos, value, strlen_value); pos += strlen_value;
10147 *(pos++) = 0;
10148 if (num_pairs) {
10149 (*num_pairs)++;
10150 }
10151 }
10152 }
10153
10154
10155 static
10156 void
10157 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10158 {
10159 *position += strlen(key) + 1 + value_max + 1;
10160 }
10161
10162
10163 static
10164 void
10165 OSKextPgoMetadataPutAll(OSKext *kext,
10166 uuid_t instance_uuid,
10167 char *pBuffer,
10168 size_t *position,
10169 size_t bufferSize,
10170 uint32_t *num_pairs)
10171 {
10172 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10173 //log_10 2^16 ≈ 4.82
10174 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10175 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10176
10177 if (!pBuffer) {
10178 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10179 OSKextPgoMetadataPutMax(position, "UUID", 36);
10180 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10181 } else {
10182 uuid_string_t instance_uuid_string;
10183 uuid_unparse(instance_uuid, instance_uuid_string);
10184 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10185 "INSTANCE", instance_uuid_string);
10186
10187 OSSharedPtr<OSData> uuid_data;
10188 uuid_t uuid;
10189 uuid_string_t uuid_string;
10190 uuid_data = kext->copyUUID();
10191 if (uuid_data) {
10192 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10193 uuid_unparse(uuid, uuid_string);
10194 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10195 "UUID", uuid_string);
10196 }
10197
10198 clock_sec_t secs;
10199 clock_usec_t usecs;
10200 clock_get_calendar_microtime(&secs, &usecs);
10201 assert(usecs < 1000000);
10202 char timestamp[max_timestamp_string_size + 1];
10203 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10204 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10205 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10206 "TIMESTAMP", timestamp);
10207 }
10208
10209 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10210 "NAME", kext->getIdentifierCString());
10211
10212 char versionCString[kOSKextVersionMaxLength];
10213 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10214 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10215 "VERSION", versionCString);
10216 }
10217
10218 static
10219 size_t
10220 OSKextPgoMetadataSize(OSKext *kext)
10221 {
10222 size_t position = 0;
10223 uuid_t fakeuuid = {};
10224 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10225 return position;
10226 }
10227
10228 int
10229 OSKextGrabPgoDataLocked(OSKext *kext,
10230 bool metadata,
10231 uuid_t instance_uuid,
10232 uint64_t *pSize,
10233 char *pBuffer,
10234 uint64_t bufferSize)
10235 {
10236 int err = 0;
10237
10238 kernel_section_t *sect_prf_data = NULL;
10239 kernel_section_t *sect_prf_name = NULL;
10240 kernel_section_t *sect_prf_cnts = NULL;
10241 uint64_t size;
10242 size_t metadata_size = 0;
10243 size_t offset_to_pairs = 0;
10244
10245 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10246 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10247 if (!sect_prf_name) {
10248 // kextcache sometimes truncates the section name to 15 chars
10249 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10250 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10251 }
10252 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10253
10254 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10255 err = ENOTSUP;
10256 goto out;
10257 }
10258
10259 size = __llvm_profile_get_size_for_buffer_internal(
10260 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10261 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10262 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10263
10264 if (metadata) {
10265 metadata_size = OSKextPgoMetadataSize(kext);
10266 size += metadata_size;
10267 size += sizeof(pgo_metadata_footer);
10268 }
10269
10270
10271 if (pSize) {
10272 *pSize = size;
10273 }
10274
10275 if (pBuffer && bufferSize) {
10276 if (bufferSize < size) {
10277 err = ERANGE;
10278 goto out;
10279 }
10280
10281 err = __llvm_profile_write_buffer_internal(
10282 pBuffer,
10283 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10284 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10285 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10286
10287 if (err) {
10288 err = EIO;
10289 goto out;
10290 }
10291
10292 if (metadata) {
10293 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10294 if (offset_to_pairs > UINT32_MAX) {
10295 err = E2BIG;
10296 goto out;
10297 }
10298
10299 char *end_of_buffer = pBuffer + size;
10300 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10301 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10302
10303 size_t metadata_position = 0;
10304 uint32_t num_pairs = 0;
10305 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10306 while (metadata_position < metadata_size) {
10307 metadata_buffer[metadata_position++] = 0;
10308 }
10309
10310 struct pgo_metadata_footer footer;
10311 footer.magic = htonl(0x6d657461);
10312 footer.number_of_pairs = htonl( num_pairs );
10313 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
10314 memcpy(footerp, &footer, sizeof(footer));
10315 }
10316 }
10317
10318 out:
10319 return err;
10320 }
10321
10322
10323 int
10324 OSKextGrabPgoData(uuid_t uuid,
10325 uint64_t *pSize,
10326 char *pBuffer,
10327 uint64_t bufferSize,
10328 int wait_for_unload,
10329 int metadata)
10330 {
10331 int err = 0;
10332 OSSharedPtr<OSKext> kext;
10333
10334
10335 IORecursiveLockLock(sKextLock);
10336
10337 kext = OSKext::lookupKextWithUUID(uuid);
10338 if (!kext) {
10339 err = ENOENT;
10340 goto out;
10341 }
10342
10343 if (wait_for_unload) {
10344 OSKextGrabPgoStruct s;
10345
10346 s.metadata = metadata;
10347 s.pSize = pSize;
10348 s.pBuffer = pBuffer;
10349 s.bufferSize = bufferSize;
10350 s.err = EINTR;
10351
10352 struct list_head *prev = &kext->pendingPgoHead;
10353 struct list_head *next = kext->pendingPgoHead.next;
10354
10355 s.list_head.prev = prev;
10356 s.list_head.next = next;
10357
10358 prev->next = &s.list_head;
10359 next->prev = &s.list_head;
10360
10361 kext.reset();
10362
10363 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
10364
10365 prev = s.list_head.prev;
10366 next = s.list_head.next;
10367
10368 prev->next = next;
10369 next->prev = prev;
10370
10371 err = s.err;
10372 } else {
10373 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
10374 }
10375
10376 out:
10377
10378 IORecursiveLockUnlock(sKextLock);
10379
10380 return err;
10381 }
10382
10383 void
10384 OSKextResetPgoCountersLock()
10385 {
10386 IORecursiveLockLock(sKextLock);
10387 }
10388
10389 void
10390 OSKextResetPgoCountersUnlock()
10391 {
10392 IORecursiveLockUnlock(sKextLock);
10393 }
10394
10395
10396 extern unsigned int not_in_kdp;
10397
10398 void
10399 OSKextResetPgoCounters()
10400 {
10401 assert(!not_in_kdp);
10402 uint32_t count = sLoadedKexts->getCount();
10403 for (uint32_t i = 0; i < count; i++) {
10404 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10405 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10406 if (!sect_prf_cnts) {
10407 continue;
10408 }
10409 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10410 }
10411 }
10412
10413 OSSharedPtr<OSDictionary>
10414 OSKext::copyLoadedKextInfoByUUID(
10415 OSArray * kextIdentifiers,
10416 OSArray * infoKeys)
10417 {
10418 OSSharedPtr<OSDictionary> result;
10419 OSSharedPtr<OSDictionary> kextInfo;
10420 uint32_t max_count, i, j;
10421 uint32_t idCount = 0;
10422 uint32_t idIndex = 0;
10423 IORecursiveLockLock(sKextLock);
10424 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
10425 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
10426
10427 #if CONFIG_MACF
10428 /* Is the calling process allowed to query kext info? */
10429 if (current_task() != kernel_task) {
10430 int macCheckResult = 0;
10431 kauth_cred_t cred = NULL;
10432
10433 cred = kauth_cred_get_with_ref();
10434 macCheckResult = mac_kext_check_query(cred);
10435 kauth_cred_unref(&cred);
10436
10437 if (macCheckResult != 0) {
10438 OSKextLog(/* kext */ NULL,
10439 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10440 "Failed to query kext info (MAC policy error 0x%x).",
10441 macCheckResult);
10442 goto finish;
10443 }
10444 }
10445 #endif
10446
10447 /* Empty list of UUIDs is equivalent to no list (get all).
10448 */
10449 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10450 kextIdentifiers = NULL;
10451 } else if (kextIdentifiers) {
10452 idCount = kextIdentifiers->getCount();
10453 }
10454
10455 /* Same for keys.
10456 */
10457 if (infoKeys && !infoKeys->getCount()) {
10458 infoKeys = NULL;
10459 }
10460
10461 max_count = count[0] + count[1];
10462 result = OSDictionary::withCapacity(max_count);
10463 if (!result) {
10464 goto finish;
10465 }
10466
10467 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10468 for (i = 0; i < count[j]; i++) {
10469 OSKext *thisKext = NULL; // do not release
10470 Boolean includeThis = true;
10471 uuid_t thisKextUUID;
10472 uuid_t thisKextTextUUID;
10473 OSSharedPtr<OSData> uuid_data;
10474 uuid_string_t uuid_key;
10475
10476 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10477 if (!thisKext) {
10478 continue;
10479 }
10480
10481 uuid_data = thisKext->copyUUID();
10482 if (!uuid_data) {
10483 continue;
10484 }
10485
10486 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
10487
10488 uuid_unparse(thisKextUUID, uuid_key);
10489
10490 uuid_data = thisKext->copyTextUUID();
10491 if (!uuid_data) {
10492 continue;
10493 }
10494 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
10495
10496 /* Skip current kext if we have a list of UUIDs and
10497 * it isn't in the list.
10498 */
10499 if (kextIdentifiers) {
10500 includeThis = false;
10501
10502 for (idIndex = 0; idIndex < idCount; idIndex++) {
10503 const OSString* wantedUUID = OSDynamicCast(OSString,
10504 kextIdentifiers->getObject(idIndex));
10505
10506 uuid_t uuid;
10507 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10508
10509 if ((0 == uuid_compare(uuid, thisKextUUID))
10510 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10511 includeThis = true;
10512 /* Only need to find the first kext if multiple match,
10513 * ie. asking for the kernel uuid does not need to find
10514 * interface kexts or builtin static kexts.
10515 */
10516 kextIdentifiers->removeObject(idIndex);
10517 uuid_unparse(uuid, uuid_key);
10518 break;
10519 }
10520 }
10521 }
10522
10523 if (!includeThis) {
10524 continue;
10525 }
10526
10527 kextInfo = thisKext->copyInfo(infoKeys);
10528 if (kextInfo) {
10529 result->setObject(uuid_key, kextInfo.get());
10530 }
10531
10532 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10533 goto finish;
10534 }
10535 }
10536 }
10537
10538 finish:
10539 IORecursiveLockUnlock(sKextLock);
10540
10541 return result;
10542 }
10543
10544 /*********************************************************************
10545 *********************************************************************/
10546 /* static */
10547 OSSharedPtr<OSDictionary>
10548 OSKext::copyKextCollectionInfo(
10549 OSDictionary *requestDict,
10550 OSArray *infoKeys)
10551 {
10552 OSSharedPtr<OSDictionary> result;
10553 OSString *collectionType = NULL;
10554 OSObject *rawLoadedState = NULL;
10555 OSString *loadedState = NULL;
10556
10557 kc_kind_t kc_request_kind = KCKindUnknown;
10558 bool onlyLoaded = false;
10559 bool onlyUnloaded = false;
10560
10561 #if CONFIG_MACF
10562 /* Is the calling process allowed to query kext info? */
10563 if (current_task() != kernel_task) {
10564 int macCheckResult = 0;
10565 kauth_cred_t cred = NULL;
10566
10567 cred = kauth_cred_get_with_ref();
10568 macCheckResult = mac_kext_check_query(cred);
10569 kauth_cred_unref(&cred);
10570
10571 if (macCheckResult != 0) {
10572 OSKextLog(/* kext */ NULL,
10573 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10574 "Failed to query kext info (MAC policy error 0x%x).",
10575 macCheckResult);
10576 goto finish;
10577 }
10578 }
10579 #endif
10580
10581 if (infoKeys && !infoKeys->getCount()) {
10582 infoKeys = NULL;
10583 }
10584
10585 collectionType = OSDynamicCast(OSString,
10586 _OSKextGetRequestArgument(requestDict,
10587 kKextRequestArgumentCollectionTypeKey));
10588 if (!collectionType) {
10589 OSKextLog(/* kext */ NULL,
10590 kOSKextLogErrorLevel |
10591 kOSKextLogIPCFlag,
10592 "Invalid '%s' argument to kext collection info request.",
10593 kKextRequestArgumentCollectionTypeKey);
10594 goto finish;
10595 }
10596 if (collectionType->isEqualTo(kKCTypePrimary)) {
10597 kc_request_kind = KCKindPrimary;
10598 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10599 kc_request_kind = KCKindPageable;
10600 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10601 kc_request_kind = KCKindAuxiliary;
10602 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10603 kc_request_kind = KCKindNone;
10604 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10605 OSKextLog(/* kext */ NULL,
10606 kOSKextLogErrorLevel |
10607 kOSKextLogIPCFlag,
10608 "Invalid '%s' argument value '%s' to kext collection info request.",
10609 kKextRequestArgumentCollectionTypeKey,
10610 collectionType->getCStringNoCopy());
10611 goto finish;
10612 }
10613
10614 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10615 kKextRequestArgumentLoadedStateKey);
10616 if (rawLoadedState) {
10617 loadedState = OSDynamicCast(OSString, rawLoadedState);
10618 if (!loadedState) {
10619 OSKextLog(/* kext */ NULL,
10620 kOSKextLogErrorLevel |
10621 kOSKextLogIPCFlag,
10622 "Invalid '%s' argument to kext collection info request.",
10623 kKextRequestArgumentLoadedStateKey);
10624 goto finish;
10625 }
10626 }
10627 if (loadedState) {
10628 if (loadedState->isEqualTo("Loaded")) {
10629 onlyLoaded = true;
10630 } else if (loadedState->isEqualTo("Unloaded")) {
10631 onlyUnloaded = true;
10632 } else if (!loadedState->isEqualTo("Any")) {
10633 OSKextLog(/* kext */ NULL,
10634 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10635 "Invalid '%s' argument value '%s' for '%s' collection info",
10636 kKextRequestArgumentLoadedStateKey,
10637 loadedState->getCStringNoCopy(),
10638 collectionType->getCStringNoCopy());
10639 goto finish;
10640 }
10641 }
10642
10643 result = OSDictionary::withCapacity(sKextsByID->getCount());
10644 if (!result) {
10645 goto finish;
10646 }
10647
10648 IORecursiveLockLock(sKextLock);
10649 { // start block scope
10650 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10651 {
10652 OSKext *thisKext = NULL; // do not release
10653 OSSharedPtr<OSDictionary> kextInfo;
10654
10655 (void)thisKextID;
10656
10657 thisKext = OSDynamicCast(OSKext, obj);
10658 if (!thisKext) {
10659 return false;
10660 }
10661
10662 /*
10663 * skip the kext if it came from the wrong collection type
10664 * (and the caller requested a specific type)
10665 */
10666 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10667 return false;
10668 }
10669
10670 /*
10671 * respect the caller's desire to find only loaded or
10672 * unloaded kexts
10673 */
10674 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10675 return false;
10676 }
10677 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10678 return false;
10679 }
10680
10681 kextInfo = thisKext->copyInfo(infoKeys);
10682 if (kextInfo) {
10683 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10684 }
10685 return false;
10686 });
10687 } // end block scope
10688 IORecursiveLockUnlock(sKextLock);
10689
10690 finish:
10691 return result;
10692 }
10693
10694 /*********************************************************************
10695 *********************************************************************/
10696 /* static */
10697 OSSharedPtr<OSDictionary>
10698 OSKext::copyLoadedKextInfo(
10699 OSArray * kextIdentifiers,
10700 OSArray * infoKeys)
10701 {
10702 OSSharedPtr<OSDictionary> result;
10703 uint32_t idCount = 0;
10704 bool onlyLoaded;
10705
10706 IORecursiveLockLock(sKextLock);
10707
10708 #if CONFIG_MACF
10709 /* Is the calling process allowed to query kext info? */
10710 if (current_task() != kernel_task) {
10711 int macCheckResult = 0;
10712 kauth_cred_t cred = NULL;
10713
10714 cred = kauth_cred_get_with_ref();
10715 macCheckResult = mac_kext_check_query(cred);
10716 kauth_cred_unref(&cred);
10717
10718 if (macCheckResult != 0) {
10719 OSKextLog(/* kext */ NULL,
10720 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10721 "Failed to query kext info (MAC policy error 0x%x).",
10722 macCheckResult);
10723 goto finish;
10724 }
10725 }
10726 #endif
10727
10728 /* Empty list of bundle ids is equivalent to no list (get all).
10729 */
10730 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10731 kextIdentifiers = NULL;
10732 } else if (kextIdentifiers) {
10733 idCount = kextIdentifiers->getCount();
10734 }
10735
10736 /* Same for keys.
10737 */
10738 if (infoKeys && !infoKeys->getCount()) {
10739 infoKeys = NULL;
10740 }
10741
10742 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10743
10744 result = OSDictionary::withCapacity(128);
10745 if (!result) {
10746 goto finish;
10747 }
10748
10749 #if 0
10750 OSKextLog(/* kext */ NULL,
10751 kOSKextLogErrorLevel |
10752 kOSKextLogGeneralFlag,
10753 "kaslr: vm_kernel_slide 0x%lx \n",
10754 vm_kernel_slide);
10755 OSKextLog(/* kext */ NULL,
10756 kOSKextLogErrorLevel |
10757 kOSKextLogGeneralFlag,
10758 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10759 vm_kernel_stext, vm_kernel_etext);
10760 OSKextLog(/* kext */ NULL,
10761 kOSKextLogErrorLevel |
10762 kOSKextLogGeneralFlag,
10763 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10764 vm_kernel_base, vm_kernel_top);
10765 OSKextLog(/* kext */ NULL,
10766 kOSKextLogErrorLevel |
10767 kOSKextLogGeneralFlag,
10768 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10769 vm_kext_base, vm_kext_top);
10770 OSKextLog(/* kext */ NULL,
10771 kOSKextLogErrorLevel |
10772 kOSKextLogGeneralFlag,
10773 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10774 vm_prelink_stext, vm_prelink_etext);
10775 OSKextLog(/* kext */ NULL,
10776 kOSKextLogErrorLevel |
10777 kOSKextLogGeneralFlag,
10778 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10779 vm_prelink_sinfo, vm_prelink_einfo);
10780 OSKextLog(/* kext */ NULL,
10781 kOSKextLogErrorLevel |
10782 kOSKextLogGeneralFlag,
10783 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10784 vm_slinkedit, vm_elinkedit);
10785 #endif
10786 { // start block scope
10787 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10788 {
10789 OSKext * thisKext = NULL; // do not release
10790 Boolean includeThis = true;
10791 OSSharedPtr<OSDictionary> kextInfo;
10792
10793 thisKext = OSDynamicCast(OSKext, obj);
10794 if (!thisKext) {
10795 return false;
10796 }
10797
10798 /* Skip current kext if not yet started and caller didn't request all.
10799 */
10800 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10801 return false;
10802 }
10803
10804 /* Skip current kext if we have a list of bundle IDs and
10805 * it isn't in the list.
10806 */
10807 if (kextIdentifiers) {
10808 includeThis = false;
10809
10810 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10811 const OSString * thisRequestID = OSDynamicCast(OSString,
10812 kextIdentifiers->getObject(idIndex));
10813 if (thisKextID->isEqualTo(thisRequestID)) {
10814 includeThis = true;
10815 break;
10816 }
10817 }
10818 }
10819
10820 if (!includeThis) {
10821 return false;
10822 }
10823
10824 kextInfo = thisKext->copyInfo(infoKeys);
10825 if (kextInfo) {
10826 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10827 }
10828 return false;
10829 });
10830 } // end block scope
10831
10832 finish:
10833 IORecursiveLockUnlock(sKextLock);
10834
10835 return result;
10836 }
10837
10838 /*********************************************************************
10839 * Any info that needs to do allocations must goto finish on alloc
10840 * failure. Info that is just a lookup should just not set the object
10841 * if the info does not exist.
10842 *********************************************************************/
10843 #define _OSKextLoadInfoDictCapacity (12)
10844
10845 OSSharedPtr<OSDictionary>
10846 OSKext::copyInfo(OSArray * infoKeys)
10847 {
10848 OSSharedPtr<OSDictionary> result;
10849 bool success = false;
10850 OSSharedPtr<OSData> headerData;
10851 OSSharedPtr<OSData> logData;
10852 OSSharedPtr<OSNumber> cpuTypeNumber;
10853 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10854 OSString * versionString = NULL; // do not release
10855 OSString * bundleType = NULL; // do not release
10856 uint32_t executablePathCStringSize = 0;
10857 char * executablePathCString = NULL; // must kfree
10858 OSSharedPtr<OSString> executablePathString;
10859 OSSharedPtr<OSData> uuid;
10860 OSSharedPtr<OSArray> dependencyLoadTags;
10861 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10862 OSSharedPtr<OSArray> metaClassInfo;
10863 OSSharedPtr<OSDictionary> metaClassDict;
10864 OSMetaClass * thisMetaClass = NULL; // do not release
10865 OSSharedPtr<OSString> metaClassName;
10866 OSSharedPtr<OSString> superclassName;
10867 kc_format_t kcformat;
10868 uint32_t count, i;
10869
10870 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10871 if (!result) {
10872 goto finish;
10873 }
10874
10875
10876 /* Empty keys means no keys, but NULL is quicker to check.
10877 */
10878 if (infoKeys && !infoKeys->getCount()) {
10879 infoKeys = NULL;
10880 }
10881
10882 if (!PE_get_primary_kc_format(&kcformat)) {
10883 goto finish;
10884 }
10885
10886 /* Headers, CPU type, and CPU subtype.
10887 */
10888 if (!infoKeys ||
10889 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10890 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10891 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10892 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10893 if (linkedExecutable && !isInterface()) {
10894 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10895 linkedExecutable->getBytesNoCopy();
10896
10897 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10898 // do not return macho header info on shipping embedded - 19095897
10899 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10900 kernel_mach_header_t * temp_kext_mach_hdr;
10901 struct load_command * lcp;
10902
10903 headerData = OSData::withBytes(kext_mach_hdr,
10904 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10905 if (!headerData) {
10906 goto finish;
10907 }
10908
10909 // unslide any vmaddrs we return to userspace - 10726716
10910 temp_kext_mach_hdr = (kernel_mach_header_t *)
10911 headerData->getBytesNoCopy();
10912 if (temp_kext_mach_hdr == NULL) {
10913 goto finish;
10914 }
10915
10916 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10917 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10918 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10919 kernel_segment_command_t * segp;
10920 kernel_section_t * secp;
10921
10922 segp = (kernel_segment_command_t *) lcp;
10923 // 10543468 - if we jettisoned __LINKEDIT clear size info
10924 if (flags.jettisonLinkeditSeg) {
10925 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10926 segp->vmsize = 0;
10927 segp->fileoff = 0;
10928 segp->filesize = 0;
10929 }
10930 }
10931
10932 #if __arm__ || __arm64__
10933 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10934 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10935 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10936 segp->vmaddr = gVirtBase;
10937 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10938 secp->size = 0; // paranoia :)
10939 secp->addr = gVirtBase;
10940 }
10941 }
10942 #endif
10943
10944 #if 0
10945 OSKextLog(/* kext */ NULL,
10946 kOSKextLogErrorLevel |
10947 kOSKextLogGeneralFlag,
10948 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10949 __FUNCTION__, segp->segname, segp->vmaddr,
10950 VM_KERNEL_UNSLIDE(segp->vmaddr),
10951 segp->vmsize, segp->nsects);
10952 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10953 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10954 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10955 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10956 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10957 OSKextLog(/* kext */ NULL,
10958 kOSKextLogErrorLevel |
10959 kOSKextLogGeneralFlag,
10960 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10961 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10962 }
10963 #endif
10964 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10965
10966 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10967 secp->addr = ml_static_unslide(secp->addr);
10968 }
10969 }
10970 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10971 }
10972 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
10973 }
10974 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10975
10976 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10977 osLogDataHeaderRef *header;
10978 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10979
10980 void *os_log_data = NULL;
10981 void *cstring_data = NULL;
10982 void *asan_cstring_data = NULL;
10983 unsigned long os_log_size = 0;
10984 unsigned long cstring_size = 0;
10985 unsigned long asan_cstring_size = 0;
10986 uint32_t os_log_offset = 0;
10987 uint32_t cstring_offset = 0;
10988 uint32_t asan_cstring_offset = 0;
10989 bool res;
10990
10991 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
10992 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
10993 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
10994 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
10995 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
10996 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
10997
10998 header = (osLogDataHeaderRef *) headerBytes;
10999 header->version = OS_LOG_HDR_VERSION;
11000 header->sect_count = NUM_OS_LOG_SECTIONS;
11001 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
11002 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
11003 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
11004 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
11005 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
11006 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
11007
11008
11009 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
11010 if (!logData) {
11011 goto finish;
11012 }
11013 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11014 if (!res) {
11015 goto finish;
11016 }
11017 if (os_log_data) {
11018 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
11019 if (!res) {
11020 goto finish;
11021 }
11022 }
11023 if (cstring_data) {
11024 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
11025 if (!res) {
11026 goto finish;
11027 }
11028 }
11029 if (asan_cstring_data) {
11030 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
11031 if (!res) {
11032 goto finish;
11033 }
11034 }
11035 result->setObject(kOSBundleLogStringsKey, logData.get());
11036 }
11037
11038 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
11039 cpuTypeNumber = OSNumber::withNumber(
11040 (uint64_t) kext_mach_hdr->cputype,
11041 8 * sizeof(kext_mach_hdr->cputype));
11042 if (!cpuTypeNumber) {
11043 goto finish;
11044 }
11045 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
11046 }
11047
11048 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
11049 cpuSubtypeNumber = OSNumber::withNumber(
11050 (uint64_t) kext_mach_hdr->cpusubtype,
11051 8 * sizeof(kext_mach_hdr->cpusubtype));
11052 if (!cpuSubtypeNumber) {
11053 goto finish;
11054 }
11055 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
11056 }
11057 } else {
11058 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
11059 osLogDataHeaderRef *header;
11060 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
11061 bool res;
11062
11063 header = (osLogDataHeaderRef *) headerBytes;
11064 header->version = OS_LOG_HDR_VERSION;
11065 header->sect_count = NUM_OS_LOG_SECTIONS;
11066 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
11067 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
11068 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
11069 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11070 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
11071 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
11072
11073 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
11074 if (!logData) {
11075 goto finish;
11076 }
11077 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
11078 if (!res) {
11079 goto finish;
11080 }
11081 result->setObject(kOSBundleLogStringsKey, logData.get());
11082 }
11083 }
11084 }
11085
11086 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
11087 */
11088 result->setObject(kCFBundleIdentifierKey, bundleID.get());
11089
11090 /* CFBundlePackageType
11091 */
11092 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
11093 if (bundleType) {
11094 result->setObject(kCFBundlePackageTypeKey, bundleType);
11095 }
11096
11097 /* CFBundleVersion.
11098 */
11099 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
11100 versionString = OSDynamicCast(OSString,
11101 getPropertyForHostArch(kCFBundleVersionKey));
11102 if (versionString) {
11103 result->setObject(kCFBundleVersionKey, versionString);
11104 }
11105 }
11106
11107 /* OSBundleCompatibleVersion.
11108 */
11109 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
11110 versionString = OSDynamicCast(OSString,
11111 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
11112 if (versionString) {
11113 result->setObject(kOSBundleCompatibleVersionKey, versionString);
11114 }
11115 }
11116
11117 /* Path.
11118 */
11119 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
11120 if (path) {
11121 result->setObject(kOSBundlePathKey, path.get());
11122 }
11123 }
11124
11125
11126 /* OSBundleExecutablePath.
11127 */
11128 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
11129 if (path && executableRelPath) {
11130 uint32_t pathLength = path->getLength(); // gets incremented below
11131
11132 // +1 for slash, +1 for \0
11133 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11134
11135 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
11136 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
11137 if (!executablePathCString) {
11138 goto finish;
11139 }
11140 strlcpy(executablePathCString, path->getCStringNoCopy(),
11141 executablePathCStringSize);
11142 executablePathCString[pathLength++] = '/';
11143 executablePathCString[pathLength++] = '\0';
11144 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11145 executablePathCStringSize);
11146
11147 executablePathString = OSString::withCString(executablePathCString);
11148
11149 if (!executablePathString) {
11150 goto finish;
11151 }
11152
11153 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11154 } else if (flags.builtin) {
11155 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
11156 } else if (isDriverKit()) {
11157 if (path) {
11158 // +1 for slash, +1 for \0
11159 uint32_t pathLength = path->getLength();
11160 executablePathCStringSize = pathLength + 2;
11161
11162 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
11163 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
11164 if (!executablePathCString) {
11165 goto finish;
11166 }
11167 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11168 executablePathCString[pathLength++] = '/';
11169 executablePathCString[pathLength++] = '\0';
11170
11171 executablePathString = OSString::withCString(executablePathCString);
11172
11173 if (!executablePathString) {
11174 goto finish;
11175 }
11176
11177 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11178 }
11179 }
11180 }
11181
11182 /* UUID, if the kext has one.
11183 */
11184 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11185 uuid = copyUUID();
11186 if (uuid) {
11187 result->setObject(kOSBundleUUIDKey, uuid.get());
11188 }
11189 }
11190 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11191 uuid = copyTextUUID();
11192 if (uuid) {
11193 result->setObject(kOSBundleTextUUIDKey, uuid.get());
11194 }
11195 }
11196
11197 /*
11198 * Info.plist digest
11199 */
11200 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11201 OSData *digest;
11202 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11203 if (digest) {
11204 result->setObject(kOSKextInfoPlistDigestKey, digest);
11205 }
11206 }
11207
11208 /*
11209 * Collection type
11210 */
11211 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11212 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
11213 }
11214
11215 /*
11216 * Collection availability
11217 */
11218 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11219 result->setObject(kOSKextAuxKCAvailabilityKey,
11220 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11221 }
11222
11223 /*
11224 * Allows user load
11225 */
11226 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11227 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11228 if (allowUserLoad) {
11229 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11230 }
11231 }
11232
11233 /*
11234 * Bundle Dependencies (OSBundleLibraries)
11235 */
11236 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11237 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11238 if (libraries) {
11239 result->setObject(kOSBundleLibrariesKey, libraries);
11240 }
11241 }
11242
11243 /*****
11244 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11245 */
11246 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11247 result->setObject(kOSKernelResourceKey,
11248 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11249 }
11250
11251 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11252 result->setObject(kOSBundleIsInterfaceKey,
11253 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11254 }
11255
11256 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11257 result->setObject(kOSBundlePrelinkedKey,
11258 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
11259 }
11260
11261 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11262 result->setObject(kOSBundleStartedKey,
11263 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11264 }
11265
11266 /* LoadTag (Index).
11267 */
11268 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
11269 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
11270 /* numBits */ 8 * sizeof(loadTag));
11271 if (!scratchNumber) {
11272 goto finish;
11273 }
11274 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
11275 }
11276
11277 /* LoadAddress, LoadSize.
11278 */
11279 if (!infoKeys ||
11280 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11281 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11282 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11283 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11284 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11285 bool is_dext = isDriverKit();
11286 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
11287 /* These go to userspace via serialization, so we don't want any doubts
11288 * about their size.
11289 */
11290 uint64_t loadAddress = 0;
11291 uint32_t loadSize = 0;
11292 uint32_t wiredSize = 0;
11293 uint64_t execLoadAddress = 0;
11294 uint32_t execLoadSize = 0;
11295
11296 /* Interfaces always report 0 load address & size.
11297 * Just the way they roll.
11298 *
11299 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11300 * xxx - shouldn't have one!
11301 */
11302
11303 if (flags.builtin || linkedExecutable) {
11304 kernel_mach_header_t *mh = NULL;
11305 kernel_segment_command_t *seg = NULL;
11306
11307 if (flags.builtin) {
11308 loadAddress = kmod_info->address;
11309 loadSize = (uint32_t)kmod_info->size;
11310 } else {
11311 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11312 loadSize = linkedExecutable->getLength();
11313 }
11314 mh = (kernel_mach_header_t *)loadAddress;
11315 loadAddress = ml_static_unslide(loadAddress);
11316
11317 /* Walk through the kext, looking for the first executable
11318 * segment in case we were asked for its size/address.
11319 */
11320 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11321 if (seg->initprot & VM_PROT_EXECUTE) {
11322 execLoadAddress = ml_static_unslide(seg->vmaddr);
11323 execLoadSize = (uint32_t)seg->vmsize;
11324 break;
11325 }
11326 }
11327
11328 /* If we have a kmod_info struct, calculated the wired size
11329 * from that. Otherwise it's the full load size.
11330 */
11331 if (kmod_info) {
11332 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
11333 } else {
11334 wiredSize = loadSize;
11335 }
11336 } else if (is_dext) {
11337 /*
11338 * DriverKit userspace executables do not have a kernel linkedExecutable,
11339 * so we "fake" their address range with the LoadTag.
11340 */
11341 if (loadTag) {
11342 loadAddress = execLoadAddress = loadTag;
11343 loadSize = execLoadSize = 1;
11344 }
11345 }
11346
11347 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
11348 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11349 (unsigned long long)(loadAddress),
11350 /* numBits */ 8 * sizeof(loadAddress));
11351 if (!scratchNumber) {
11352 goto finish;
11353 }
11354 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
11355 }
11356 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11357 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11358 && loadAddress && loadSize) {
11359 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11360 if (!baseAddress) {
11361 goto finish;
11362 }
11363
11364 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11365 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11366 /* numBits */ 8 * sizeof(loadAddress));
11367 if (!scratchNumber) {
11368 goto finish;
11369 }
11370 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11371 }
11372 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11373 && (this == sKernelKext) && gBuiltinKmodsCount) {
11374 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
11375 }
11376 }
11377
11378 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
11379 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11380 (unsigned long long)(execLoadAddress),
11381 /* numBits */ 8 * sizeof(execLoadAddress));
11382 if (!scratchNumber) {
11383 goto finish;
11384 }
11385 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
11386 }
11387 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
11388 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11389 (unsigned long long)(loadSize),
11390 /* numBits */ 8 * sizeof(loadSize));
11391 if (!scratchNumber) {
11392 goto finish;
11393 }
11394 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
11395 }
11396 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
11397 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11398 (unsigned long long)(execLoadSize),
11399 /* numBits */ 8 * sizeof(execLoadSize));
11400 if (!scratchNumber) {
11401 goto finish;
11402 }
11403 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
11404 }
11405 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11406 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11407 (unsigned long long)(wiredSize),
11408 /* numBits */ 8 * sizeof(wiredSize));
11409 if (!scratchNumber) {
11410 goto finish;
11411 }
11412 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
11413 }
11414 }
11415 }
11416
11417 /* OSBundleDependencies. In descending order for
11418 * easy compatibility with kextstat(8).
11419 */
11420 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11421 if ((count = getNumDependencies())) {
11422 dependencyLoadTags = OSArray::withCapacity(count);
11423 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
11424
11425 i = count - 1;
11426 do {
11427 OSKext * dependency = OSDynamicCast(OSKext,
11428 dependencies->getObject(i));
11429
11430 if (!dependency) {
11431 continue;
11432 }
11433 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11434 (unsigned long long)dependency->getLoadTag(),
11435 /* numBits*/ 8 * sizeof(loadTag));
11436 if (!scratchNumber) {
11437 goto finish;
11438 }
11439 dependencyLoadTags->setObject(scratchNumber.get());
11440 } while (i--);
11441 }
11442 }
11443
11444 /* OSBundleMetaClasses.
11445 */
11446 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11447 if (metaClasses && metaClasses->getCount()) {
11448 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
11449 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11450 if (!metaClassIterator || !metaClassInfo) {
11451 goto finish;
11452 }
11453 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
11454
11455 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11456 metaClassIterator->getNextObject()))) {
11457 metaClassDict = OSDictionary::withCapacity(3);
11458 if (!metaClassDict) {
11459 goto finish;
11460 }
11461
11462 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11463 if (thisMetaClass->getSuperClass()) {
11464 superclassName = OSString::withCString(
11465 thisMetaClass->getSuperClass()->getClassName());
11466 }
11467 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
11468 8 * sizeof(unsigned int));
11469
11470 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11471 * of course.
11472 */
11473 if (!metaClassDict || !metaClassName || !scratchNumber) {
11474 goto finish;
11475 }
11476
11477 metaClassInfo->setObject(metaClassDict.get());
11478 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
11479 if (superclassName) {
11480 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
11481 }
11482 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
11483 }
11484 }
11485 }
11486
11487 /* OSBundleRetainCount.
11488 */
11489 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
11490 {
11491 int kextRetainCount = getRetainCount() - 1;
11492 if (isLoaded()) {
11493 kextRetainCount--;
11494 }
11495 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11496 (int)kextRetainCount,
11497 /* numBits*/ 8 * sizeof(int));
11498 if (scratchNumber) {
11499 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
11500 }
11501 }
11502 }
11503
11504 success = true;
11505
11506 finish:
11507 if (executablePathCString) {
11508 kfree_data(executablePathCString, executablePathCStringSize);
11509 }
11510 if (!success) {
11511 result.reset();
11512 }
11513 return result;
11514 }
11515
11516 /*********************************************************************
11517 *********************************************************************/
11518 /* static */
11519 bool
11520 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11521 {
11522 bool ok;
11523 OSSharedPtr<OSKext> kext;
11524
11525 IORecursiveLockLock(sKextLock);
11526 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
11527 IORecursiveLockUnlock(sKextLock);
11528
11529 if (!kext || !kext->path || !kext->userExecutableRelPath) {
11530 return false;
11531 }
11532 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11533 kext->path->getCStringNoCopy(),
11534 kext->userExecutableRelPath->getCStringNoCopy());
11535 ok = true;
11536
11537 return ok;
11538 }
11539
11540 /*********************************************************************
11541 *********************************************************************/
11542 /* static */
11543 OSReturn
11544 OSKext::requestResource(
11545 const char * kextIdentifierCString,
11546 const char * resourceNameCString,
11547 OSKextRequestResourceCallback callback,
11548 void * context,
11549 OSKextRequestTag * requestTagOut)
11550 {
11551 OSReturn result = kOSReturnError;
11552 OSSharedPtr<OSKext> callbackKext; // looked up
11553
11554 OSKextRequestTag requestTag = -1;
11555 OSSharedPtr<OSNumber> requestTagNum;
11556 OSSharedPtr<OSDictionary> requestDict;
11557 OSSharedPtr<OSString> kextIdentifier;
11558 OSSharedPtr<OSString> resourceName;
11559
11560 OSSharedPtr<OSDictionary> callbackRecord;
11561 OSSharedPtr<OSData> callbackWrapper;
11562
11563 OSSharedPtr<OSData> contextWrapper;
11564
11565 IORecursiveLockLock(sKextLock);
11566
11567 if (requestTagOut) {
11568 *requestTagOut = kOSKextRequestTagInvalid;
11569 }
11570
11571 /* If requests to user space are disabled, don't go any further */
11572 if (!sKernelRequestsEnabled) {
11573 OSKextLog(/* kext */ NULL,
11574 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11575 "Can't request resource %s for %s - requests to user space are disabled.",
11576 resourceNameCString,
11577 kextIdentifierCString);
11578 result = kOSKextReturnDisabled;
11579 goto finish;
11580 }
11581
11582 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11583 result = kOSKextReturnInvalidArgument;
11584 goto finish;
11585 }
11586
11587 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11588 if (!callbackKext) {
11589 OSKextLog(/* kext */ NULL,
11590 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11591 "Resource request has bad callback address.");
11592 result = kOSKextReturnInvalidArgument;
11593 goto finish;
11594 }
11595 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11596 OSKextLog(/* kext */ NULL,
11597 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11598 "Resource request callback is in a kext that is not started.");
11599 result = kOSKextReturnInvalidArgument;
11600 goto finish;
11601 }
11602
11603 /* Do not allow any new requests to be made on a kext that is unloading.
11604 */
11605 if (callbackKext->flags.stopping) {
11606 result = kOSKextReturnStopping;
11607 goto finish;
11608 }
11609
11610 /* If we're wrapped the next available request tag around to the negative
11611 * numbers, we can't service any more requests.
11612 */
11613 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11614 OSKextLog(/* kext */ NULL,
11615 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11616 "No more request tags available; restart required.");
11617 result = kOSKextReturnNoResources;
11618 goto finish;
11619 }
11620 requestTag = sNextRequestTag++;
11621
11622 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
11623 requestDict);
11624 if (result != kOSReturnSuccess) {
11625 goto finish;
11626 }
11627
11628 kextIdentifier = OSString::withCString(kextIdentifierCString);
11629 resourceName = OSString::withCString(resourceNameCString);
11630 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11631 8 * sizeof(requestTag));
11632 if (!kextIdentifier ||
11633 !resourceName ||
11634 !requestTagNum ||
11635 !_OSKextSetRequestArgument(requestDict.get(),
11636 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11637 !_OSKextSetRequestArgument(requestDict.get(),
11638 kKextRequestArgumentNameKey, resourceName.get()) ||
11639 !_OSKextSetRequestArgument(requestDict.get(),
11640 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
11641 result = kOSKextReturnNoMemory;
11642 goto finish;
11643 }
11644
11645 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
11646 if (!callbackRecord) {
11647 result = kOSKextReturnNoMemory;
11648 goto finish;
11649 }
11650 // we validate callback address at call time
11651 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
11652 if (context) {
11653 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
11654 }
11655 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11656 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
11657 result = kOSKextReturnNoMemory;
11658 goto finish;
11659 }
11660
11661 if (context) {
11662 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11663 kKextRequestArgumentContextKey, contextWrapper.get())) {
11664 result = kOSKextReturnNoMemory;
11665 goto finish;
11666 }
11667 }
11668
11669 /* Only post the requests after all the other potential failure points
11670 * have been passed.
11671 */
11672 if (!sKernelRequests->setObject(requestDict.get()) ||
11673 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
11674 result = kOSKextReturnNoMemory;
11675 goto finish;
11676 }
11677
11678 OSKext::pingIOKitDaemon();
11679
11680 result = kOSReturnSuccess;
11681 if (requestTagOut) {
11682 *requestTagOut = requestTag;
11683 }
11684
11685 finish:
11686
11687 /* If we didn't succeed, yank the request & callback
11688 * from their holding arrays.
11689 */
11690 if (result != kOSReturnSuccess) {
11691 unsigned int index;
11692
11693 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
11694 if (index != (unsigned int)-1) {
11695 sKernelRequests->removeObject(index);
11696 }
11697 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
11698 if (index != (unsigned int)-1) {
11699 sRequestCallbackRecords->removeObject(index);
11700 }
11701 }
11702
11703 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11704
11705 IORecursiveLockUnlock(sKextLock);
11706
11707 return result;
11708 }
11709
11710 OSReturn
11711 OSKext::requestDaemonLaunch(
11712 OSString *kextIdentifier,
11713 OSString *serverName,
11714 OSNumber *serverTag,
11715 IOUserServerCheckInToken * checkInToken)
11716 {
11717 OSReturn result = kOSReturnError;
11718 OSSharedPtr<OSDictionary> requestDict;
11719
11720 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
11721 return kOSKextReturnInvalidArgument;
11722 }
11723
11724 IORecursiveLockLock(sKextLock);
11725
11726 OSKextLog(/* kext */ NULL,
11727 kOSKextLogDebugLevel |
11728 kOSKextLogGeneralFlag,
11729 "Requesting daemon launch for %s with serverName %s and tag %llu",
11730 kextIdentifier->getCStringNoCopy(),
11731 serverName->getCStringNoCopy(),
11732 serverTag->unsigned64BitValue()
11733 );
11734
11735 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
11736 if (result != kOSReturnSuccess) {
11737 goto finish;
11738 }
11739
11740 if (!_OSKextSetRequestArgument(requestDict.get(),
11741 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
11742 !_OSKextSetRequestArgument(requestDict.get(),
11743 kKextRequestArgumentDriverExtensionServerName, serverName) ||
11744 !_OSKextSetRequestArgument(requestDict.get(),
11745 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11746 !_OSKextSetRequestArgument(requestDict.get(),
11747 kKextRequestArgumentCheckInToken, checkInToken)) {
11748 result = kOSKextReturnNoMemory;
11749 goto finish;
11750 }
11751
11752 /* Only post the requests after all the other potential failure points
11753 * have been passed.
11754 */
11755 if (!sKernelRequests->setObject(requestDict.get())) {
11756 result = kOSKextReturnNoMemory;
11757 goto finish;
11758 }
11759 OSKext::pingIOKitDaemon();
11760
11761 result = kOSReturnSuccess;
11762 finish:
11763 IORecursiveLockUnlock(sKextLock);
11764 return result;
11765 }
11766
11767 /*********************************************************************
11768 * Assumes sKextLock is held.
11769 *********************************************************************/
11770 /* static */
11771 OSReturn
11772 OSKext::dequeueCallbackForRequestTag(
11773 OSKextRequestTag requestTag,
11774 OSSharedPtr<OSDictionary> &callbackRecordOut)
11775 {
11776 OSDictionary * callbackRecordOutRaw = NULL;
11777 OSReturn result;
11778
11779 result = dequeueCallbackForRequestTag(requestTag,
11780 &callbackRecordOutRaw);
11781
11782 if (kOSReturnSuccess == result) {
11783 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11784 }
11785
11786 return result;
11787 }
11788 OSReturn
11789 OSKext::dequeueCallbackForRequestTag(
11790 OSKextRequestTag requestTag,
11791 OSDictionary ** callbackRecordOut)
11792 {
11793 OSReturn result = kOSReturnError;
11794 OSSharedPtr<OSNumber> requestTagNum;
11795
11796 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11797 8 * sizeof(requestTag));
11798 if (!requestTagNum) {
11799 goto finish;
11800 }
11801
11802 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11803 callbackRecordOut);
11804
11805 finish:
11806 return result;
11807 }
11808
11809 /*********************************************************************
11810 * Assumes sKextLock is held.
11811 *********************************************************************/
11812 /* static */
11813 OSReturn
11814 OSKext::dequeueCallbackForRequestTag(
11815 OSNumber * requestTagNum,
11816 OSSharedPtr<OSDictionary> &callbackRecordOut)
11817 {
11818 OSDictionary * callbackRecordOutRaw = NULL;
11819 OSReturn result;
11820
11821 result = dequeueCallbackForRequestTag(requestTagNum,
11822 &callbackRecordOutRaw);
11823
11824 if (kOSReturnSuccess == result) {
11825 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11826 }
11827
11828 return result;
11829 }
11830 OSReturn
11831 OSKext::dequeueCallbackForRequestTag(
11832 OSNumber * requestTagNum,
11833 OSDictionary ** callbackRecordOut)
11834 {
11835 OSReturn result = kOSKextReturnInvalidArgument;
11836 OSDictionary * callbackRecord = NULL; // retain if matched!
11837 OSNumber * callbackTagNum = NULL; // do not release
11838 unsigned int count, i;
11839
11840 result = kOSReturnError;
11841 count = sRequestCallbackRecords->getCount();
11842 for (i = 0; i < count; i++) {
11843 callbackRecord = OSDynamicCast(OSDictionary,
11844 sRequestCallbackRecords->getObject(i));
11845 if (!callbackRecord) {
11846 goto finish;
11847 }
11848
11849 /* If we don't find a tag, we basically have a leak here. Maybe
11850 * we should just remove it.
11851 */
11852 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11853 callbackRecord, kKextRequestArgumentRequestTagKey));
11854 if (!callbackTagNum) {
11855 goto finish;
11856 }
11857
11858 /* We could be even more paranoid and check that all the incoming
11859 * args match what's in the callback record.
11860 */
11861 if (callbackTagNum->isEqualTo(requestTagNum)) {
11862 if (callbackRecordOut) {
11863 *callbackRecordOut = callbackRecord;
11864 callbackRecord->retain();
11865 }
11866 sRequestCallbackRecords->removeObject(i);
11867 result = kOSReturnSuccess;
11868 goto finish;
11869 }
11870 }
11871 result = kOSKextReturnNotFound;
11872
11873 finish:
11874 return result;
11875 }
11876
11877
11878 /*********************************************************************
11879 * Busy timeout triage
11880 *********************************************************************/
11881 /* static */
11882 bool
11883 OSKext::pendingIOKitDaemonRequests(void)
11884 {
11885 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11886 }
11887
11888 extern "C" int vm_enable_driverkit_shared_region;
11889
11890 /*********************************************************************
11891 * Acquires and releases sKextLock
11892 *
11893 * This function is designed to be called exactly once on boot by
11894 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11895 * kext and dext personalities, and then attempts to map a System
11896 * (pageable) KC and an Auxiliary (aux) KC.
11897 *
11898 * Even if the pageable or aux KC fail to load - this function will
11899 * not allow a second call. This avoids security issues where
11900 * kernelmanagerd has been compromised or the pageable kc has been
11901 * tampered with and the attacker attempts to re-load a malicious
11902 * variant.
11903 *
11904 * Return: if a KC fails to load the return value will contain:
11905 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11906 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11907 * Similarly, if the aux kc load fails, the return value will
11908 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11909 * compose with each other and with kOSKextReturnKCLoadFailure.
11910 *********************************************************************/
11911 /* static */
11912 OSReturn
11913 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11914 {
11915 static bool daemon_ready = false;
11916
11917 OSReturn ret = kOSKextReturnInvalidArgument;
11918 OSReturn kcerr = 0;
11919 bool start_matching = false;
11920
11921 bool allow_fileset_load = !daemon_ready;
11922 #if !(defined(__x86_64__) || defined(__i386__))
11923 /* never allow KCs full of kexts on non-x86 machines */
11924 allow_fileset_load = false;
11925 #endif
11926
11927 /*
11928 * Change with 70582300
11929 */
11930 #if 0 || !defined(VM_MAPPED_KEXTS)
11931 /*
11932 * On platforms that don't support the SystemKC or a file-backed
11933 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
11934 * needs to be queried before we load any codeless kexts or release
11935 * any 3rd party kexts to run. On platforms that support a file-backed
11936 * AuxKC, this process is done via the kext audit mechanism.
11937 */
11938
11939 printf("KextLog: waiting for kext receipt to be queried.\n");
11940 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
11941 IOSleep(30);
11942 }
11943 #endif /* !VM_MAPPED_KEXTS */
11944
11945 /*
11946 * Get the args from the request. Right now we need the file
11947 * name for the pageable and the aux kext collection file sets.
11948 */
11949 OSDictionary * requestArgs = NULL; // do not release
11950 OSString * pageable_filepath = NULL; // do not release
11951 OSString * aux_filepath = NULL; // do not release
11952 OSArray * codeless_kexts = NULL; // do not release
11953 OSNumber * enable_dk_shared_region = NULL; // do not release
11954
11955 kernel_mach_header_t *akc_mh = NULL;
11956
11957 requestArgs = OSDynamicCast(OSDictionary,
11958 requestDict->getObject(kKextRequestArgumentsKey));
11959
11960 if (requestArgs == NULL) {
11961 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11962 "KextLog: No arguments in plist for loading fileset kext\n");
11963 printf("KextLog: No arguments in plist for loading fileset kext\n");
11964 return ret;
11965 }
11966
11967 ret = kOSKextReturnDisabled;
11968
11969 IORecursiveLockLock(sKextLock);
11970
11971 if (!sLoadEnabled) {
11972 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11973 "KextLog: Kext loading is disabled (attempt to load KCs).");
11974 IORecursiveLockUnlock(sKextLock);
11975 return ret;
11976 }
11977
11978 pageable_filepath = OSDynamicCast(OSString,
11979 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11980
11981 if (allow_fileset_load && pageable_filepath != NULL) {
11982 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11983
11984 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11985 if (ret) {
11986 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11987 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11988
11989 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11990 ret = kOSKextReturnKCLoadFailure;
11991 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11992 goto try_auxkc;
11993 }
11994 /*
11995 * Even if the AuxKC fails to load, we still want to send
11996 * the System KC personalities to the catalog for matching
11997 */
11998 start_matching = true;
11999 } else if (pageable_filepath != NULL) {
12000 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12001 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
12002 ret = kOSKextReturnUnsupported;
12003 }
12004
12005 try_auxkc:
12006 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
12007 if (akc_mh) {
12008 /*
12009 * If we try to load a deferred AuxKC, then don't ever attempt
12010 * a filesystem map of a file
12011 */
12012 allow_fileset_load = false;
12013
12014 /*
12015 * This function is only called once per boot, so we haven't
12016 * yet loaded an AuxKC. If we have registered the AuxKC mach
12017 * header, that means that the kext collection has been placed
12018 * in memory for us by the booter, and is waiting for us to
12019 * process it. Grab the deferred XML plist of info
12020 * dictionaries and add all the kexts.
12021 */
12022 OSSharedPtr<OSObject> parsedXML;
12023 OSSharedPtr<OSData> loaded_kcUUID;
12024 OSDictionary *infoDict;
12025 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
12026 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12027 #if !defined(VM_MAPPED_KEXTS)
12028 /*
12029 * On platforms where we don't dynamically wire-down / page-in
12030 * kext memory, we need to maintain the invariant that if the
12031 * AuxKC in memory does not contain a kext receipt, then we
12032 * should not load any of the kexts.
12033 */
12034 size_t receipt_sz = 0;
12035 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
12036 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12037 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
12038 ret = kOSKextReturnKCLoadFailure;
12039 goto try_codeless;
12040 }
12041 #endif
12042 if (infoDict) {
12043 bool added;
12044 printf("KextLog: Adding kexts from in-memory AuxKC\n");
12045 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
12046 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
12047 if (!loaded_kcUUID) {
12048 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12049 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
12050 } else if (!added) {
12051 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12052 "KextLog: WARNING: Failed to load AuxKC from memory.");
12053 }
12054 /* only return success if the pageable load (above) was successful */
12055 if (ret != kOSKextReturnKCLoadFailure) {
12056 ret = kOSReturnSuccess;
12057 }
12058 /* the registration of the AuxKC parsed out the KC's UUID already */
12059 } else {
12060 if (daemon_ready) {
12061 /*
12062 * Complain, but don't return an error if this isn't the first time the
12063 * IOKit daemon is checking in. If the daemon ever restarts, we will
12064 * hit this case because we've already consumed the deferred personalities.
12065 * We return success here so that a call to this function from a restarted
12066 * daemon with no codeless kexts will succeed.
12067 */
12068 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12069 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
12070 if (ret != kOSKextReturnKCLoadFailure) {
12071 ret = kOSReturnSuccess;
12072 }
12073 } else {
12074 /* this is a real error case */
12075 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12076 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
12077 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
12078 ret = kOSKextReturnKCLoadFailure;
12079 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12080 }
12081 }
12082 }
12083
12084 aux_filepath = OSDynamicCast(OSString,
12085 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
12086 if (allow_fileset_load && aux_filepath != NULL) {
12087 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
12088
12089 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
12090 if (ret) {
12091 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12092 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12093
12094 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12095 ret = kOSKextReturnKCLoadFailure;
12096 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12097 goto try_codeless;
12098 }
12099 start_matching = true;
12100 } else if (aux_filepath != NULL) {
12101 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12102 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
12103 if (ret != kOSKextReturnKCLoadFailure) {
12104 ret = kOSKextReturnUnsupported;
12105 }
12106 }
12107
12108 try_codeless:
12109 /*
12110 * Load codeless kexts last so that there is no possibilty of a
12111 * codeless kext bundle ID preventing a kext in the system KC from
12112 * loading
12113 */
12114 codeless_kexts = OSDynamicCast(OSArray,
12115 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
12116 if (codeless_kexts != NULL) {
12117 uint32_t count = codeless_kexts->getCount();
12118 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12119 "KextLog: loading %d codeless kexts/dexts", count);
12120 for (uint32_t i = 0; i < count; i++) {
12121 OSDictionary *infoDict;
12122 infoDict = OSDynamicCast(OSDictionary,
12123 codeless_kexts->getObject(i));
12124 if (!infoDict) {
12125 continue;
12126 }
12127 // instantiate a new kext, and don't hold a reference
12128 // (the kext subsystem will hold one implicitly)
12129 OSKext::withCodelessInfo(infoDict);
12130 }
12131 /* ignore errors that are not KC load failures */
12132 if (ret != kOSKextReturnKCLoadFailure) {
12133 ret = kOSReturnSuccess;
12134 }
12135 start_matching = true;
12136 }
12137
12138 enable_dk_shared_region = OSDynamicCast(OSNumber,
12139 requestArgs->getObject(kKextRequestEnableDriverKitSharedRegionKey));
12140 if (enable_dk_shared_region != NULL && enable_dk_shared_region->unsigned64BitValue() == 1) {
12141 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12142 "KextLog: Enabling DriverKit shared region.");
12143 vm_enable_driverkit_shared_region = 1;
12144 }
12145
12146 /* send personalities to the IOCatalog once */
12147 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
12148 OSKext::sendAllKextPersonalitiesToCatalog(true);
12149 /*
12150 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12151 * things as active and start all the delayed matching: the
12152 * dext and codeless kext personalities should have all been
12153 * delivered via this one call.
12154 */
12155 if (!daemon_ready) {
12156 OSKext::setIOKitDaemonActive();
12157 OSKext::setDeferredLoadSucceeded(TRUE);
12158 IOService::iokitDaemonLaunched();
12159 }
12160 if (sOSKextWasResetAfterUserspaceReboot) {
12161 sOSKextWasResetAfterUserspaceReboot = false;
12162 OSKext::setIOKitDaemonActive();
12163 IOService::startDeferredMatches();
12164 }
12165 }
12166
12167 if (ret == kOSKextReturnKCLoadFailure) {
12168 ret |= kcerr;
12169 }
12170
12171 /*
12172 * Only allow this function to attempt to load the pageable and
12173 * aux KCs once per boot.
12174 */
12175 daemon_ready = true;
12176
12177 IORecursiveLockUnlock(sKextLock);
12178
12179 return ret;
12180 }
12181
12182 OSReturn
12183 OSKext::resetMutableSegments(void)
12184 {
12185 kernel_segment_command_t *seg = NULL;
12186 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12187 u_int index = 0;
12188 OSKextSavedMutableSegment *savedSegment = NULL;
12189 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12190 OSReturn err;
12191
12192 if (!savedMutableSegments) {
12193 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12194 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12195 err = kOSKextReturnInternalError;
12196 goto finish;
12197 }
12198
12199 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12200 if (!segmentIsMutable(seg)) {
12201 continue;
12202 }
12203 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12204 uint64_t vmsize = seg->vmsize;
12205 err = kOSKextReturnInternalError;
12206 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12207 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12208 assert(savedSegment);
12209 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12210 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12211 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12212 err = savedSegment->restoreContents(seg);
12213 if (err != kOSReturnSuccess) {
12214 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12215 }
12216 }
12217 }
12218 if (err != kOSReturnSuccess) {
12219 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12220 }
12221 }
12222 err = kOSReturnSuccess;
12223 finish:
12224 return err;
12225 }
12226
12227
12228 /*********************************************************************
12229 * Assumes sKextLock is held.
12230 *********************************************************************/
12231 /* static */
12232 OSReturn
12233 OSKext::loadKCFileSet(
12234 const char *filepath,
12235 kc_kind_t type)
12236 {
12237 #if VM_MAPPED_KEXTS
12238 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12239 OSReturn err;
12240 struct vnode *vp = NULL;
12241 void *fileset_control;
12242 off_t fsize;
12243 bool pageable = (type == KCKindPageable);
12244
12245 if ((pageable && pageableKCloaded) ||
12246 (!pageable && auxKCloaded)) {
12247 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12248 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12249
12250 return kOSKextReturnInvalidArgument;
12251 }
12252
12253 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12254 if (!pageable && !pageableKCloaded) {
12255 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12256 "Trying to load the Aux KC without loading the Pageable KC");
12257 return kOSKextReturnInvalidArgument;
12258 }
12259
12260 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12261
12262 if (fileset_control == NULL) {
12263 printf("Could not get memory control object for file %s", filepath);
12264
12265 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12266 "Could not get memory control object for file %s", filepath);
12267 return kOSKextReturnInvalidArgument;
12268 }
12269 if (vp == NULL) {
12270 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12271 "Could not find vnode for file %s", filepath);
12272 return kOSKextReturnInvalidArgument;
12273 }
12274
12275 kernel_mach_header_t *mh = NULL;
12276 uintptr_t slide = 0;
12277
12278 #if CONFIG_CSR
12279 /*
12280 * When SIP is enabled, the KC we map must be SIP-protected
12281 */
12282 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12283 struct vnode_attr va;
12284 int error;
12285 VATTR_INIT(&va);
12286 VATTR_WANTED(&va, va_flags);
12287 error = vnode_getattr(vp, &va, vfs_context_current());
12288 if (error) {
12289 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12290 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12291 err = kOSKextReturnInternalError;
12292 goto finish;
12293 }
12294 if (!(va.va_flags & SF_RESTRICTED)) {
12295 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12296 "Path to KC '%s' is not SIP-protected", filepath);
12297 err = kOSKextReturnInvalidArgument;
12298 goto finish;
12299 }
12300 }
12301 #endif
12302
12303 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12304 if (err) {
12305 printf("KextLog: mapKCFileSet returned %d\n", err);
12306
12307 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12308 "mapKCFileSet returned %d\n", err);
12309
12310 err = kOSKextReturnInvalidArgument;
12311 }
12312
12313 #if CONFIG_CSR
12314 finish:
12315 #endif
12316 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12317 assert(vp != NULL);
12318 if (err == kOSReturnSuccess) {
12319 PE_set_kc_vp(type, vp);
12320 if (pageable) {
12321 pageableKCloaded = true;
12322 } else {
12323 auxKCloaded = true;
12324 }
12325 } else {
12326 vnode_put(vp);
12327 }
12328
12329 return err;
12330 #else
12331 (void)filepath;
12332 (void)type;
12333 return kOSKextReturnUnsupported;
12334 #endif // VM_MAPPED_KEXTS
12335 }
12336
12337 #if defined(__x86_64__) || defined(__i386__)
12338 /*********************************************************************
12339 * Assumes sKextLock is held.
12340 *********************************************************************/
12341 /* static */
12342 OSReturn
12343 OSKext::mapKCFileSet(
12344 void *control,
12345 vm_size_t fsize,
12346 kernel_mach_header_t **mhp,
12347 off_t file_offset,
12348 uintptr_t *slidep,
12349 bool pageable,
12350 void *map_entry_list)
12351 {
12352 bool fileset_load = false;
12353 kern_return_t ret;
12354 OSReturn err;
12355 kernel_section_t *infoPlistSection = NULL;
12356 OSDictionary *infoDict = NULL;
12357
12358 OSSharedPtr<OSObject> parsedXML;
12359 OSSharedPtr<OSString> errorString;
12360 OSSharedPtr<OSData> loaded_kcUUID;
12361
12362 /* Check if initial load for file set */
12363 if (*mhp == NULL) {
12364 fileset_load = true;
12365
12366 /* Get a page aligned address from kext map to map the file */
12367 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12368 if (pagealigned_addr == 0) {
12369 return kOSKextReturnNoMemory;
12370 }
12371
12372 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12373
12374 /* Allocate memory for bailout mechanism */
12375 map_entry_list = allocate_kcfileset_map_entry_list();
12376 if (map_entry_list == NULL) {
12377 return kOSKextReturnNoMemory;
12378 }
12379 }
12380
12381 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12382 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12383 /* mhp and slideptr are updated by mapKCTextSegment */
12384 if (err) {
12385 if (fileset_load) {
12386 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12387 }
12388 return err;
12389 }
12390
12391 /* Initialize the kc header globals */
12392 if (fileset_load) {
12393 if (pageable) {
12394 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12395 } else {
12396 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12397 }
12398 }
12399
12400 /* Iterate through all the segments and map necessary segments */
12401 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12402 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12403 vm_map_offset_t start;
12404 kernel_mach_header_t *k_mh = NULL;
12405 kernel_segment_command_t * seg = NULL;
12406 struct fileset_entry_command *fse = NULL;
12407
12408 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12409 seg = (kernel_segment_command_t *)lcp;
12410 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12411 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12412 fse = (struct fileset_entry_command *)lcp;
12413 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12414
12415 /* Map the segments of the mach-o binary */
12416 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12417 if (err) {
12418 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12419 return kOSKextReturnInvalidArgument;
12420 }
12421 continue;
12422 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12423 /* Check if the Aux KC is built pageable style */
12424 if (!pageable && !fileset_load && !auxKCloaded) {
12425 resetAuxKCSegmentOnUnload = true;
12426 }
12427 continue;
12428 } else {
12429 continue;
12430 }
12431
12432 if (fileset_load) {
12433 if (seg->vmsize == 0) {
12434 continue;
12435 }
12436
12437 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12438 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12439 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12440 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12441 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12442 continue;
12443 }
12444 } else {
12445 if (seg->vmsize == 0) {
12446 continue;
12447 }
12448
12449 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12450 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12451 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12452 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12453 continue;
12454 }
12455 }
12456
12457 ret = vm_map_kcfileset_segment(
12458 &start, seg->vmsize,
12459 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12460
12461 if (ret != KERN_SUCCESS) {
12462 if (fileset_load) {
12463 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12464 }
12465 return kOSKextReturnInvalidArgument;
12466 }
12467 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12468 }
12469
12470 /* Return if regular mach-o */
12471 if (!fileset_load) {
12472 return 0;
12473 }
12474
12475 /*
12476 * Fixup for the Pageable KC and the Aux KC is done by
12477 * i386_slide_kext_collection_mh_addrs, but it differs in
12478 * following ways:
12479 *
12480 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12481 * The fixup of kext segments and kext load commands are done at kext
12482 * load time by calling i386_slide_individual_kext.
12483 *
12484 * AuxKC old style: Fixup all the segments and all the load commands.
12485 *
12486 * AuxKC pageable style: Same as the Pageable KC.
12487 */
12488 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12489 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12490 if (ret != KERN_SUCCESS) {
12491 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12492 return kOSKextReturnInvalidArgument;
12493 }
12494
12495 /* Get the prelink info dictionary */
12496 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12497 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12498 if (parsedXML) {
12499 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12500 }
12501
12502 if (!infoDict) {
12503 const char *errorCString = "(unknown error)";
12504
12505 if (errorString && errorString->getCStringNoCopy()) {
12506 errorCString = errorString->getCStringNoCopy();
12507 } else if (parsedXML) {
12508 errorCString = "not a dictionary";
12509 }
12510 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12511 "Error unserializing kext info plist section: %s.", errorCString);
12512 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12513 return kOSKextReturnInvalidArgument;
12514 }
12515
12516 /* Validate that the Kext Collection is prelinked to the loaded KC */
12517 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12518 if (err) {
12519 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12520 return kOSKextReturnInvalidArgument;
12521 }
12522
12523 /* Set Protection of Segments */
12524 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12525
12526 OSKext::addKextsFromKextCollection(*mhp,
12527 infoDict, kPrelinkTextSegment,
12528 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12529
12530 /* Copy in the KC UUID */
12531 if (!loaded_kcUUID) {
12532 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12533 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12534 } else if (pageable) {
12535 pageablekc_uuid_valid = TRUE;
12536 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12537 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12538 } else {
12539 auxkc_uuid_valid = TRUE;
12540 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12541 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12542 }
12543
12544 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12545
12546 return 0;
12547 }
12548
12549 /*********************************************************************
12550 * Assumes sKextLock is held.
12551 *********************************************************************/
12552 /* static */
12553 OSReturn
12554 OSKext::mapKCTextSegment(
12555 void *control,
12556 kernel_mach_header_t **mhp,
12557 off_t file_offset,
12558 uintptr_t *slidep,
12559 void *map_entry_list)
12560 {
12561 kern_return_t ret;
12562 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12563 PAGE_MASK);
12564 vm_map_offset_t load_command_map_size = 0;
12565 kernel_mach_header_t *base_mh = *mhp;
12566
12567 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12568 ret = vm_map_kcfileset_segment(
12569 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12570 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12571
12572 if (ret != KERN_SUCCESS) {
12573 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12574
12575 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12576 "Failed to map mach header of kc fileset with error %d", ret);
12577 return kOSKextReturnInvalidArgument;
12578 }
12579
12580 if (slidep) {
12581 /* Verify that it's an MH_FILESET */
12582 if (base_mh->filetype != MH_FILESET) {
12583 printf("Kext Log: mapKCTextSegment mach header filetype"
12584 " is not an MH_FILESET, it is %x", base_mh->filetype);
12585
12586 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12587 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12588
12589 /* Unmap the mach header */
12590 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12591 return kOSKextReturnInvalidArgument;
12592 }
12593 }
12594
12595 /* Map the remaining pages of load commands */
12596 if (base_mh->sizeofcmds > mach_header_map_size) {
12597 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12598 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12599
12600 /* Map the load commands */
12601 ret = vm_map_kcfileset_segment(
12602 &load_command_addr, load_command_map_size,
12603 (memory_object_control_t)control, file_offset + mach_header_map_size,
12604 (VM_PROT_READ | VM_PROT_WRITE));
12605
12606 if (ret != KERN_SUCCESS) {
12607 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12608 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12609 "Failed to map load commands of kc fileset with error %d", ret);
12610
12611 /* Unmap the mach header */
12612 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12613 return kOSKextReturnInvalidArgument;
12614 }
12615 }
12616
12617 kernel_segment_command_t *text_seg;
12618 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12619
12620 /* Calculate the slide and vm addr of mach header */
12621 if (slidep) {
12622 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12623 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12624 }
12625
12626 /* Cache the text segment size and file offset before unmapping */
12627 vm_map_offset_t text_segment_size = text_seg->vmsize;
12628 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12629 vm_prot_t text_maxprot = text_seg->maxprot;
12630
12631 /* Unmap the first page and loadcommands and map the text segment */
12632 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12633 assert(ret == KERN_SUCCESS);
12634
12635 if (load_command_map_size) {
12636 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12637 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12638 assert(ret == KERN_SUCCESS);
12639 }
12640
12641 /* Map the text segment at actual vm addr specified in fileset */
12642 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12643 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12644 if (ret != KERN_SUCCESS) {
12645 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12646 "Failed to map Text segment of kc fileset with error %d", ret);
12647 return kOSKextReturnInvalidArgument;
12648 }
12649
12650 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12651 return 0;
12652 }
12653
12654 /*********************************************************************
12655 * Assumes sKextLock is held.
12656 *********************************************************************/
12657 /* static */
12658 OSReturn
12659 OSKext::protectKCFileSet(
12660 kernel_mach_header_t *mh,
12661 kc_kind_t type)
12662 {
12663 vm_map_t kext_map = g_kext_map;
12664 kernel_segment_command_t * seg = NULL;
12665 vm_map_offset_t start = 0;
12666 vm_map_offset_t end = 0;
12667 OSReturn ret = 0;
12668
12669 /* Set VM permissions */
12670 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12671 while (seg) {
12672 start = round_page(seg->vmaddr);
12673 end = trunc_page(seg->vmaddr + seg->vmsize);
12674
12675 /*
12676 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12677 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12678 * for the Aux KC as well.
12679 */
12680 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12681 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12682 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12683 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12684 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12685 ret = OSKext_protect((kernel_mach_header_t *)mh,
12686 kext_map, start, end, seg->maxprot, TRUE, type);
12687 if (ret != KERN_SUCCESS) {
12688 printf("OSKext protect failed with error %d", ret);
12689 return kOSKextReturnInvalidArgument;
12690 }
12691
12692 ret = OSKext_protect((kernel_mach_header_t *)mh,
12693 kext_map, start, end, seg->initprot, FALSE, type);
12694 if (ret != KERN_SUCCESS) {
12695 printf("OSKext protect failed with error %d", ret);
12696 return kOSKextReturnInvalidArgument;
12697 }
12698
12699 ret = OSKext_wire((kernel_mach_header_t *)mh,
12700 kext_map, start, end, seg->initprot, FALSE, type);
12701 if (ret != KERN_SUCCESS) {
12702 printf("OSKext wire failed with error %d", ret);
12703 return kOSKextReturnInvalidArgument;
12704 }
12705 }
12706
12707 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12708 }
12709
12710 return 0;
12711 }
12712
12713 /*********************************************************************
12714 * Assumes sKextLock is held.
12715 *********************************************************************/
12716 /* static */
12717 void
12718 OSKext::freeKCFileSetcontrol(void)
12719 {
12720 PE_reset_all_kc_vp();
12721 }
12722
12723 /*********************************************************************
12724 * Assumes sKextLock is held.
12725 *
12726 * resetKCFileSetSegments: Kext start function expects data segment to
12727 * be pristine on every load, unmap the dirty segments on unload and
12728 * remap them from FileSet on disk. Remap all segments of kext since
12729 * fixups are done per kext and not per segment.
12730 *********************************************************************/
12731 OSReturn
12732 OSKext::resetKCFileSetSegments(void)
12733 {
12734 kernel_segment_command_t *seg = NULL;
12735 kernel_segment_command_t *text_seg;
12736 uint32_t text_fileoff;
12737 kernel_mach_header_t *k_mh = NULL;
12738 uintptr_t slide;
12739 struct vnode *vp = NULL;
12740 void *fileset_control = NULL;
12741 bool pageable = (kc_type == KCKindPageable);
12742 OSReturn err;
12743 kern_return_t kr;
12744
12745 /* Check the vnode reference is still available */
12746 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12747 if (vp == NULL) {
12748 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12749 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12750 return kOSKextReturnInternalError;
12751 }
12752
12753 fileset_control = ubc_getobject(vp, 0);
12754 assert(fileset_control != NULL);
12755
12756 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12757 "Kext %s resetting all segments", getIdentifierCString());
12758
12759 k_mh = (kernel_mach_header_t *)kmod_info->address;
12760 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12761 text_fileoff = text_seg->fileoff;
12762 slide = PE_get_kc_slide(kc_type);
12763
12764 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12765 while (seg) {
12766 if (seg->vmsize == 0) {
12767 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12768 continue;
12769 }
12770
12771 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12772 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12773 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12774 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12775 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12776 continue;
12777 }
12778
12779 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12780 assert(kr == KERN_SUCCESS);
12781 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12782 }
12783
12784 /* Unmap the text segment */
12785 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12786 assert(kr == KERN_SUCCESS);
12787
12788 /* Map all the segments of the kext */
12789 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12790 if (err) {
12791 panic("Could not reset segments of a mapped kext, error %x", err);
12792 }
12793
12794 /* Update address in kmod_info, since it has been reset */
12795 if (kmod_info->address) {
12796 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12797 }
12798
12799 return 0;
12800 }
12801
12802 /*********************************************************************
12803 * Mechanism to track all segment mapping while mapping KC fileset.
12804 *********************************************************************/
12805
12806 struct kcfileset_map_entry {
12807 vm_map_offset_t me_start;
12808 vm_map_offset_t me_size;
12809 };
12810
12811 struct kcfileset_map_entry_list {
12812 int kme_list_count;
12813 int kme_list_index;
12814 struct kcfileset_map_entry kme_list[];
12815 };
12816
12817 #define KCFILESET_MAP_ENTRY_MAX (16380)
12818
12819 static void *
12820 allocate_kcfileset_map_entry_list(void)
12821 {
12822 struct kcfileset_map_entry_list *entry_list;
12823
12824 entry_list = kalloc_type(struct kcfileset_map_entry_list,
12825 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
12826
12827 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12828 entry_list->kme_list_index = 0;
12829 return entry_list;
12830 }
12831
12832 static void
12833 add_kcfileset_map_entry(
12834 void *map_entry_list,
12835 vm_map_offset_t start,
12836 vm_map_offset_t size)
12837 {
12838 if (map_entry_list == NULL) {
12839 return;
12840 }
12841
12842 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12843
12844 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12845 panic("Ran out of map kc fileset list");
12846 }
12847
12848 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12849 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12850
12851 entry_list->kme_list_index++;
12852 }
12853
12854 static void
12855 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12856 void *map_entry_list,
12857 boolean_t unmap_entries,
12858 bool pageable)
12859 {
12860 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12861
12862 if (unmap_entries) {
12863 for (int i = 0; i < entry_list->kme_list_index; i++) {
12864 kern_return_t ret;
12865 ret = vm_unmap_kcfileset_segment(
12866 &(entry_list->kme_list[i].me_start),
12867 entry_list->kme_list[i].me_size);
12868 assert(ret == KERN_SUCCESS);
12869 }
12870
12871 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
12872 }
12873
12874 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
12875 KCFILESET_MAP_ENTRY_MAX, entry_list);
12876 }
12877
12878 /*********************************************************************
12879 * Mechanism to map kext segment.
12880 *********************************************************************/
12881
12882 kern_return_t
12883 vm_map_kcfileset_segment(
12884 vm_map_offset_t *start,
12885 vm_map_offset_t size,
12886 void *control,
12887 vm_object_offset_t fileoffset,
12888 vm_prot_t max_prot)
12889 {
12890 vm_map_kernel_flags_t vmk_flags;
12891 vmk_flags.vmkf_no_copy_on_read = 1;
12892 vmk_flags.vmkf_cs_enforcement = 0;
12893 vmk_flags.vmkf_cs_enforcement_override = 1;
12894 kern_return_t ret;
12895
12896 /* Add Write to max prot to allow fixups */
12897 max_prot = max_prot | VM_PROT_WRITE;
12898
12899 /*
12900 * Map the segments from file as COPY mappings to
12901 * make sure changes on disk to the file does not affect
12902 * mapped segments.
12903 */
12904 ret = vm_map_enter_mem_object_control(
12905 g_kext_map,
12906 start,
12907 size,
12908 (mach_vm_offset_t)0,
12909 VM_FLAGS_FIXED,
12910 vmk_flags,
12911 VM_KERN_MEMORY_OSKEXT,
12912 (memory_object_control_t)control,
12913 fileoffset,
12914 TRUE, /* copy */
12915 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12916 VM_INHERIT_NONE);
12917
12918 return ret;
12919 }
12920
12921 kern_return_t
12922 vm_unmap_kcfileset_segment(
12923 vm_map_offset_t *start,
12924 vm_map_offset_t size)
12925 {
12926 return mach_vm_deallocate(g_kext_map, *start, size);
12927 }
12928
12929 #endif //(__x86_64__) || defined(__i386__)
12930
12931 /*********************************************************************
12932 * Assumes sKextLock is held.
12933 *********************************************************************/
12934 /* static */
12935 OSReturn
12936 OSKext::validateKCFileSetUUID(
12937 OSDictionary *infoDict,
12938 kc_kind_t type)
12939 {
12940 OSReturn ret = kOSReturnSuccess;
12941
12942 if (!kernelcache_uuid_valid) {
12943 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12944 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12945 ret = kOSKextReturnInvalidArgument;
12946 goto finish;
12947 }
12948 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12949 if (ret != 0) {
12950 goto finish;
12951 }
12952
12953 #if defined(__x86_64__) || defined(__i386__)
12954 /* Check if the Aux KC is prelinked to correct Pageable KC */
12955 if (type == KCKindAuxiliary) {
12956 if (!pageablekc_uuid_valid) {
12957 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12958 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12959 ret = kOSKextReturnInvalidArgument;
12960 goto finish;
12961 }
12962 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12963 if (ret != 0) {
12964 goto finish;
12965 }
12966 }
12967 #endif //(__x86_64__) || defined(__i386__)
12968
12969 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12970 finish:
12971 return ret;
12972 }
12973
12974 /*********************************************************************
12975 * Assumes sKextLock is held.
12976 *********************************************************************/
12977 /* static */
12978 OSReturn
12979 OSKext::validateKCUUIDfromPrelinkInfo(
12980 uuid_t *loaded_kcuuid,
12981 kc_kind_t type,
12982 OSDictionary *infoDict,
12983 const char *uuid_key)
12984 {
12985 /* extract the UUID from the dictionary */
12986 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12987 if (!prelinkinfoKCUUID) {
12988 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12989 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12990 return kOSKextReturnInvalidArgument;
12991 }
12992
12993 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12994 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12995 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12996 return kOSKextReturnInvalidArgument;
12997 }
12998
12999 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
13000 prelinkinfoKCUUID->getLength())) {
13001 OSData *info_dict_uuid;
13002 uuid_string_t info_dict_uuid_str = {};
13003 uuid_string_t expected_uuid_str = {};
13004 uuid_string_t given_uuid_str = {};
13005 uuid_t given_uuid;
13006
13007 /* extract the KC UUID from the dictionary */
13008 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
13009 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
13010 uuid_t tmp_uuid;
13011 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
13012 uuid_unparse(tmp_uuid, info_dict_uuid_str);
13013 }
13014
13015 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
13016 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
13017 uuid_unparse(given_uuid, given_uuid_str);
13018
13019 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
13020 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
13021 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13022 "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 if (type == KCKindPageable && sPanicOnKCMismatch) {
13025 panic("System KC UUID %s linked against %s, but %s is loaded",
13026 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
13027 }
13028 return kOSKextReturnInvalidArgument;
13029 }
13030
13031 return 0;
13032 }
13033
13034 /*********************************************************************
13035 * Assumes sKextLock is held.
13036 *********************************************************************/
13037 /* static */
13038 OSReturn
13039 OSKext::dispatchResource(OSDictionary * requestDict)
13040 {
13041 OSReturn result = kOSReturnError;
13042 OSSharedPtr<OSDictionary> callbackRecord;
13043 OSNumber * requestTag = NULL; // do not release
13044 OSNumber * requestResult = NULL; // do not release
13045 OSData * dataObj = NULL; // do not release
13046 uint32_t dataLength = 0;
13047 const void * dataPtr = NULL; // do not free
13048 OSData * callbackWrapper = NULL; // do not release
13049 OSKextRequestResourceCallback callback = NULL;
13050 OSData * contextWrapper = NULL; // do not release
13051 void * context = NULL; // do not free
13052 OSSharedPtr<OSKext> callbackKext;
13053
13054 /* Get the args from the request. Right now we need the tag
13055 * to look up the callback record, and the result for invoking the callback.
13056 */
13057 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
13058 kKextRequestArgumentRequestTagKey));
13059 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
13060 kKextRequestArgumentResultKey));
13061 if (!requestTag || !requestResult) {
13062 result = kOSKextReturnInvalidArgument;
13063 goto finish;
13064 }
13065
13066 /* Look for a callback record matching this request's tag.
13067 */
13068 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
13069 if (result != kOSReturnSuccess) {
13070 goto finish;
13071 }
13072
13073 /*****
13074 * Get the context pointer of the callback record (if there is one).
13075 */
13076 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord.get(),
13077 kKextRequestArgumentContextKey));
13078 context = _OSKextExtractPointer(contextWrapper);
13079 if (contextWrapper && !context) {
13080 goto finish;
13081 }
13082
13083 callbackWrapper = OSDynamicCast(OSData,
13084 _OSKextGetRequestArgument(callbackRecord.get(),
13085 kKextRequestArgumentCallbackKey));
13086 callback = _OSKextExtractCallbackPointer(callbackWrapper);
13087 if (!callback) {
13088 goto finish;
13089 }
13090
13091 /* Check for a data obj. We might not have one and that's ok, that means
13092 * we didn't find the requested resource, and we still have to tell the
13093 * caller that via the callback.
13094 */
13095 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
13096 kKextRequestArgumentValueKey));
13097 if (dataObj) {
13098 dataPtr = dataObj->getBytesNoCopy();
13099 dataLength = dataObj->getLength();
13100 }
13101
13102 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
13103 if (!callbackKext) {
13104 OSKextLog(/* kext */ NULL,
13105 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13106 "Can't invoke callback for resource request; ");
13107 goto finish;
13108 }
13109 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
13110 OSKextLog(/* kext */ NULL,
13111 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13112 "Can't invoke kext resource callback; ");
13113 goto finish;
13114 }
13115
13116 (void)callback(requestTag->unsigned32BitValue(),
13117 (OSReturn)requestResult->unsigned32BitValue(),
13118 dataPtr, dataLength, context);
13119
13120 result = kOSReturnSuccess;
13121
13122 finish:
13123 return result;
13124 }
13125
13126 /*********************************************************************
13127 * Assumes sKextLock is held.
13128 *********************************************************************/
13129 /* static */
13130 OSReturn
13131 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
13132 {
13133 OSSharedPtr<OSDictionary> missingIDs;
13134 OSArray *bundleIDList = NULL; // do not release
13135
13136 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
13137 requestDict, kKextRequestArgumentMissingBundleIDs));
13138 if (!bundleIDList) {
13139 return kOSKextReturnInvalidArgument;
13140 }
13141
13142 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
13143 if (!missingIDs) {
13144 return kOSKextReturnNoMemory;
13145 }
13146
13147 uint32_t count, i;
13148 count = bundleIDList->getCount();
13149 for (i = 0; i < count; i++) {
13150 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
13151 if (thisID) {
13152 missingIDs->setObject(thisID, kOSBooleanFalse);
13153 }
13154 }
13155
13156 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13157
13158 return kOSReturnSuccess;
13159 }
13160
13161 /*********************************************************************
13162 * Assumes sKextLock is held.
13163 *********************************************************************/
13164 /* static */
13165 OSReturn
13166 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13167 {
13168 bool loadable = true;
13169 if (!kextIdentifier) {
13170 return kOSKextReturnInvalidArgument;
13171 }
13172
13173 if (requestDict) {
13174 OSBoolean *loadableArg;
13175 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13176 requestDict, kKextRequestArgumentBundleAvailability));
13177 /* If we find the "Bundle Available" arg, and it's false, then
13178 * mark the bundle ID as _not_ loadable
13179 */
13180 if (loadableArg && !loadableArg->getValue()) {
13181 loadable = false;
13182 }
13183 }
13184
13185 if (!sNonLoadableKextsByID) {
13186 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13187 }
13188
13189 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13190
13191 OSKextLog(/* kext */ NULL,
13192 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13193 "KextLog: AuxKC bundle %s marked as %s",
13194 kextIdentifier->getCStringNoCopy(),
13195 (loadable ? "loadable" : "NOT loadable"));
13196
13197 return kOSReturnSuccess;
13198 }
13199
13200 /*********************************************************************
13201 *********************************************************************/
13202 /* static */
13203 void
13204 OSKext::invokeRequestCallback(
13205 OSDictionary * callbackRecord,
13206 OSReturn callbackResult)
13207 {
13208 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
13209 OSSharedPtr<OSNumber> resultNum;
13210
13211 if (!predicate) {
13212 goto finish;
13213 }
13214
13215 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13216 8 * sizeof(callbackResult));
13217 if (!resultNum) {
13218 goto finish;
13219 }
13220
13221 /* Insert the result into the callback record and dispatch it as if it
13222 * were the reply coming down from user space.
13223 */
13224 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
13225 resultNum.get());
13226
13227 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13228 /* This removes the pending callback record.
13229 */
13230 OSKext::dispatchResource(callbackRecord);
13231 }
13232
13233 finish:
13234 return;
13235 }
13236
13237 /*********************************************************************
13238 * Assumes sKextLock is held.
13239 *********************************************************************/
13240 /* static */
13241 OSReturn
13242 OSKext::cancelRequest(
13243 OSKextRequestTag requestTag,
13244 void ** contextOut)
13245 {
13246 OSReturn result = kOSKextReturnNoMemory;
13247 OSSharedPtr<OSDictionary> callbackRecord;
13248 OSData * contextWrapper = NULL; // do not release
13249
13250 IORecursiveLockLock(sKextLock);
13251 result = OSKext::dequeueCallbackForRequestTag(requestTag,
13252 callbackRecord);
13253 IORecursiveLockUnlock(sKextLock);
13254
13255 if (result == kOSReturnSuccess && contextOut) {
13256 contextWrapper = OSDynamicCast(OSData,
13257 _OSKextGetRequestArgument(callbackRecord.get(),
13258 kKextRequestArgumentContextKey));
13259 *contextOut = _OSKextExtractPointer(contextWrapper);
13260 }
13261
13262 return result;
13263 }
13264
13265 /*********************************************************************
13266 * Assumes sKextLock is held.
13267 *********************************************************************/
13268 void
13269 OSKext::invokeOrCancelRequestCallbacks(
13270 OSReturn callbackResult,
13271 bool invokeFlag)
13272 {
13273 unsigned int count, i;
13274
13275 count = sRequestCallbackRecords->getCount();
13276 if (!count) {
13277 goto finish;
13278 }
13279
13280 i = count - 1;
13281 do {
13282 OSDictionary * request = OSDynamicCast(OSDictionary,
13283 sRequestCallbackRecords->getObject(i));
13284
13285 if (!request) {
13286 continue;
13287 }
13288 OSData * callbackWrapper = OSDynamicCast(OSData,
13289 _OSKextGetRequestArgument(request,
13290 kKextRequestArgumentCallbackKey));
13291
13292 if (!callbackWrapper) {
13293 sRequestCallbackRecords->removeObject(i);
13294 continue;
13295 }
13296
13297 vm_address_t callbackAddress = (vm_address_t)
13298 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13299
13300 if ((kmod_info->address <= callbackAddress) &&
13301 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13302 if (invokeFlag) {
13303 /* This removes the callback record.
13304 */
13305 invokeRequestCallback(request, callbackResult);
13306 } else {
13307 sRequestCallbackRecords->removeObject(i);
13308 }
13309 }
13310 } while (i--);
13311
13312 finish:
13313 return;
13314 }
13315
13316 /*********************************************************************
13317 * Assumes sKextLock is held.
13318 *********************************************************************/
13319 uint32_t
13320 OSKext::countRequestCallbacks(void)
13321 {
13322 uint32_t result = 0;
13323 unsigned int count, i;
13324
13325 count = sRequestCallbackRecords->getCount();
13326 if (!count) {
13327 goto finish;
13328 }
13329
13330 i = count - 1;
13331 do {
13332 OSDictionary * request = OSDynamicCast(OSDictionary,
13333 sRequestCallbackRecords->getObject(i));
13334
13335 if (!request) {
13336 continue;
13337 }
13338 OSData * callbackWrapper = OSDynamicCast(OSData,
13339 _OSKextGetRequestArgument(request,
13340 kKextRequestArgumentCallbackKey));
13341
13342 if (!callbackWrapper) {
13343 continue;
13344 }
13345
13346 vm_address_t callbackAddress = (vm_address_t)
13347 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13348
13349 if ((kmod_info->address <= callbackAddress) &&
13350 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13351 result++;
13352 }
13353 } while (i--);
13354
13355 finish:
13356 return result;
13357 }
13358
13359 /*********************************************************************
13360 *********************************************************************/
13361 static OSReturn
13362 _OSKextCreateRequest(
13363 const char * predicate,
13364 OSSharedPtr<OSDictionary> & requestR)
13365 {
13366 OSReturn result = kOSKextReturnNoMemory;
13367 OSSharedPtr<OSDictionary> request;
13368
13369 request = OSDictionary::withCapacity(2);
13370 if (!request) {
13371 goto finish;
13372 }
13373 result = _OSDictionarySetCStringValue(request.get(),
13374 kKextRequestPredicateKey, predicate);
13375 if (result != kOSReturnSuccess) {
13376 goto finish;
13377 }
13378 result = kOSReturnSuccess;
13379
13380 finish:
13381 if (result == kOSReturnSuccess) {
13382 requestR = os::move(request);
13383 }
13384
13385 return result;
13386 }
13387
13388 /*********************************************************************
13389 *********************************************************************/
13390 static OSString *
13391 _OSKextGetRequestPredicate(OSDictionary * requestDict)
13392 {
13393 return OSDynamicCast(OSString,
13394 requestDict->getObject(kKextRequestPredicateKey));
13395 }
13396
13397 /*********************************************************************
13398 *********************************************************************/
13399 static OSObject *
13400 _OSKextGetRequestArgument(
13401 OSDictionary * requestDict,
13402 const char * argName)
13403 {
13404 OSDictionary * args = OSDynamicCast(OSDictionary,
13405 requestDict->getObject(kKextRequestArgumentsKey));
13406 if (args) {
13407 return args->getObject(argName);
13408 }
13409 return NULL;
13410 }
13411
13412 /*********************************************************************
13413 *********************************************************************/
13414 static bool
13415 _OSKextSetRequestArgument(
13416 OSDictionary * requestDict,
13417 const char * argName,
13418 OSObject * value)
13419 {
13420 OSDictionary * args = OSDynamicCast(OSDictionary,
13421 requestDict->getObject(kKextRequestArgumentsKey));
13422 OSSharedPtr<OSDictionary> newArgs;
13423 if (!args) {
13424 newArgs = OSDictionary::withCapacity(2);
13425 args = newArgs.get();
13426 if (!args) {
13427 goto finish;
13428 }
13429 requestDict->setObject(kKextRequestArgumentsKey, args);
13430 }
13431 if (args) {
13432 return args->setObject(argName, value);
13433 }
13434 finish:
13435 return false;
13436 }
13437
13438 /*********************************************************************
13439 *********************************************************************/
13440 static void *
13441 _OSKextExtractPointer(OSData * wrapper)
13442 {
13443 void * result = NULL;
13444 const void * resultPtr = NULL;
13445
13446 if (!wrapper) {
13447 goto finish;
13448 }
13449 resultPtr = wrapper->getBytesNoCopy();
13450 result = *(void **)resultPtr;
13451 finish:
13452 return result;
13453 }
13454
13455 /*********************************************************************
13456 *********************************************************************/
13457 static OSKextRequestResourceCallback
13458 _OSKextExtractCallbackPointer(OSData * wrapper)
13459 {
13460 OSKextRequestResourceCallback result = NULL;
13461 const void * resultPtr = NULL;
13462
13463 if (!wrapper) {
13464 goto finish;
13465 }
13466 resultPtr = wrapper->getBytesNoCopy();
13467 result = *(OSKextRequestResourceCallback *)resultPtr;
13468 finish:
13469 return result;
13470 }
13471
13472
13473 /*********************************************************************
13474 *********************************************************************/
13475 static OSReturn
13476 _OSDictionarySetCStringValue(
13477 OSDictionary * dict,
13478 const char * cKey,
13479 const char * cValue)
13480 {
13481 OSReturn result = kOSKextReturnNoMemory;
13482 OSSharedPtr<const OSSymbol> key;
13483 OSSharedPtr<OSString> value;
13484
13485 key = OSSymbol::withCString(cKey);
13486 value = OSString::withCString(cValue);
13487 if (!key || !value) {
13488 goto finish;
13489 }
13490 if (dict->setObject(key.get(), value.get())) {
13491 result = kOSReturnSuccess;
13492 }
13493
13494 finish:
13495 return result;
13496 }
13497
13498 /*********************************************************************
13499 *********************************************************************/
13500 static bool
13501 _OSArrayContainsCString(
13502 OSArray * array,
13503 const char * cString)
13504 {
13505 bool result = false;
13506 OSSharedPtr<const OSSymbol> symbol;
13507 uint32_t count, i;
13508
13509 if (!array || !cString) {
13510 goto finish;
13511 }
13512
13513 symbol = OSSymbol::withCStringNoCopy(cString);
13514 if (!symbol) {
13515 goto finish;
13516 }
13517
13518 count = array->getCount();
13519 for (i = 0; i < count; i++) {
13520 OSObject * thisObject = array->getObject(i);
13521 if (symbol->isEqualTo(thisObject)) {
13522 result = true;
13523 goto finish;
13524 }
13525 }
13526
13527 finish:
13528 return result;
13529 }
13530
13531 #if CONFIG_KXLD
13532 /*********************************************************************
13533 * We really only care about boot / system start up related kexts.
13534 * We return true if we're less than REBUILD_MAX_TIME since start up,
13535 * otherwise return false.
13536 *********************************************************************/
13537 bool
13538 _OSKextInPrelinkRebuildWindow(void)
13539 {
13540 static bool outside_the_window = false;
13541 AbsoluteTime my_abstime;
13542 UInt64 my_ns;
13543 SInt32 my_secs;
13544
13545 if (outside_the_window) {
13546 return false;
13547 }
13548 clock_get_uptime(&my_abstime);
13549 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13550 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13551 if (my_secs > REBUILD_MAX_TIME) {
13552 outside_the_window = true;
13553 return false;
13554 }
13555 return true;
13556 }
13557 #endif /* CONFIG_KXLD */
13558
13559 /*********************************************************************
13560 *********************************************************************/
13561 bool
13562 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13563 {
13564 int unLoadedCount, i;
13565 bool result = false;
13566
13567 IORecursiveLockLock(sKextLock);
13568
13569 if (sUnloadedPrelinkedKexts == NULL) {
13570 goto finish;
13571 }
13572 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13573 if (unLoadedCount == 0) {
13574 goto finish;
13575 }
13576
13577 for (i = 0; i < unLoadedCount; i++) {
13578 const OSSymbol * myBundleID; // do not release
13579
13580 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13581 if (!myBundleID) {
13582 continue;
13583 }
13584 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13585 result = true;
13586 break;
13587 }
13588 }
13589 finish:
13590 IORecursiveLockUnlock(sKextLock);
13591 return result;
13592 }
13593
13594 #if PRAGMA_MARK
13595 #pragma mark Personalities (IOKit Drivers)
13596 #endif
13597 /*********************************************************************
13598 *********************************************************************/
13599 /* static */
13600 OSSharedPtr<OSArray>
13601 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13602 {
13603 OSSharedPtr<OSArray> result;
13604 OSSharedPtr<OSCollectionIterator> kextIterator;
13605 OSSharedPtr<OSArray> personalities;
13606
13607 OSString * kextID = NULL; // do not release
13608 OSKext * theKext = NULL; // do not release
13609
13610 IORecursiveLockLock(sKextLock);
13611
13612 /* Let's conservatively guess that any given kext has around 3
13613 * personalities for now.
13614 */
13615 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13616 if (!result) {
13617 goto finish;
13618 }
13619
13620 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
13621 if (!kextIterator) {
13622 goto finish;
13623 }
13624
13625 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
13626 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
13627 if (theKext->flags.requireExplicitLoad) {
13628 OSKextLog(theKext,
13629 kOSKextLogDebugLevel |
13630 kOSKextLogLoadFlag,
13631 "Kext %s requires an explicit kextload; "
13632 "omitting its personalities.",
13633 theKext->getIdentifierCString());
13634 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
13635 personalities = theKext->copyPersonalitiesArray();
13636 if (!personalities) {
13637 continue;
13638 }
13639 result->merge(personalities.get());
13640 } else {
13641 // xxx - check for better place to put this log msg
13642 OSKextLog(theKext,
13643 kOSKextLogWarningLevel |
13644 kOSKextLogLoadFlag,
13645 "Kext %s is not loadable during safe boot; "
13646 "omitting its personalities.",
13647 theKext->getIdentifierCString());
13648 }
13649 }
13650
13651 finish:
13652 IORecursiveLockUnlock(sKextLock);
13653
13654 return result;
13655 }
13656
13657 /*********************************************************************
13658 *********************************************************************/
13659 /* static */
13660 void
13661 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13662 {
13663 int numPersonalities = 0;
13664
13665 OSKextLog(/* kext */ NULL,
13666 kOSKextLogStepLevel |
13667 kOSKextLogLoadFlag,
13668 "Sending all eligible registered kexts' personalities "
13669 "to the IOCatalogue %s.",
13670 startMatching ? "and starting matching" : "but not starting matching");
13671
13672 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
13673 /* filterSafeBootFlag */ true);
13674
13675 if (personalities) {
13676 gIOCatalogue->addDrivers(personalities.get(), startMatching);
13677 numPersonalities = personalities->getCount();
13678 }
13679
13680 OSKextLog(/* kext */ NULL,
13681 kOSKextLogStepLevel |
13682 kOSKextLogLoadFlag,
13683 "%d kext personalit%s sent to the IOCatalogue; %s.",
13684 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13685 startMatching ? "matching started" : "matching not started");
13686 return;
13687 }
13688
13689 /*********************************************************************
13690 * Do not make a deep copy, just convert the IOKitPersonalities dict
13691 * to an array for sending to the IOCatalogue.
13692 *********************************************************************/
13693 OSSharedPtr<OSArray>
13694 OSKext::copyPersonalitiesArray(void)
13695 {
13696 OSSharedPtr<OSArray> result;
13697 OSDictionary * personalities = NULL; // do not release
13698 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
13699
13700 OSString * personalityName = NULL; // do not release
13701 OSString * personalityBundleIdentifier = NULL; // do not release
13702
13703 personalities = OSDynamicCast(OSDictionary,
13704 getPropertyForHostArch(kIOKitPersonalitiesKey));
13705 if (!personalities) {
13706 goto finish;
13707 }
13708
13709 result = OSArray::withCapacity(personalities->getCount());
13710 if (!result) {
13711 goto finish;
13712 }
13713
13714 personalitiesIterator =
13715 OSCollectionIterator::withCollection(personalities);
13716 if (!personalitiesIterator) {
13717 goto finish;
13718 }
13719 while ((personalityName = OSDynamicCast(OSString,
13720 personalitiesIterator->getNextObject()))) {
13721 OSDictionary * personality = OSDynamicCast(OSDictionary,
13722 personalities->getObject(personalityName));
13723
13724 /******
13725 * If the personality doesn't have a CFBundleIdentifier, or if it
13726 * differs from the kext's, insert the kext's ID so we can find it.
13727 * The publisher ID is used to remove personalities from bundles
13728 * correctly.
13729 */
13730 personalityBundleIdentifier = OSDynamicCast(OSString,
13731 personality->getObject(kCFBundleIdentifierKey));
13732
13733 if (!personalityBundleIdentifier) {
13734 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13735 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13736 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
13737 }
13738
13739 result->setObject(personality);
13740 }
13741
13742 finish:
13743 return result;
13744 }
13745
13746 /*********************************************************************
13747 * Might want to change this to a bool return?
13748 *********************************************************************/
13749 OSReturn
13750 OSKext::sendPersonalitiesToCatalog(
13751 bool startMatching,
13752 OSArray * personalityNames)
13753 {
13754 OSReturn result = kOSReturnSuccess;
13755 OSSharedPtr<OSArray> personalitiesToSend;
13756 OSDictionary * kextPersonalities = NULL; // do not release
13757 int count, i;
13758
13759 if (!sLoadEnabled) {
13760 OSKextLog(this,
13761 kOSKextLogErrorLevel |
13762 kOSKextLogLoadFlag,
13763 "Kext loading is disabled (attempt to start matching for kext %s).",
13764 getIdentifierCString());
13765 result = kOSKextReturnDisabled;
13766 goto finish;
13767 }
13768
13769 if (sSafeBoot && !isLoadableInSafeBoot()) {
13770 OSKextLog(this,
13771 kOSKextLogErrorLevel |
13772 kOSKextLogLoadFlag,
13773 "Kext %s is not loadable during safe boot; "
13774 "not sending personalities to the IOCatalogue.",
13775 getIdentifierCString());
13776 result = kOSKextReturnNotLoadable;
13777 goto finish;
13778 }
13779
13780 if (!personalityNames || !personalityNames->getCount()) {
13781 personalitiesToSend = copyPersonalitiesArray();
13782 } else {
13783 kextPersonalities = OSDynamicCast(OSDictionary,
13784 getPropertyForHostArch(kIOKitPersonalitiesKey));
13785 if (!kextPersonalities || !kextPersonalities->getCount()) {
13786 // not an error
13787 goto finish;
13788 }
13789 personalitiesToSend = OSArray::withCapacity(0);
13790 if (!personalitiesToSend) {
13791 result = kOSKextReturnNoMemory;
13792 goto finish;
13793 }
13794 count = personalityNames->getCount();
13795 for (i = 0; i < count; i++) {
13796 OSString * name = OSDynamicCast(OSString,
13797 personalityNames->getObject(i));
13798 if (!name) {
13799 continue;
13800 }
13801 OSDictionary * personality = OSDynamicCast(OSDictionary,
13802 kextPersonalities->getObject(name));
13803 if (personality) {
13804 personalitiesToSend->setObject(personality);
13805 }
13806 }
13807 }
13808 if (personalitiesToSend) {
13809 unsigned numPersonalities = personalitiesToSend->getCount();
13810 OSKextLog(this,
13811 kOSKextLogStepLevel |
13812 kOSKextLogLoadFlag,
13813 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13814 getIdentifierCString(),
13815 numPersonalities,
13816 numPersonalities > 1 ? "ies" : "y",
13817 startMatching ? " and starting matching" : " but not starting matching");
13818 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
13819 }
13820 finish:
13821 return result;
13822 }
13823
13824 /*********************************************************************
13825 * xxx - We should allow removing the kext's declared personalities,
13826 * xxx - even with other bundle identifiers.
13827 *********************************************************************/
13828 void
13829 OSKext::removePersonalitiesFromCatalog(void)
13830 {
13831 OSSharedPtr<OSDictionary> personality;
13832
13833 personality = OSDictionary::withCapacity(1);
13834 if (!personality) {
13835 goto finish;
13836 }
13837 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
13838
13839 OSKextLog(this,
13840 kOSKextLogStepLevel |
13841 kOSKextLogLoadFlag,
13842 "Kext %s removing all personalities naming it from the IOCatalogue.",
13843 getIdentifierCString());
13844
13845 /* Have the IOCatalog remove all personalities matching this kext's
13846 * bundle ID and trigger matching anew.
13847 */
13848 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
13849
13850 finish:
13851 return;
13852 }
13853
13854
13855 #if PRAGMA_MARK
13856 #pragma mark Logging
13857 #endif
13858 /*********************************************************************
13859 * Do not call any function that takes sKextLock here!
13860 *********************************************************************/
13861 /* static */
13862 OSKextLogSpec
13863 OSKext::setUserSpaceLogFilter(
13864 OSKextLogSpec newUserLogFilter,
13865 bool captureFlag)
13866 {
13867 OSKextLogSpec result;
13868 bool allocError = false;
13869
13870 /* Do not call any function that takes sKextLoggingLock during
13871 * this critical block. That means do logging after.
13872 */
13873 IOLockLock(sKextLoggingLock);
13874
13875 result = sUserSpaceKextLogFilter;
13876 sUserSpaceKextLogFilter = newUserLogFilter;
13877
13878 if (newUserLogFilter && captureFlag &&
13879 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13880 // xxx - do some measurements for a good initial capacity?
13881 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13882 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13883
13884 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
13885 allocError = true;
13886 }
13887 }
13888
13889 IOLockUnlock(sKextLoggingLock);
13890
13891 /* If the config flag itself is changing, log the state change
13892 * going both ways, before setting up the user-space log arrays,
13893 * so that this is only logged in the kernel.
13894 */
13895 if (result != newUserLogFilter) {
13896 OSKextLog(/* kext */ NULL,
13897 kOSKextLogDebugLevel |
13898 kOSKextLogGeneralFlag,
13899 "User-space log flags changed from 0x%x to 0x%x.",
13900 result, newUserLogFilter);
13901 }
13902 if (allocError) {
13903 OSKextLog(/* kext */ NULL,
13904 kOSKextLogErrorLevel |
13905 kOSKextLogGeneralFlag,
13906 "Failed to allocate user-space log message arrays.");
13907 }
13908
13909 return result;
13910 }
13911
13912 /*********************************************************************
13913 * Do not call any function that takes sKextLock here!
13914 *********************************************************************/
13915 /* static */
13916 OSSharedPtr<OSArray>
13917 OSKext::clearUserSpaceLogFilter(void)
13918 {
13919 OSSharedPtr<OSArray> result;
13920 OSKextLogSpec oldLogFilter;
13921 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
13922
13923 /* Do not call any function that takes sKextLoggingLock during
13924 * this critical block. That means do logging after.
13925 */
13926 IOLockLock(sKextLoggingLock);
13927
13928 result = OSArray::withCapacity(2);
13929 if (result) {
13930 result->setObject(sUserSpaceLogSpecArray.get());
13931 result->setObject(sUserSpaceLogMessageArray.get());
13932 }
13933 sUserSpaceLogSpecArray.reset();
13934 sUserSpaceLogMessageArray.reset();
13935
13936 oldLogFilter = sUserSpaceKextLogFilter;
13937 sUserSpaceKextLogFilter = newLogFilter;
13938
13939 IOLockUnlock(sKextLoggingLock);
13940
13941 /* If the config flag itself is changing, log the state change
13942 * going both ways, after tearing down the user-space log
13943 * arrays, so this is only logged within the kernel.
13944 */
13945 if (oldLogFilter != newLogFilter) {
13946 OSKextLog(/* kext */ NULL,
13947 kOSKextLogDebugLevel |
13948 kOSKextLogGeneralFlag,
13949 "User-space log flags changed from 0x%x to 0x%x.",
13950 oldLogFilter, newLogFilter);
13951 }
13952
13953 return result;
13954 }
13955
13956
13957 /*********************************************************************
13958 * Do not call any function that takes sKextLock here!
13959 *********************************************************************/
13960 /* static */
13961 OSKextLogSpec
13962 OSKext::getUserSpaceLogFilter(void)
13963 {
13964 OSKextLogSpec result;
13965
13966 IOLockLock(sKextLoggingLock);
13967 result = sUserSpaceKextLogFilter;
13968 IOLockUnlock(sKextLoggingLock);
13969
13970 return result;
13971 }
13972
13973 /*********************************************************************
13974 * This function is called by OSMetaClass during kernel C++ setup.
13975 * Be careful what you access here; assume only OSKext::initialize()
13976 * has been called.
13977 *
13978 * Do not call any function that takes sKextLock here!
13979 *********************************************************************/
13980 #define VTRESET "\033[0m"
13981
13982 #define VTBOLD "\033[1m"
13983 #define VTUNDER "\033[4m"
13984
13985 #define VTRED "\033[31m"
13986 #define VTGREEN "\033[32m"
13987 #define VTYELLOW "\033[33m"
13988 #define VTBLUE "\033[34m"
13989 #define VTMAGENTA "\033[35m"
13990 #define VTCYAN "\033[36m"
13991
13992 inline const char *
13993 colorForFlags(OSKextLogSpec flags)
13994 {
13995 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13996
13997 switch (logLevel) {
13998 case kOSKextLogErrorLevel:
13999 return VTRED VTBOLD;
14000 case kOSKextLogWarningLevel:
14001 return VTRED;
14002 case kOSKextLogBasicLevel:
14003 return VTYELLOW VTUNDER;
14004 case kOSKextLogProgressLevel:
14005 return VTYELLOW;
14006 case kOSKextLogStepLevel:
14007 return VTGREEN;
14008 case kOSKextLogDetailLevel:
14009 return VTCYAN;
14010 case kOSKextLogDebugLevel:
14011 return VTMAGENTA;
14012 default:
14013 return ""; // white
14014 }
14015 }
14016
14017 inline bool
14018 logSpecMatch(
14019 OSKextLogSpec msgLogSpec,
14020 OSKextLogSpec logFilter)
14021 {
14022 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
14023 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
14024 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
14025
14026 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
14027 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
14028 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
14029
14030 /* Explicit messages always get logged.
14031 */
14032 if (msgLevel == kOSKextLogExplicitLevel) {
14033 return true;
14034 }
14035
14036 /* Warnings and errors are logged regardless of the flags.
14037 */
14038 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
14039 return true;
14040 }
14041
14042 /* A verbose message that isn't for a logging-enabled kext and isn't global
14043 * does *not* get logged.
14044 */
14045 if (!msgKextGlobal && !filterKextGlobal) {
14046 return false;
14047 }
14048
14049 /* Warnings and errors are logged regardless of the flags.
14050 * All other messages must fit the flags and
14051 * have a level at or below the filter.
14052 *
14053 */
14054 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
14055 return true;
14056 }
14057 return false;
14058 }
14059
14060 extern "C" {
14061 void
14062 OSKextLog(
14063 OSKext * aKext,
14064 OSKextLogSpec msgLogSpec,
14065 const char * format, ...)
14066 {
14067 va_list argList;
14068
14069 va_start(argList, format);
14070 OSKextVLog(aKext, msgLogSpec, format, argList);
14071 va_end(argList);
14072 }
14073
14074 void
14075 OSKextVLog(
14076 OSKext * aKext,
14077 OSKextLogSpec msgLogSpec,
14078 const char * format,
14079 va_list srcArgList)
14080 {
14081 extern int disableConsoleOutput;
14082
14083 bool logForKernel = false;
14084 bool logForUser = false;
14085 va_list argList;
14086 char stackBuffer[120];
14087 uint32_t length = 0;
14088 char * allocBuffer = NULL; // must kfree
14089 OSSharedPtr<OSNumber> logSpecNum;
14090 OSSharedPtr<OSString> logString;
14091 char * buffer = stackBuffer; // do not free
14092
14093 IOLockLock(sKextLoggingLock);
14094
14095 /* Set the kext/global bit in the message spec if we have no
14096 * kext or if the kext requests logging.
14097 */
14098 if (!aKext || aKext->flags.loggingEnabled) {
14099 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
14100 }
14101
14102 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
14103 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14104 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
14105 }
14106
14107 if (!(logForKernel || logForUser)) {
14108 goto finish;
14109 }
14110
14111 /* No goto from here until past va_end()!
14112 */
14113 va_copy(argList, srcArgList);
14114 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
14115 va_end(argList);
14116
14117 if (length + 1 >= sizeof(stackBuffer)) {
14118 allocBuffer = (char *)kalloc_data_tag(length + 1,
14119 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14120 if (!allocBuffer) {
14121 goto finish;
14122 }
14123
14124 /* No goto from here until past va_end()!
14125 */
14126 va_copy(argList, srcArgList);
14127 vsnprintf(allocBuffer, length + 1, format, argList);
14128 va_end(argList);
14129
14130 buffer = allocBuffer;
14131 }
14132
14133 /* If user space wants the log message, queue it up.
14134 */
14135 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14136 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
14137 logString = OSString::withCString(buffer);
14138 if (logSpecNum && logString) {
14139 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
14140 sUserSpaceLogMessageArray->setObject(logString.get());
14141 }
14142 }
14143
14144 /* Always log messages from the kernel according to the kernel's
14145 * log flags.
14146 */
14147 if (logForKernel) {
14148 /* If we are in console mode and have a custom log filter,
14149 * colorize the log message.
14150 */
14151 if (!disableConsoleOutput && sBootArgLogFilterFound) {
14152 const char * color = ""; // do not free
14153 color = colorForFlags(msgLogSpec);
14154 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14155 buffer, color[0] ? VTRESET : "");
14156 } else {
14157 printf("%s\n", buffer);
14158 }
14159 }
14160
14161 finish:
14162 IOLockUnlock(sKextLoggingLock);
14163
14164 if (allocBuffer) {
14165 kfree_data(allocBuffer, length + 1);
14166 }
14167 return;
14168 }
14169
14170 #if KASLR_IOREG_DEBUG
14171
14172 #define IOLOG_INDENT( the_indention ) \
14173 { \
14174 int i; \
14175 for ( i = 0; i < (the_indention); i++ ) { \
14176 IOLog(" "); \
14177 } \
14178 }
14179
14180 extern vm_offset_t vm_kernel_stext;
14181 extern vm_offset_t vm_kernel_etext;
14182 extern mach_vm_offset_t kext_alloc_base;
14183 extern mach_vm_offset_t kext_alloc_max;
14184
14185 bool ScanForAddrInObject(OSObject * theObject,
14186 int indent );
14187
14188 bool
14189 ScanForAddrInObject(OSObject * theObject,
14190 int indent)
14191 {
14192 const OSMetaClass * myTypeID;
14193 OSSharedPtr<OSCollectionIterator> myIter;
14194 OSSymbol * myKey;
14195 OSObject * myValue;
14196 bool myResult = false;
14197
14198 if (theObject == NULL) {
14199 IOLog("%s: theObject is NULL \n",
14200 __FUNCTION__);
14201 return myResult;
14202 }
14203
14204 myTypeID = OSTypeIDInst(theObject);
14205
14206 if (myTypeID == OSTypeID(OSDictionary)) {
14207 OSDictionary * myDictionary;
14208
14209 myDictionary = OSDynamicCast(OSDictionary, theObject);
14210 myIter = OSCollectionIterator::withCollection( myDictionary );
14211 if (myIter == NULL) {
14212 return myResult;
14213 }
14214
14215 // !! reset the iterator
14216 myIter->reset();
14217
14218 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14219 bool myTempResult;
14220
14221 myValue = myDictionary->getObject(myKey);
14222 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14223 if (myTempResult) {
14224 // if we ever get a true result return true
14225 myResult = true;
14226 IOLOG_INDENT(indent);
14227 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14228 }
14229 }
14230
14231 // !! release the iterator
14232 myIter.reset();
14233 } else if (myTypeID == OSTypeID(OSArray)) {
14234 OSArray * myArray;
14235
14236 myArray = OSDynamicCast(OSArray, theObject);
14237 myIter = OSCollectionIterator::withCollection(myArray);
14238 if (myIter == NULL) {
14239 return myResult;
14240 }
14241 // !! reset the iterator
14242 myIter->reset();
14243
14244 while ((myValue = myIter->getNextObject())) {
14245 bool myTempResult;
14246 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14247 if (myTempResult) {
14248 // if we ever get a true result return true
14249 myResult = true;
14250 IOLOG_INDENT(indent);
14251 IOLog("OSArray: \n");
14252 }
14253 }
14254 // !! release the iterator
14255 myIter.reset();
14256 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14257 // should we look for addresses in strings?
14258 } else if (myTypeID == OSTypeID(OSData)) {
14259 void * * myPtrPtr;
14260 unsigned int myLen;
14261 OSData * myDataObj;
14262
14263 myDataObj = OSDynamicCast(OSData, theObject);
14264 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14265 myLen = myDataObj->getLength();
14266
14267 if (myPtrPtr && myLen && myLen > 7) {
14268 int i;
14269 int myPtrCount = (myLen / sizeof(void *));
14270
14271 for (i = 0; i < myPtrCount; i++) {
14272 UInt64 numberValue = (UInt64) * (myPtrPtr);
14273
14274 if (kext_alloc_max != 0 &&
14275 numberValue >= kext_alloc_base &&
14276 numberValue < kext_alloc_max) {
14277 OSSharedPtr<OSKext> myKext;
14278 // IOLog("found OSData %p in kext map %p to %p \n",
14279 // *(myPtrPtr),
14280 // (void *) kext_alloc_base,
14281 // (void *) kext_alloc_max);
14282
14283 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14284 if (myKext) {
14285 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14286 *(myPtrPtr),
14287 myKext->getIdentifierCString());
14288 }
14289 myResult = true;
14290 }
14291 if (vm_kernel_etext != 0 &&
14292 numberValue >= vm_kernel_stext &&
14293 numberValue < vm_kernel_etext) {
14294 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14295 *(myPtrPtr),
14296 (void *) vm_kernel_stext,
14297 (void *) vm_kernel_etext);
14298 myResult = true;
14299 }
14300 myPtrPtr++;
14301 }
14302 }
14303 } else if (myTypeID == OSTypeID(OSBoolean)) {
14304 // do nothing here...
14305 } else if (myTypeID == OSTypeID(OSNumber)) {
14306 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14307
14308 UInt64 numberValue = number->unsigned64BitValue();
14309
14310 if (kext_alloc_max != 0 &&
14311 numberValue >= kext_alloc_base &&
14312 numberValue < kext_alloc_max) {
14313 OSSharedPtr<OSKext> myKext;
14314 IOLog("found OSNumber in kext map %p to %p \n",
14315 (void *) kext_alloc_base,
14316 (void *) kext_alloc_max);
14317 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14318
14319 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14320 if (myKext) {
14321 IOLog("found in kext \"%s\" \n",
14322 myKext->getIdentifierCString());
14323 }
14324
14325 myResult = true;
14326 }
14327 if (vm_kernel_etext != 0 &&
14328 numberValue >= vm_kernel_stext &&
14329 numberValue < vm_kernel_etext) {
14330 IOLog("found OSNumber in kernel text segment %p to %p \n",
14331 (void *) vm_kernel_stext,
14332 (void *) vm_kernel_etext);
14333 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14334 myResult = true;
14335 }
14336 }
14337 #if 0
14338 else {
14339 const OSMetaClass* myMetaClass = NULL;
14340
14341 myMetaClass = theObject->getMetaClass();
14342 if (myMetaClass) {
14343 IOLog("class %s \n", myMetaClass->getClassName());
14344 } else {
14345 IOLog("Unknown object \n" );
14346 }
14347 }
14348 #endif
14349
14350 return myResult;
14351 }
14352 #endif // KASLR_KEXT_DEBUG
14353 }; /* extern "C" */
14354
14355 #if PRAGMA_MARK
14356 #pragma mark Backtrace Dump & kmod_get_info() support
14357 #endif
14358 /*********************************************************************
14359 * This function must be safe to call in panic context.
14360 *********************************************************************/
14361 /* static */
14362 void
14363 OSKext::printKextsInBacktrace(
14364 vm_offset_t * addr __unused,
14365 unsigned int cnt __unused,
14366 int (* printf_func)(const char *fmt, ...) __unused,
14367 uint32_t flags __unused)
14368 {
14369 addr64_t summary_page = 0;
14370 addr64_t last_summary_page = 0;
14371 bool found_kmod = false;
14372 u_int i = 0;
14373
14374 if (kPrintKextsLock & flags) {
14375 if (!sKextSummariesLock) {
14376 return;
14377 }
14378 IOLockLock(sKextSummariesLock);
14379 }
14380
14381 if (!gLoadedKextSummaries) {
14382 (*printf_func)(" can't perform kext scan: no kext summary");
14383 goto finish;
14384 }
14385
14386 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14387 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14388 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14389 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14390 (*printf_func)(" can't perform kext scan: "
14391 "missing kext summary page %p", summary_page);
14392 goto finish;
14393 }
14394 }
14395
14396 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14397 OSKextLoadedKextSummary * summary;
14398
14399 summary = gLoadedKextSummaries->summaries + i;
14400 if (!summary->address) {
14401 continue;
14402 }
14403
14404 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14405 continue;
14406 }
14407
14408 if (!found_kmod) {
14409 if (!(kPrintKextsTerse & flags)) {
14410 (*printf_func)(" Kernel Extensions in backtrace:\n");
14411 }
14412 found_kmod = true;
14413 }
14414
14415 printSummary(summary, printf_func, flags);
14416 }
14417
14418 finish:
14419 if (kPrintKextsLock & flags) {
14420 IOLockUnlock(sKextSummariesLock);
14421 }
14422
14423 return;
14424 }
14425
14426 /*********************************************************************
14427 * This function must be safe to call in panic context.
14428 *********************************************************************/
14429 /* static */
14430 boolean_t
14431 OSKext::summaryIsInBacktrace(
14432 OSKextLoadedKextSummary * summary,
14433 vm_offset_t * addr,
14434 unsigned int cnt)
14435 {
14436 u_int i = 0;
14437
14438 for (i = 0; i < cnt; i++) {
14439 vm_offset_t kscan_addr = addr[i];
14440 #if __has_feature(ptrauth_calls)
14441 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14442 #endif /* __has_feature(ptrauth_calls) */
14443 if ((kscan_addr >= summary->text_exec_address) &&
14444 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
14445 return TRUE;
14446 }
14447 }
14448
14449 return FALSE;
14450 }
14451
14452 /*
14453 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14454 * sKextSummariesLock held.
14455 */
14456 OSKextLoadedKextSummary *
14457 OSKext::summaryForAddress(uintptr_t addr)
14458 {
14459 #if __has_feature(ptrauth_calls)
14460 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14461 #endif /* __has_feature(ptrauth_calls) */
14462 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14463 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14464 if (!summary->address) {
14465 continue;
14466 }
14467
14468 #if VM_MAPPED_KEXTS
14469 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14470 * support split kexts, but we also may unmap the kexts, which can
14471 * race with the above codepath (see OSKext::unload). As such,
14472 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14473 */
14474 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14475 return summary;
14476 }
14477 #else
14478 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14479 kernel_segment_command_t *seg;
14480
14481 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14482 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14483 return summary;
14484 }
14485 }
14486 #endif
14487 }
14488
14489 /* addr did not map to any kext */
14490 return NULL;
14491 }
14492
14493 /* static */
14494 void *
14495 OSKext::kextForAddress(const void *address)
14496 {
14497 void * image = NULL;
14498 OSKextActiveAccount * active;
14499 OSKext * kext = NULL;
14500 uint32_t baseIdx;
14501 uint32_t lim;
14502 uintptr_t addr = (uintptr_t) address;
14503 size_t i;
14504
14505 if (!addr) {
14506 return NULL;
14507 }
14508 #if __has_feature(ptrauth_calls)
14509 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14510 #endif /* __has_feature(ptrauth_calls) */
14511
14512 if (sKextAccountsCount) {
14513 IOSimpleLockLock(sKextAccountsLock);
14514 // bsearch sKextAccounts list
14515 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14516 active = &sKextAccounts[baseIdx + (lim >> 1)];
14517 if ((addr >= active->address) && (addr < active->address_end)) {
14518 kext = active->account->kext;
14519 if (kext && kext->kmod_info) {
14520 image = (void *) kext->kmod_info->address;
14521 }
14522 break;
14523 } else if (addr > active->address) {
14524 // move right
14525 baseIdx += (lim >> 1) + 1;
14526 lim--;
14527 }
14528 // else move left
14529 }
14530 IOSimpleLockUnlock(sKextAccountsLock);
14531 }
14532 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14533 image = (void *) &_mh_execute_header;
14534 }
14535 if (!image && gLoadedKextSummaries) {
14536 IOLockLock(sKextSummariesLock);
14537 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14538 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14539 if (addr >= summary->address && addr < summary->address + summary->size) {
14540 image = (void *)summary->address;
14541 }
14542 }
14543 IOLockUnlock(sKextSummariesLock);
14544 }
14545
14546 return image;
14547 }
14548
14549 /*
14550 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14551 * Safe to call in panic context.
14552 */
14553 static OSKextLoadedKextSummary *
14554 findSummary(uint32_t tagID)
14555 {
14556 OSKextLoadedKextSummary * summary;
14557 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14558 summary = gLoadedKextSummaries->summaries + i;
14559 if (summary->loadTag == tagID) {
14560 return summary;
14561 }
14562 }
14563 return NULL;
14564 }
14565
14566 /*********************************************************************
14567 * This function must be safe to call in panic context.
14568 *********************************************************************/
14569 void
14570 OSKext::printSummary(
14571 OSKextLoadedKextSummary * summary,
14572 int (* printf_func)(const char *fmt, ...),
14573 uint32_t flags)
14574 {
14575 kmod_reference_t * kmod_ref = NULL;
14576 uuid_string_t uuid;
14577 char version[kOSKextVersionMaxLength];
14578 uint64_t tmpAddr;
14579 uint64_t tmpSize;
14580 OSKextLoadedKextSummary *dependencySummary;
14581
14582 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14583 strlcpy(version, "unknown version", sizeof(version));
14584 }
14585 (void) uuid_unparse(summary->uuid, uuid);
14586
14587 #if defined(__arm__) || defined(__arm64__)
14588 tmpAddr = summary->text_exec_address;
14589 tmpSize = summary->text_exec_size;
14590 #else
14591 tmpAddr = summary->address;
14592 tmpSize = summary->size;
14593 #endif
14594 if (kPrintKextsUnslide & flags) {
14595 tmpAddr = ml_static_unslide(tmpAddr);
14596 }
14597 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14598 (kPrintKextsTerse & flags) ? "" : " ",
14599 summary->name, version, uuid,
14600 tmpAddr, tmpAddr + tmpSize - 1);
14601
14602 if (kPrintKextsTerse & flags) {
14603 return;
14604 }
14605
14606 /* print dependency info */
14607 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14608 kmod_ref;
14609 kmod_ref = kmod_ref->next) {
14610 kmod_info_t * rinfo;
14611
14612 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14613 (*printf_func)(" kmod dependency scan stopped "
14614 "due to missing dependency page: %p\n",
14615 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14616 break;
14617 }
14618 rinfo = kmod_ref->info;
14619
14620 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14621 (*printf_func)(" kmod dependency scan stopped "
14622 "due to missing kmod page: %p\n",
14623 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14624 break;
14625 }
14626
14627 if (!rinfo->address) {
14628 continue; // skip fake entries for built-ins
14629 }
14630
14631 dependencySummary = findSummary(rinfo->id);
14632 uuid[0] = 0x00;
14633 tmpAddr = rinfo->address;
14634 tmpSize = rinfo->size;
14635 if (dependencySummary) {
14636 (void) uuid_unparse(dependencySummary->uuid, uuid);
14637 #if defined(__arm__) || defined(__arm64__)
14638 tmpAddr = dependencySummary->text_exec_address;
14639 tmpSize = dependencySummary->text_exec_size;
14640 #endif
14641 }
14642
14643 if (kPrintKextsUnslide & flags) {
14644 tmpAddr = ml_static_unslide(tmpAddr);
14645 }
14646 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14647 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
14648 }
14649 return;
14650 }
14651
14652
14653 #if !defined(__arm__) && !defined(__arm64__)
14654 /*******************************************************************************
14655 * substitute() looks at an input string (a pointer within a larger buffer)
14656 * for a match to a substring, and on match it writes the marker & substitution
14657 * character to an output string, updating the scan (from) and
14658 * output (to) indexes as appropriate.
14659 *******************************************************************************/
14660 static int substitute(
14661 const char * scan_string,
14662 char * string_out,
14663 uint32_t * to_index,
14664 uint32_t * from_index,
14665 const char * substring,
14666 char marker,
14667 char substitution);
14668
14669 /* string_out must be at least KMOD_MAX_NAME bytes.
14670 */
14671 static int
14672 substitute(
14673 const char * scan_string,
14674 char * string_out,
14675 uint32_t * to_index,
14676 uint32_t * from_index,
14677 const char * substring,
14678 char marker,
14679 char substitution)
14680 {
14681 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
14682
14683 /* On a substring match, append the marker (if there is one) and then
14684 * the substitution character, updating the output (to) index accordingly.
14685 * Then update the input (from) length by the length of the substring
14686 * that got replaced.
14687 */
14688 if (!strncmp(scan_string, substring, substring_length)) {
14689 if (marker) {
14690 string_out[(*to_index)++] = marker;
14691 }
14692 string_out[(*to_index)++] = substitution;
14693 (*from_index) += substring_length;
14694 return 1;
14695 }
14696 return 0;
14697 }
14698
14699 /*******************************************************************************
14700 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14701 * KMOD_MAX_NAME characters and performs various substitutions of common
14702 * prefixes & substrings as defined by tables in kext_panic_report.h.
14703 *******************************************************************************/
14704 static void compactIdentifier(
14705 const char * identifier,
14706 char * identifier_out,
14707 char ** identifier_out_end);
14708
14709 static void
14710 compactIdentifier(
14711 const char * identifier,
14712 char * identifier_out,
14713 char ** identifier_out_end)
14714 {
14715 uint32_t from_index, to_index;
14716 uint32_t scan_from_index = 0;
14717 uint32_t scan_to_index = 0;
14718 subs_entry_t * subs_entry = NULL;
14719 int did_sub = 0;
14720
14721 from_index = to_index = 0;
14722 identifier_out[0] = '\0';
14723
14724 /* Replace certain identifier prefixes with shorter @+character sequences.
14725 * Check the return value of substitute() so we only replace the prefix.
14726 */
14727 for (subs_entry = &kext_identifier_prefix_subs[0];
14728 subs_entry->substring && !did_sub;
14729 subs_entry++) {
14730 did_sub = substitute(identifier, identifier_out,
14731 &scan_to_index, &scan_from_index,
14732 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14733 }
14734 did_sub = 0;
14735
14736 /* Now scan through the identifier looking for the common substrings
14737 * and replacing them with shorter !+character sequences via substitute().
14738 */
14739 for (/* see above */;
14740 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14741 /* see loop */) {
14742 const char * scan_string = &identifier[scan_from_index];
14743
14744 did_sub = 0;
14745
14746 if (scan_from_index) {
14747 for (subs_entry = &kext_identifier_substring_subs[0];
14748 subs_entry->substring && !did_sub;
14749 subs_entry++) {
14750 did_sub = substitute(scan_string, identifier_out,
14751 &scan_to_index, &scan_from_index,
14752 subs_entry->substring, '!', subs_entry->substitute);
14753 }
14754 }
14755
14756 /* If we didn't substitute, copy the input character to the output.
14757 */
14758 if (!did_sub) {
14759 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14760 }
14761 }
14762
14763 identifier_out[scan_to_index] = '\0';
14764 if (identifier_out_end) {
14765 *identifier_out_end = &identifier_out[scan_to_index];
14766 }
14767
14768 return;
14769 }
14770 #endif /* !defined(__arm__) && !defined(__arm64__) */
14771
14772 /*******************************************************************************
14773 * assemble_identifier_and_version() adds to a string buffer a compacted
14774 * bundle identifier followed by a version string.
14775 *******************************************************************************/
14776
14777 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14778 */
14779 static size_t assemble_identifier_and_version(
14780 kmod_info_t * kmod_info,
14781 char * identPlusVers,
14782 size_t bufSize);
14783
14784 static size_t
14785 assemble_identifier_and_version(
14786 kmod_info_t * kmod_info,
14787 char * identPlusVers,
14788 size_t bufSize)
14789 {
14790 size_t result = 0;
14791
14792 #if defined(__arm__) || defined(__arm64__)
14793 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14794 #else
14795 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14796 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
14797 #endif
14798 identPlusVers[result++] = '\t'; // increment for real char
14799 identPlusVers[result] = '\0'; // don't increment for nul char
14800 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14801 if (result >= bufSize) {
14802 identPlusVers[bufSize - 1] = '\0';
14803 result = bufSize - 1;
14804 }
14805
14806 return result;
14807 }
14808
14809 /*******************************************************************************
14810 * Assumes sKextLock is held.
14811 *******************************************************************************/
14812 /* static */
14813 int
14814 OSKext::saveLoadedKextPanicListTyped(
14815 const char * prefix,
14816 int invertFlag,
14817 int libsFlag,
14818 char * paniclist,
14819 uint32_t list_size)
14820 {
14821 int result = -1;
14822 unsigned int count, i;
14823
14824 count = sLoadedKexts->getCount();
14825 if (!count) {
14826 goto finish;
14827 }
14828
14829 i = count - 1;
14830 do {
14831 OSObject * rawKext = sLoadedKexts->getObject(i);
14832 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14833 int match;
14834 size_t identPlusVersLength;
14835 size_t tempLen;
14836 char identPlusVers[2 * KMOD_MAX_NAME];
14837
14838 if (!rawKext) {
14839 printf("OSKext::saveLoadedKextPanicListTyped - "
14840 "NULL kext in loaded kext list; continuing\n");
14841 continue;
14842 }
14843
14844 if (!theKext) {
14845 printf("OSKext::saveLoadedKextPanicListTyped - "
14846 "Kext type cast failed in loaded kext list; continuing\n");
14847 continue;
14848 }
14849
14850 /* Skip all built-in kexts.
14851 */
14852 if (theKext->isKernelComponent()) {
14853 continue;
14854 }
14855
14856 kmod_info_t * kmod_info = theKext->kmod_info;
14857
14858 /* Filter for kmod name (bundle identifier).
14859 */
14860 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14861 if ((match && invertFlag) || (!match && !invertFlag)) {
14862 continue;
14863 }
14864
14865 /* Filter for libraries (kexts that have a compatible version).
14866 */
14867 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14868 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14869 continue;
14870 }
14871
14872 if (!kmod_info ||
14873 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14874 printf("kext scan stopped due to missing kmod_info page: %p\n",
14875 kmod_info);
14876 goto finish;
14877 }
14878
14879 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14880 identPlusVers,
14881 sizeof(identPlusVers));
14882 if (!identPlusVersLength) {
14883 printf("error saving loaded kext info\n");
14884 goto finish;
14885 }
14886
14887 /* make sure everything fits and we null terminate.
14888 */
14889 tempLen = strlcat(paniclist, identPlusVers, list_size);
14890 if (tempLen >= list_size) {
14891 // panic list is full, keep it and null terminate
14892 paniclist[list_size - 1] = 0x00;
14893 result = 0;
14894 goto finish;
14895 }
14896 tempLen = strlcat(paniclist, "\n", list_size);
14897 if (tempLen >= list_size) {
14898 // panic list is full, keep it and null terminate
14899 paniclist[list_size - 1] = 0x00;
14900 result = 0;
14901 goto finish;
14902 }
14903 } while (i--);
14904
14905 result = 0;
14906 finish:
14907
14908 return result;
14909 }
14910
14911 /*********************************************************************
14912 *********************************************************************/
14913 /* static */
14914 void
14915 OSKext::saveLoadedKextPanicList(void)
14916 {
14917 char * newlist = NULL;
14918 uint32_t newlist_size = 0;
14919
14920 newlist_size = KEXT_PANICLIST_SIZE;
14921 newlist = (char *)kalloc_data_tag(newlist_size,
14922 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14923
14924 if (!newlist) {
14925 OSKextLog(/* kext */ NULL,
14926 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14927 "Couldn't allocate kext panic log buffer.");
14928 goto finish;
14929 }
14930
14931 newlist[0] = '\0';
14932
14933 // non-"com.apple." kexts
14934 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14935 /* libs? */ -1, newlist, newlist_size) != 0) {
14936 goto finish;
14937 }
14938 // "com.apple." nonlibrary kexts
14939 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14940 /* libs? */ 0, newlist, newlist_size) != 0) {
14941 goto finish;
14942 }
14943 // "com.apple." library kexts
14944 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14945 /* libs? */ 1, newlist, newlist_size) != 0) {
14946 goto finish;
14947 }
14948
14949 if (loaded_kext_paniclist) {
14950 kheap_free(KHEAP_DATA_BUFFERS, loaded_kext_paniclist,
14951 loaded_kext_paniclist_size);
14952 }
14953 loaded_kext_paniclist = newlist;
14954 newlist = NULL;
14955 loaded_kext_paniclist_size = newlist_size;
14956
14957 finish:
14958 if (newlist) {
14959 kfree_data(newlist, newlist_size);
14960 }
14961 return;
14962 }
14963
14964 /*********************************************************************
14965 * Assumes sKextLock is held.
14966 *********************************************************************/
14967 void
14968 OSKext::savePanicString(bool isLoading)
14969 {
14970 u_long len;
14971
14972 if (!kmod_info) {
14973 return; // do not goto finish here b/c of lock
14974 }
14975
14976 len = assemble_identifier_and_version( kmod_info,
14977 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14978 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14979 if (!len) {
14980 printf("error saving unloaded kext info\n");
14981 goto finish;
14982 }
14983
14984 if (isLoading) {
14985 last_loaded_strlen = len;
14986 last_loaded_address = (void *)kmod_info->address;
14987 last_loaded_size = kmod_info->size;
14988 clock_get_uptime(&last_loaded_timestamp);
14989 } else {
14990 last_unloaded_strlen = len;
14991 last_unloaded_address = (void *)kmod_info->address;
14992 last_unloaded_size = kmod_info->size;
14993 clock_get_uptime(&last_unloaded_timestamp);
14994 }
14995
14996 finish:
14997 return;
14998 }
14999
15000 /*********************************************************************
15001 *********************************************************************/
15002 /* static */
15003 void
15004 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
15005 {
15006 if (last_loaded_strlen) {
15007 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
15008 AbsoluteTime_to_scalar(&last_loaded_timestamp),
15009 last_loaded_strlen, last_loaded_str_buf,
15010 last_loaded_address, last_loaded_size);
15011 }
15012
15013 if (last_unloaded_strlen) {
15014 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
15015 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
15016 last_unloaded_strlen, last_unloaded_str_buf,
15017 last_unloaded_address, last_unloaded_size);
15018 }
15019
15020 printf_func("loaded kexts:\n");
15021 if (loaded_kext_paniclist &&
15022 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
15023 loaded_kext_paniclist[0]) {
15024 printf_func("%.*s",
15025 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
15026 loaded_kext_paniclist);
15027 } else {
15028 printf_func("(none)\n");
15029 }
15030 return;
15031 }
15032
15033 /*********************************************************************
15034 * Assumes sKextLock is held.
15035 *********************************************************************/
15036 /* static */
15037 void
15038 OSKext::updateLoadedKextSummaries(void)
15039 {
15040 kern_return_t result = KERN_FAILURE;
15041 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
15042 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
15043 OSKext *aKext;
15044 vm_map_offset_t start, end;
15045 size_t summarySize = 0;
15046 size_t size;
15047 u_int count;
15048 u_int maxKexts;
15049 u_int i, j;
15050 OSKextActiveAccount * accountingList;
15051 OSKextActiveAccount * prevAccountingList;
15052 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
15053
15054 prevAccountingList = NULL;
15055 prevAccountingListCount = 0;
15056
15057 #if DEVELOPMENT || DEBUG
15058 if (IORecursiveLockHaveLock(sKextLock) == false) {
15059 panic("sKextLock must be held");
15060 }
15061 #endif
15062
15063 IOLockLock(sKextSummariesLock);
15064
15065 count = sLoadedKexts->getCount();
15066 for (i = 0, maxKexts = 0; i < count; ++i) {
15067 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15068 maxKexts += (aKext && aKext->isExecutable());
15069 }
15070
15071 if (!maxKexts) {
15072 goto finish;
15073 }
15074 if (maxKexts < kOSKextTypicalLoadCount) {
15075 maxKexts = kOSKextTypicalLoadCount;
15076 }
15077
15078 /* Calculate the size needed for the new summary headers.
15079 */
15080
15081 size = sizeof(*gLoadedKextSummaries);
15082 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
15083 size = round_page(size);
15084
15085 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
15086 if (gLoadedKextSummaries) {
15087 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
15088 gLoadedKextSummaries = NULL;
15089 gLoadedKextSummariesTimestamp = mach_absolute_time();
15090 sLoadedKextSummariesAllocSize = 0;
15091 }
15092 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
15093 if (result != KERN_SUCCESS) {
15094 goto finish;
15095 }
15096 summaryHeader = summaryHeaderAlloc;
15097 summarySize = size;
15098 } else {
15099 summaryHeader = gLoadedKextSummaries;
15100 summarySize = sLoadedKextSummariesAllocSize;
15101
15102 start = (vm_map_offset_t) summaryHeader;
15103 end = start + summarySize;
15104 result = vm_map_protect(kernel_map,
15105 start,
15106 end,
15107 VM_PROT_DEFAULT,
15108 FALSE);
15109 if (result != KERN_SUCCESS) {
15110 goto finish;
15111 }
15112 }
15113
15114 /* Populate the summary header.
15115 */
15116
15117 bzero(summaryHeader, summarySize);
15118 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
15119 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
15120
15121 /* Populate each kext summary.
15122 */
15123
15124 count = sLoadedKexts->getCount();
15125 accountingListAlloc = 0;
15126 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15127 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15128 if (!aKext || !aKext->isExecutable()) {
15129 continue;
15130 }
15131
15132 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
15133 summaryHeader->numSummaries++;
15134 accountingListAlloc++;
15135 }
15136
15137 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
15138 accountingListCount = 0;
15139 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15140 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15141 if (!aKext || !aKext->isExecutable()) {
15142 continue;
15143 }
15144
15145 OSKextActiveAccount activeAccount;
15146 aKext->updateActiveAccount(&activeAccount);
15147 // order by address
15148 for (idx = 0; idx < accountingListCount; idx++) {
15149 if (activeAccount.address < accountingList[idx].address) {
15150 break;
15151 }
15152 }
15153 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
15154 accountingList[idx] = activeAccount;
15155 accountingListCount++;
15156 }
15157 assert(accountingListCount == accountingListAlloc);
15158 /* Write protect the buffer and move it into place.
15159 */
15160
15161 start = (vm_map_offset_t) summaryHeader;
15162 end = start + summarySize;
15163
15164 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15165 if (result != KERN_SUCCESS) {
15166 goto finish;
15167 }
15168
15169 gLoadedKextSummaries = summaryHeader;
15170 gLoadedKextSummariesTimestamp = mach_absolute_time();
15171 sLoadedKextSummariesAllocSize = summarySize;
15172 summaryHeaderAlloc = NULL;
15173
15174 /* Call the magic breakpoint function through a static function pointer so
15175 * the compiler can't optimize the function away.
15176 */
15177 if (sLoadedKextSummariesUpdated) {
15178 (*sLoadedKextSummariesUpdated)();
15179 }
15180
15181 IOSimpleLockLock(sKextAccountsLock);
15182 prevAccountingList = sKextAccounts;
15183 prevAccountingListCount = sKextAccountsCount;
15184 sKextAccounts = accountingList;
15185 sKextAccountsCount = accountingListCount;
15186 IOSimpleLockUnlock(sKextAccountsLock);
15187
15188 finish:
15189 IOLockUnlock(sKextSummariesLock);
15190
15191 /* If we had to allocate a new buffer but failed to generate the summaries,
15192 * free that now.
15193 */
15194 if (summaryHeaderAlloc) {
15195 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15196 }
15197 if (prevAccountingList) {
15198 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15199 }
15200
15201 return;
15202 }
15203
15204 /*********************************************************************
15205 *********************************************************************/
15206 void
15207 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15208 {
15209 OSSharedPtr<OSData> uuid;
15210
15211 strlcpy(summary->name, getIdentifierCString(),
15212 sizeof(summary->name));
15213
15214 uuid = copyUUID();
15215 if (uuid) {
15216 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
15217 }
15218
15219 if (flags.builtin) {
15220 // this value will stop lldb from parsing the mach-o header
15221 // summary->address = UINT64_MAX;
15222 // summary->size = 0;
15223 summary->address = kmod_info->address;
15224 summary->size = kmod_info->size;
15225 } else {
15226 summary->address = kmod_info->address;
15227 summary->size = kmod_info->size;
15228 }
15229 summary->version = getVersion();
15230 summary->loadTag = kmod_info->id;
15231 summary->flags = 0;
15232 summary->reference_list = (uint64_t) kmod_info->reference_list;
15233
15234 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15235 if (summary->text_exec_address == 0) {
15236 // Fallback to __TEXT
15237 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15238 }
15239 return;
15240 }
15241
15242 /*********************************************************************
15243 *********************************************************************/
15244
15245 void
15246 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
15247 {
15248 kernel_mach_header_t *hdr = NULL;
15249 kernel_segment_command_t *seg = NULL;
15250
15251 bzero(accountp, sizeof(*accountp));
15252
15253 hdr = (kernel_mach_header_t *)kmod_info->address;
15254 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15255 /*
15256 * If this kext supports split segments (or is in a new
15257 * MH_FILESET kext collection), use the first
15258 * executable segment as the range for instructions
15259 * (and thus for backtracing.
15260 */
15261 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15262 if (seg->initprot & VM_PROT_EXECUTE) {
15263 break;
15264 }
15265 }
15266 }
15267 if (seg) {
15268 accountp->address = seg->vmaddr;
15269 if (accountp->address) {
15270 accountp->address_end = seg->vmaddr + seg->vmsize;
15271 }
15272 } else {
15273 /* For non-split kexts and for kexts without executable
15274 * segments, just use the kmod_info range (as the kext
15275 * is either all in one range or should not show up in
15276 * instruction backtraces).
15277 */
15278 accountp->address = kmod_info->address;
15279 if (accountp->address) {
15280 accountp->address_end = kmod_info->address + kmod_info->size;
15281 }
15282 }
15283
15284 accountp->account = this->account;
15285 }
15286
15287 bool
15288 OSKext::isDriverKit(void)
15289 {
15290 OSString *bundleType;
15291
15292 if (infoDict) {
15293 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15294 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15295 return TRUE;
15296 }
15297 }
15298 return FALSE;
15299 }
15300
15301 bool
15302 OSKext::isInFileset(void)
15303 {
15304 if (!kmod_info) {
15305 goto check_prelinked;
15306 }
15307
15308 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15309 return true;
15310 }
15311
15312 check_prelinked:
15313 if (isPrelinked()) {
15314 /*
15315 * If we haven't setup kmod_info yet, but we know
15316 * we're loading a prelinked kext in an MH_FILESET KC,
15317 * then return true
15318 */
15319 kc_format_t kc_format;
15320 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15321 return true;
15322 }
15323 }
15324 return false;
15325 }
15326
15327 bool
15328 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15329 {
15330 kern_return_t result;
15331 if (!super::init()) {
15332 return false;
15333 }
15334 if (seg == nullptr) {
15335 return false;
15336 }
15337 result = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&data, seg->vmsize, VM_KERN_MEMORY_KEXT);
15338 if (result != KERN_SUCCESS) {
15339 return false;
15340 }
15341 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15342 savedSegment = seg;
15343 vmsize = seg->vmsize;
15344 vmaddr = seg->vmaddr;
15345 return true;
15346 }
15347
15348 OSSharedPtr<OSKextSavedMutableSegment>
15349 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15350 {
15351 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15352 if (me && !me->initWithSegment(seg)) {
15353 return nullptr;
15354 }
15355 return me;
15356 }
15357
15358 void
15359 OSKextSavedMutableSegment::free(void)
15360 {
15361 if (data) {
15362 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15363 }
15364 }
15365
15366 vm_offset_t
15367 OSKextSavedMutableSegment::getVMAddr() const
15368 {
15369 return vmaddr;
15370 }
15371
15372 vm_offset_t
15373 OSKextSavedMutableSegment::getVMSize() const
15374 {
15375 return vmsize;
15376 }
15377
15378 OSReturn
15379 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15380 {
15381 if (seg != savedSegment) {
15382 return kOSKextReturnInvalidArgument;
15383 }
15384 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15385 return kOSKextReturnInvalidArgument;
15386 }
15387 memcpy((void *)seg->vmaddr, data, vmsize);
15388 return kOSReturnSuccess;
15389 }
15390
15391 extern "C" kern_return_t
15392 OSKextSetReceiptQueried(void)
15393 {
15394 OSKextLog(/* kext */ NULL,
15395 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
15396 "Setting kext receipt as queried");
15397
15398 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
15399 return KERN_SUCCESS;
15400 }
15401
15402 extern "C" const vm_allocation_site_t *
15403 OSKextGetAllocationSiteForCaller(uintptr_t address)
15404 {
15405 OSKextActiveAccount * active;
15406 vm_allocation_site_t * site;
15407 vm_allocation_site_t * releasesite;
15408
15409 uint32_t baseIdx;
15410 uint32_t lim;
15411 #if __has_feature(ptrauth_calls)
15412 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15413 #endif /* __has_feature(ptrauth_calls) */
15414
15415 IOSimpleLockLock(sKextAccountsLock);
15416 site = releasesite = NULL;
15417
15418 // bsearch sKextAccounts list
15419 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15420 active = &sKextAccounts[baseIdx + (lim >> 1)];
15421 if ((address >= active->address) && (address < active->address_end)) {
15422 site = &active->account->site;
15423 if (!site->tag) {
15424 vm_tag_alloc_locked(site, &releasesite);
15425 }
15426 break;
15427 } else if (address > active->address) {
15428 // move right
15429 baseIdx += (lim >> 1) + 1;
15430 lim--;
15431 }
15432 // else move left
15433 }
15434 IOSimpleLockUnlock(sKextAccountsLock);
15435 if (releasesite) {
15436 kern_allocation_name_release(releasesite);
15437 }
15438
15439 return site;
15440 }
15441
15442 #if DEVELOPMENT || DEBUG
15443 extern "C" void
15444 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
15445 {
15446 OSKextActiveAccount * active;
15447
15448 uint32_t baseIdx;
15449 uint32_t lim;
15450 #if __has_feature(ptrauth_calls)
15451 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15452 #endif /* __has_feature(ptrauth_calls) */
15453
15454 IOSimpleLockLock(sKextAccountsLock);
15455
15456 // bsearch sKextAccounts list
15457 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15458 active = &sKextAccounts[baseIdx + (lim >> 1)];
15459 if ((address >= active->address) && (address < active->address_end)) {
15460 cb(&active->account->task_refgrp);
15461 break;
15462 } else if (address > active->address) {
15463 // move right
15464 baseIdx += (lim >> 1) + 1;
15465 lim--;
15466 }
15467 // else move left
15468 }
15469 IOSimpleLockUnlock(sKextAccountsLock);
15470 }
15471 #endif /* DEVELOPMENT || DEBUG */
15472
15473 extern "C" uint32_t
15474 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
15475 {
15476 OSKextAccount * account = (typeof(account))site;
15477 const char * kname;
15478
15479 if (name) {
15480 if (account->kext) {
15481 kname = account->kext->getIdentifierCString();
15482 } else {
15483 kname = "<>";
15484 }
15485 strlcpy(name, kname, namelen);
15486 }
15487
15488 return account->loadTag;
15489 }
15490
15491 extern "C" void
15492 OSKextFreeSite(vm_allocation_site_t * site)
15493 {
15494 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15495 IOFreeType(freeAccount, OSKextAccount);
15496 }
15497
15498 /*********************************************************************
15499 *********************************************************************/
15500
15501 #if CONFIG_IMAGEBOOT
15502 int
15503 OSKextGetUUIDForName(const char *name, uuid_t uuid)
15504 {
15505 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
15506 if (!kext) {
15507 return 1;
15508 }
15509
15510 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
15511 if (uuid_data) {
15512 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
15513 return 0;
15514 }
15515
15516 return 1;
15517 }
15518 #endif
15519
15520 static int
15521 sysctl_willuserspacereboot
15522 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15523 {
15524 int new_value = 0, old_value = 0, changed = 0;
15525 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15526 if (error) {
15527 return error;
15528 }
15529 if (changed) {
15530 OSKext::willUserspaceReboot();
15531 }
15532 return 0;
15533 }
15534
15535 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15536 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15537 NULL, 0, sysctl_willuserspacereboot, "I", "");
15538