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_xnu.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_xnu.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 CONFIG_SPTM
91 #include <arm64/sptm/sptm.h>
92 #endif
93
94 #if PRAGMA_MARK
95 #pragma mark External & Internal Function Protos
96 #endif
97 /*********************************************************************
98 *********************************************************************/
99 extern "C" {
100 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
101 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
102
103 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
104 extern int dtrace_keep_kernel_symbols(void);
105
106 #if defined(__x86_64__) || defined(__i386__)
107 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
108 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
109 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
110 static void *allocate_kcfileset_map_entry_list(void);
111 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
112 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
113 int vnode_put(struct vnode *vp);
114 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
115 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
116 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
117 void * ubc_getobject(struct vnode *vp, __unused int flags);
118 #endif //(__x86_64__) || defined(__i386__)
119 }
120
121 extern unsigned long gVirtBase;
122 extern unsigned long gPhysBase;
123
124 bool pageableKCloaded = false;
125 bool auxKCloaded = false;
126 bool resetAuxKCSegmentOnUnload = false;
127
128 extern boolean_t pageablekc_uuid_valid;
129 extern uuid_t pageablekc_uuid;
130 extern uuid_string_t pageablekc_uuid_string;
131
132 extern boolean_t auxkc_uuid_valid;
133 extern uuid_t auxkc_uuid;
134 extern uuid_string_t auxkc_uuid_string;
135
136 static OSReturn _OSKextCreateRequest(
137 const char * predicate,
138 OSSharedPtr<OSDictionary> & requestP);
139 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
140 static OSObject * _OSKextGetRequestArgument(
141 OSDictionary * requestDict,
142 const char * argName);
143 static bool _OSKextSetRequestArgument(
144 OSDictionary * requestDict,
145 const char * argName,
146 OSMetaClassBase * value);
147 template <typename T>
148 static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
149 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
150 static OSReturn _OSDictionarySetCStringValue(
151 OSDictionary * dict,
152 const char * key,
153 const char * value);
154 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
155 #if CONFIG_KXLD
156 static bool _OSKextInPrelinkRebuildWindow(void);
157 #endif
158
159 // We really should add containsObject() & containsCString to OSCollection & subclasses.
160 // So few pad slots, though....
161 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
162 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
163
164 static const char *getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size);
165
166 /* Prelinked arm kexts do not have VM entries because the method we use to
167 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
168 * not work on ARM. To get around that, we must free prelinked kext
169 * executables with ml_static_mfree() instead of kext_free().
170 */
171 #if __i386__ || __x86_64__
172 #define VM_MAPPED_KEXTS 1
173 #define KASLR_KEXT_DEBUG 0
174 #define KASLR_IOREG_DEBUG 0
175 #elif __arm__ || __arm64__
176 #define VM_MAPPED_KEXTS 0
177 #define KASLR_KEXT_DEBUG 0
178 #else
179 #error Unsupported architecture
180 #endif
181
182 #if PRAGMA_MARK
183 #pragma mark Constants & Macros
184 #endif
185 /*********************************************************************
186 * Constants & Macros
187 *********************************************************************/
188
189 /* Use this number to create containers.
190 */
191 #define kOSKextTypicalLoadCount (150)
192 #define kOSKextTypicalUpgradeCount (5)
193
194 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
195 * A loaded kext will no dependents or external retains will have 2 retains.
196 */
197 #define kOSKextMinRetainCount (1)
198 #define kOSKextMinLoadedRetainCount (2)
199
200 #define kOSKextMaxDextLaunchedCount (~((uint32_t)0))
201 #define KOSBundleDextUniqueIdentifierMaxStringLength (KOSBundleDextUniqueIdentifierMaxLength * 2 +1)
202
203 /**********
204 * Strings and substrings used in dependency resolution.
205 */
206 #define APPLE_KEXT_PREFIX "com.apple."
207 #define KERNEL_LIB "com.apple.kernel"
208
209 #define PRIVATE_KPI "com.apple.kpi.private"
210
211 /* Version for compatbility pseudokexts (com.apple.kernel.*),
212 * compatible back to v6.0.
213 */
214 #define KERNEL6_LIB "com.apple.kernel.6.0"
215 #define KERNEL6_VERSION "7.9.9"
216
217 #define KERNEL_LIB_PREFIX "com.apple.kernel."
218 #define KPI_LIB_PREFIX "com.apple.kpi."
219
220 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
221
222 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
223 #define MINIMUM_WAKEUP_SECONDS (30)
224
225 /*********************************************************************
226 * infoDict keys for internally-stored data. Saves on ivar slots for
227 * objects we don't keep around past boot time or during active load.
228 *********************************************************************/
229
230 /* A usable, uncompressed file is stored under this key.
231 */
232 #define _kOSKextExecutableKey "_OSKextExecutable"
233
234 /* An indirect reference to the executable file from an mkext
235 * is stored under this key.
236 */
237 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
238
239 /* If the file is contained in a larger buffer laid down by the booter or
240 * sent from user space, the OSKext stores that OSData under this key so that
241 * references are properly tracked. This is always an mkext, right now.
242 */
243 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
244
245 #define OS_LOG_HDR_VERSION 1
246 #define NUM_OS_LOG_SECTIONS 3
247
248 #define OS_LOG_SECT_IDX 0
249 #define CSTRING_SECT_IDX 1
250 #define ASAN_CSTRING_SECT_IDX 2
251
252 #if PRAGMA_MARK
253 #pragma mark Typedefs
254 #endif
255 /*********************************************************************
256 * Typedefs
257 *********************************************************************/
258
259 /*********************************************************************
260 * osLogDataHeaderRef describes the header information of an OSData
261 * object that is returned when querying for kOSBundleLogStringsKey.
262 * We currently return information regarding 2 sections - os_log and
263 * cstring. In the case that the os_log section doesn't exist, we just
264 * return an offset and length of 0 for that section.
265 *********************************************************************/
266 typedef struct osLogDataHeader {
267 uint32_t version;
268 uint32_t sect_count;
269 struct {
270 uint32_t sect_offset;
271 uint32_t sect_size;
272 } sections[0];
273 } osLogDataHeaderRef;
274
275 /*********************************************************************
276 * MkextEntryRef describes the contents of an OSData object
277 * referencing a file entry from an mkext so that we can uncompress
278 * (if necessary) and extract it on demand.
279 *
280 * It contains the mkextVersion in case we ever wind up supporting
281 * multiple mkext formats. Mkext format 1 is officially retired as of
282 * Snow Leopard.
283 *********************************************************************/
284 typedef struct MkextEntryRef {
285 mkext_basic_header * mkext; // beginning of whole mkext file
286 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
287 } MkextEntryRef;
288
289 #if PRAGMA_MARK
290 #pragma mark Global and static Module Variables
291 #endif
292 /*********************************************************************
293 * Global & static variables, used to keep track of kexts.
294 *********************************************************************/
295
296 static bool sPrelinkBoot = false;
297 static bool sSafeBoot = false;
298 static bool sKeepSymbols = false;
299 static bool sPanicOnKCMismatch = false;
300 static bool sOSKextWasResetAfterUserspaceReboot = false;
301
302 /*********************************************************************
303 * sKextLock is the principal lock for OSKext, and guards all static
304 * and global variables not owned by other locks (declared further
305 * below). It must be taken by any entry-point method or function,
306 * including internal functions called on scheduled threads.
307 *
308 * sKextLock and sKextInnerLock are recursive due to multiple functions
309 * that are called both externally and internally. The other locks are
310 * nonrecursive.
311 *
312 * Which locks are taken depends on what they protect, but if more than
313 * one must be taken, they must always be locked in this order
314 * (and unlocked in reverse order) to prevent deadlocks:
315 *
316 * 1. sKextLock
317 * 2. sKextInnerLock
318 * 3. sKextSummariesLock
319 * 4. sKextLoggingLock
320 */
321 static IORecursiveLock * sKextLock = NULL;
322
323 static OSSharedPtr<OSDictionary> sKextsByID;
324 static OSSharedPtr<OSDictionary> sExcludeListByID;
325 static OSKextVersion sExcludeListVersion = 0;
326 static OSSharedPtr<OSArray> sLoadedKexts;
327 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
328 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
329 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
330 static OSSharedPtr<OSDictionary> sDriverKitToUpgradeByID;
331
332 // Requests to the IOKit daemon waiting to be picked up.
333 static OSSharedPtr<OSArray> sKernelRequests;
334 // Identifier of kext load requests in sKernelRequests
335 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
336 static OSSharedPtr<OSArray> sRequestCallbackRecords;
337
338 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
339 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
340 #if CONFIG_KXLD
341 static KXLDContext * sKxldContext = NULL;
342 #endif
343 static uint32_t sNextLoadTag = 0;
344 static uint32_t sNextRequestTag = 0;
345
346 static bool sUserLoadsActive = false;
347 static bool sIOKitDaemonActive = false;
348 static bool sDeferredLoadSucceeded = false;
349 static bool sConsiderUnloadsExecuted = false;
350
351 #if NO_KEXTD
352 static bool sKernelRequestsEnabled = false;
353 #else
354 static bool sKernelRequestsEnabled = true;
355 #endif
356 static bool sLoadEnabled = true;
357 static bool sUnloadEnabled = true;
358
359 /*********************************************************************
360 * Stuff for the OSKext representing the kernel itself.
361 **********/
362 static OSKext * sKernelKext = NULL;
363
364 /* Load Tag IDs used by statically loaded binaries (e.g, the kernel itself). */
365 enum : uint32_t {
366 kOSKextKernelLoadTag = 0,
367 #if CONFIG_SPTM
368 kOSKextSPTMLoadTag = 1,
369 kOSKextTXMLoadTag = 2,
370 #endif /* CONFIG_SPTM */
371 kOSKextLoadTagCount
372 };
373
374 /* Set up a fake kmod_info struct for the kernel.
375 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
376 * before OSKext is initialized; that call only needs the name
377 * and address to be set correctly.
378 *
379 * We don't do much else with the kerne's kmod_info; we never
380 * put it into the kmod list, never adjust the reference count,
381 * and never have kernel components reference it.
382 * For that matter, we don't do much with kmod_info structs
383 * at all anymore! We just keep them filled in for gdb and
384 * binary compability.
385 */
386 kmod_info_t g_kernel_kmod_info = {
387 .next = NULL,
388 .info_version = KMOD_INFO_VERSION,
389 .id = kOSKextKernelLoadTag, // loadTag: kernel is always 0
390 .name = kOSKextKernelIdentifier,// bundle identifier
391 .version = "0", // filled in in OSKext::initialize()
392 .reference_count = -1, // never adjusted; kernel never unloads
393 .reference_list = NULL,
394 .address = 0,
395 .size = 0, // filled in in OSKext::initialize()
396 .hdr_size = 0,
397 .start = NULL,
398 .stop = NULL
399 };
400
401 #if CONFIG_SPTM
402 /* The SPTM and TXM need fake kmod structures just like the kernel. */
403 kmod_info_t g_sptm_kmod_info = {
404 .next = NULL,
405 .info_version = KMOD_INFO_VERSION,
406 .id = kOSKextSPTMLoadTag, // Always one after the kernel
407 .name = kOSKextSPTMIdentifier,// bundle identifier
408 .version = "0", // filled in by OSKext::initialize()
409 .reference_count = -1, // never adjusted; SPTM never unloads
410 .reference_list = NULL,
411 .address = 0,
412 .size = 0, // filled in by OSKext::initialize()
413 .hdr_size = 0,
414 .start = NULL,
415 .stop = NULL
416 };
417
418 kmod_info_t g_txm_kmod_info = {
419 .next = NULL,
420 .info_version = KMOD_INFO_VERSION,
421 .id = kOSKextTXMLoadTag, // Always one after the SPTM
422 .name = kOSKextTXMIdentifier,// bundle identifier
423 .version = "0", // filled in by OSKext::initialize()
424 .reference_count = -1, // never adjusted; TXM never unloads
425 .reference_list = NULL,
426 .address = 0,
427 .size = 0, // filled in by OSKext::initialize()
428 .hdr_size = 0,
429 .start = NULL,
430 .stop = NULL
431 };
432 #endif /* CONFIG_SPTM */
433
434 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
435
436 kmod_info_t invalid_kmod_info = {
437 .next = NULL,
438 .info_version = KMOD_INFO_VERSION,
439 .id = UINT32_MAX,
440 .name = "invalid",
441 .version = "0",
442 .reference_count = -1,
443 .reference_list = NULL,
444 .address = 0,
445 .size = 0,
446 .hdr_size = 0,
447 .start = NULL,
448 .stop = NULL
449 };
450
451 extern "C" {
452 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
453 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
454 // misc_protos.h, db_low_trace.c, kgmacros
455 // 'kmod' is a holdover from the old kmod system, we can't rename it.
456 kmod_info_t * kmod = NULL;
457
458 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
459
460
461 static char * loaded_kext_paniclist = NULL;
462 static uint32_t loaded_kext_paniclist_size = 0;
463
464 AbsoluteTime last_loaded_timestamp;
465 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
466 static u_long last_loaded_strlen = 0;
467 static void * last_loaded_address = NULL;
468 static u_long last_loaded_size = 0;
469
470 AbsoluteTime last_unloaded_timestamp;
471 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
472 static u_long last_unloaded_strlen = 0;
473 static void * last_unloaded_address = NULL;
474 static u_long last_unloaded_size = 0;
475
476 // Statically linked kmods described by several mach-o sections:
477 //
478 // kPrelinkInfoSegment:kBuiltinInfoSection
479 // Array of pointers to kmod_info_t structs.
480 //
481 // kPrelinkInfoSegment:kBuiltinInfoSection
482 // Array of pointers to an embedded mach-o header.
483 //
484 // __DATA:kBuiltinInitSection, kBuiltinTermSection
485 // Structors for all kmods. Has to be filtered by proc address.
486 //
487
488 static uint32_t gBuiltinKmodsCount;
489 static kernel_section_t * gBuiltinKmodsSectionInfo;
490 static kernel_section_t * gBuiltinKmodsSectionStart;
491
492 const OSSymbol * gIOSurfaceIdentifier;
493 vm_tag_t gIOSurfaceTag;
494
495 /*********************************************************************
496 * sKextInnerLock protects against cross-calls with IOService and
497 * IOCatalogue, and owns the variables declared immediately below.
498 *
499 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
500 *
501 * When both sKextLock and sKextInnerLock need to be taken,
502 * always lock sKextLock first and unlock it second. Never take both
503 * locks in an entry point to OSKext; if you need to do so, you must
504 * spawn an independent thread to avoid potential deadlocks for threads
505 * calling into OSKext.
506 **********/
507 static IORecursiveLock * sKextInnerLock = NULL;
508
509 #if XNU_TARGET_OS_OSX
510 static bool sAutounloadEnabled = true;
511 #endif
512 static bool sConsiderUnloadsCalled = false;
513 static bool sConsiderUnloadsPending = false;
514
515 static unsigned int sConsiderUnloadDelay = 60; // seconds
516 static thread_call_t sUnloadCallout = NULL;
517 #if CONFIG_KXLD
518 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
519 #endif // CONFIG_KXLD
520 static bool sSystemSleep = false; // true when system going to sleep
521 static AbsoluteTime sLastWakeTime; // last time we woke up
522
523 /*********************************************************************
524 * Backtraces can be printed at various times so we need a tight lock
525 * on data used for that. sKextSummariesLock protects the variables
526 * declared immediately below.
527 *
528 * gLoadedKextSummaries is accessed by other modules, but only during
529 * a panic so the lock isn't needed then.
530 *
531 * gLoadedKextSummaries has the "used" attribute in order to ensure
532 * that it remains visible even when we are performing extremely
533 * aggressive optimizations, as it is needed to allow the debugger
534 * to automatically parse the list of loaded kexts.
535 **********/
536 static IOLock * sKextSummariesLock = NULL;
537 extern "C" lck_grp_t vm_page_lck_grp_bucket;
538 static lck_grp_t * sKextAccountsLockGrp = &vm_page_lck_grp_bucket;
539 #define sKextAccountsLock (&vm_allocation_sites_lock)
540
541 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
542 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
543 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
544 static size_t sLoadedKextSummariesAllocSize = 0;
545
546 static OSKextActiveAccount * sKextAccounts;
547 static uint32_t sKextAccountsCount;
548 };
549
550 /*********************************************************************
551 * sKextLoggingLock protects the logging variables declared immediately below.
552 **********/
553 static IOLock * sKextLoggingLock = NULL;
554
555 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
556 kOSKextLogVerboseFlagsMask;
557 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
558 static bool sBootArgLogFilterFound = false;
559 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
560 0, "kernel kext logging");
561
562 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
563 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
564 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
565
566 /*********
567 * End scope for sKextInnerLock-protected variables.
568 *********************************************************************/
569
570 /*********************************************************************
571 * OSValueObject concrete type instantiations
572 **********/
573 OSDefineValueObjectForDependentType(void*)
574 OSDefineValueObjectForDependentType(OSKextRequestResourceCallback)
575
576
577 /**********************************************************************/
578
579 TUNABLE(uint32_t, kMaxDextCrashesInOneDay, "daily_max_dext_crashes", kMaxDextCrashesInOneDayDefault);
580
581 /*********************************************************************
582 * helper function used for collecting PGO data upon unload of a kext
583 */
584
585 static int OSKextGrabPgoDataLocked(OSKext *kext,
586 bool metadata,
587 uuid_t instance_uuid,
588 uint64_t *pSize,
589 char *pBuffer,
590 uint64_t bufferSize);
591
592 /**********************************************************************/
593
594
595
596 #if PRAGMA_MARK
597 #pragma mark OSData callbacks (need to move to OSData)
598 #endif
599 /*********************************************************************
600 * C functions used for callbacks.
601 *********************************************************************/
602 extern "C" {
603 void
osdata_kmem_free(void * ptr,unsigned int length)604 osdata_kmem_free(void * ptr, unsigned int length)
605 {
606 kmem_free(kernel_map, (vm_address_t)ptr, length);
607 return;
608 }
609
610 void
osdata_phys_free(void * ptr,unsigned int length)611 osdata_phys_free(void * ptr, unsigned int length)
612 {
613 ml_static_mfree((vm_offset_t)ptr, length);
614 return;
615 }
616
617 void
osdata_vm_deallocate(void * ptr,unsigned int length)618 osdata_vm_deallocate(void * ptr, unsigned int length)
619 {
620 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
621 return;
622 }
623
624 void
osdata_kext_free(void * ptr,unsigned int length)625 osdata_kext_free(void * ptr, unsigned int length)
626 {
627 (void)kext_free((vm_offset_t)ptr, length);
628 }
629 };
630
631 #if PRAGMA_MARK
632 #pragma mark KXLD Allocation Callback
633 #endif
634 #if CONFIG_KXLD
635 /*********************************************************************
636 * KXLD Allocation Callback
637 *********************************************************************/
638 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)639 kern_allocate(
640 u_long size,
641 KXLDAllocateFlags * flags,
642 void * user_data)
643 {
644 vm_address_t result = 0; // returned
645 kern_return_t mach_result = KERN_FAILURE;
646 bool success = false;
647 OSKext * theKext = (OSKext *)user_data;
648 unsigned int roundSize = 0;
649 OSSharedPtr<OSData> linkBuffer;
650
651 if (round_page(size) > UINT_MAX) {
652 OSKextLog(theKext,
653 kOSKextLogErrorLevel |
654 kOSKextLogGeneralFlag,
655 "%s: Requested memory size is greater than UINT_MAX.",
656 theKext->getIdentifierCString());
657 goto finish;
658 }
659
660 roundSize = (unsigned int)round_page(size);
661
662 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
663 if (mach_result != KERN_SUCCESS) {
664 OSKextLog(theKext,
665 kOSKextLogErrorLevel |
666 kOSKextLogGeneralFlag,
667 "Can't allocate kernel memory to link %s.",
668 theKext->getIdentifierCString());
669 goto finish;
670 }
671
672 /* Create an OSData wrapper for the allocated buffer.
673 */
674 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
675 if (!linkBuffer) {
676 OSKextLog(theKext,
677 kOSKextLogErrorLevel |
678 kOSKextLogGeneralFlag,
679 "Can't allocate linked executable wrapper for %s.",
680 theKext->getIdentifierCString());
681 goto finish;
682 }
683 linkBuffer->setDeallocFunction(osdata_kext_free);
684 OSKextLog(theKext,
685 kOSKextLogProgressLevel |
686 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
687 "Allocated link buffer for kext %s at %p (%lu bytes).",
688 theKext->getIdentifierCString(),
689 (void *)result, (unsigned long)roundSize);
690
691 theKext->setLinkedExecutable(linkBuffer.get());
692
693 *flags = kKxldAllocateWritable;
694 success = true;
695
696 finish:
697 if (!success && result) {
698 kext_free(result, roundSize);
699 result = 0;
700 }
701
702 return (kxld_addr_t)result;
703 }
704
705 /*********************************************************************
706 *********************************************************************/
707 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)708 kxld_log_callback(
709 KXLDLogSubsystem subsystem,
710 KXLDLogLevel level,
711 const char * format,
712 va_list argList,
713 void * user_data)
714 {
715 OSKext *theKext = (OSKext *) user_data;
716 OSKextLogSpec logSpec = 0;
717
718 switch (subsystem) {
719 case kKxldLogLinking:
720 logSpec |= kOSKextLogLinkFlag;
721 break;
722 case kKxldLogPatching:
723 logSpec |= kOSKextLogPatchFlag;
724 break;
725 }
726
727 switch (level) {
728 case kKxldLogExplicit:
729 logSpec |= kOSKextLogExplicitLevel;
730 break;
731 case kKxldLogErr:
732 logSpec |= kOSKextLogErrorLevel;
733 break;
734 case kKxldLogWarn:
735 logSpec |= kOSKextLogWarningLevel;
736 break;
737 case kKxldLogBasic:
738 logSpec |= kOSKextLogProgressLevel;
739 break;
740 case kKxldLogDetail:
741 logSpec |= kOSKextLogDetailLevel;
742 break;
743 case kKxldLogDebug:
744 logSpec |= kOSKextLogDebugLevel;
745 break;
746 }
747
748 OSKextVLog(theKext, logSpec, format, argList);
749 }
750 #endif // CONFIG_KXLD
751
752 #if PRAGMA_MARK
753 #pragma mark IOStatistics defines
754 #endif
755
756 #if IOKITSTATS
757
758 #define notifyKextLoadObservers(kext, kmod_info) \
759 do { \
760 IOStatistics::onKextLoad(kext, kmod_info); \
761 } while (0)
762
763 #define notifyKextUnloadObservers(kext) \
764 do { \
765 IOStatistics::onKextUnload(kext); \
766 } while (0)
767
768 #define notifyAddClassObservers(kext, addedClass, flags) \
769 do { \
770 IOStatistics::onClassAdded(kext, addedClass); \
771 } while (0)
772
773 #define notifyRemoveClassObservers(kext, removedClass, flags) \
774 do { \
775 IOStatistics::onClassRemoved(kext, removedClass); \
776 } while (0)
777
778 #else
779
780 #define notifyKextLoadObservers(kext, kmod_info)
781 #define notifyKextUnloadObservers(kext)
782 #define notifyAddClassObservers(kext, addedClass, flags)
783 #define notifyRemoveClassObservers(kext, removedClass, flags)
784
785 #endif /* IOKITSTATS */
786
787 #if PRAGMA_MARK
788 #pragma mark Module Config (Startup & Shutdown)
789 #endif
790 /*********************************************************************
791 * Module Config (Class Definition & Class Methods)
792 *********************************************************************/
793 #define super OSObject
794 OSDefineMetaClassAndStructors(OSKext, OSObject)
795
796 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
797
798 OSDefineMetaClassAndStructors(OSDextStatistics, OSObject);
799
800 /*********************************************************************
801 *********************************************************************/
802 /**
803 * Allocate and intialize a fake/representative OSKext object for a statically
804 * loaded (by iBoot) binary (e.g., the XNU kernel itself).
805 *
806 * @param kmod_info Pointer to the kmod_info structure for the binary being
807 * setup. At least the "name" and "id" fields needs to already
808 * be set correctly.
809 *
810 * @return The allocated and initialized OSKext object.
811 */
812 /* static */
813 OSKext *
allocAndInitFakeKext(kmod_info_t * kmod_info)814 OSKext::allocAndInitFakeKext(kmod_info_t *kmod_info)
815 {
816 vm_offset_t load_address = 0;
817 const char *bundle_name = NULL;
818 bool macho_is_unslid = false;
819 bool set_custom_path = false;
820 const char *executable_fallback_name = NULL;
821
822 if (kmod_info->id == kOSKextKernelLoadTag) {
823 load_address = (vm_offset_t)&_mh_execute_header;
824 bundle_name = "mach_kernel";
825
826 /* The kernel Mach-O header is fixed up to slide all of its addresses. */
827 macho_is_unslid = false;
828
829 /**
830 * No path to the binary is set for the kernel in its OSKext object. The
831 * kernel binary is located in fixed directories depending on the OS.
832 */
833 set_custom_path = false;
834 executable_fallback_name = NULL;
835 #if CONFIG_SPTM
836 } else if (kmod_info->id == kOSKextSPTMLoadTag) {
837 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_SPTM];
838 bundle_name = "sptm";
839
840 /* The addresses in the SPTM Mach-O header are all unslid. */
841 macho_is_unslid = true;
842
843 set_custom_path = true;
844 executable_fallback_name = "sptm.no.binname.in.macho";
845 } else if (kmod_info->id == kOSKextTXMLoadTag) {
846 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_TXM];
847 bundle_name = "txm";
848
849 /* The addresses in the TXM Mach-O header are all unslid. */
850 macho_is_unslid = true;
851
852 set_custom_path = true;
853 executable_fallback_name = "txm.no.binname.in.macho";
854 #endif /* CONFIG_SPTM */
855 } else {
856 panic("%s: Unsupported kmod_info->id (%d)", __func__, kmod_info->id);
857 }
858
859 /* Set up an OSKext instance to represent the statically loaded binary. */
860 OSKext *fakeKext = new OSKext;
861 assert(fakeKext);
862 assert(load_address != 0);
863
864 /*
865 * The start address is always a slid address whereas the last VA returned
866 * by getlastaddr() might be unslid depending on the Mach-O. If the address
867 * coming from the Mach-O is unslid, then unslide the start address before
868 * computing the length of the executable.
869 */
870 size_t binaryLength = getlastaddr((kernel_mach_header_t*)load_address);
871 binaryLength -= (macho_is_unslid) ? ml_static_unslide(load_address) : load_address;
872 assert(binaryLength <= UINT_MAX);
873
874 /**
875 * The load address is always slid. That value will be unslid before being
876 * exposed to userspace.
877 */
878 OSSharedPtr<OSData> executable = OSData::withBytesNoCopy(
879 (void*)load_address, (unsigned int)binaryLength);
880 assert(executable);
881
882 fakeKext->loadTag = sNextLoadTag++;
883 fakeKext->bundleID = OSSymbol::withCString(kmod_info->name);
884
885 fakeKext->version = OSKextParseVersionString(osrelease);
886 fakeKext->compatibleVersion = fakeKext->version;
887 fakeKext->linkedExecutable = os::move(executable);
888 fakeKext->interfaceUUID = fakeKext->copyUUID();
889
890 fakeKext->flags.hasAllDependencies = 1;
891 fakeKext->flags.kernelComponent = 1;
892 fakeKext->flags.prelinked = 0;
893 fakeKext->flags.loaded = 1;
894 fakeKext->flags.started = 1;
895 fakeKext->flags.CPPInitialized = 0;
896 fakeKext->flags.jettisonLinkeditSeg = 0;
897 fakeKext->flags.unslidMachO = macho_is_unslid;
898
899 #if CONFIG_SPTM
900 if (set_custom_path) {
901 /* Only SPTM/TXM should have custom paths to their executables set. */
902 assert((kmod_info->id == kOSKextSPTMLoadTag) ||
903 (kmod_info->id == kOSKextTXMLoadTag));
904
905 /* All SPTM/TXM binaries are placed into the same path on internal systems. */
906 fakeKext->path = OSString::withCStringNoCopy("/usr/appleinternal/standalone/platform");
907
908 /**
909 * Each SPTM/TXM Mach-O should contain a __TEXT,__binname section which contains
910 * a character array representing the name of the Mach-O executable.
911 */
912 kernel_section_t *binname_sect =
913 getsectbynamefromheader((kernel_mach_header_t*)load_address, "__TEXT", "__binname");
914
915 if (binname_sect != NULL) {
916 const char *binname = (const char *)ml_static_slide(binname_sect->addr);
917 fakeKext->executableRelPath = OSString::withCStringNoCopy(binname);
918 } else {
919 fakeKext->executableRelPath = OSString::withCStringNoCopy(executable_fallback_name);
920 }
921 }
922 #endif /* CONFIG_SPTM */
923
924 fakeKext->kmod_info = kmod_info;
925 strlcpy(kmod_info->version, osrelease,
926 sizeof(kmod_info->version));
927 kmod_info->size = binaryLength;
928 assert(kmod_info->id == fakeKext->loadTag);
929
930 /*
931 * Con up an info dict, so we don't have to have special-case checking all
932 * over.
933 */
934 fakeKext->infoDict = OSDictionary::withCapacity(5);
935 assert(fakeKext->infoDict);
936 bool setResult = fakeKext->infoDict->setObject(kCFBundleIdentifierKey,
937 fakeKext->bundleID.get());
938 assert(setResult);
939 setResult = fakeKext->infoDict->setObject(kOSKernelResourceKey,
940 kOSBooleanTrue);
941 assert(setResult);
942
943 {
944 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
945 assert(scratchString);
946 setResult = fakeKext->infoDict->setObject(kCFBundleVersionKey,
947 scratchString.get());
948 assert(setResult);
949 }
950
951 {
952 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(bundle_name));
953 assert(scratchString);
954 setResult = fakeKext->infoDict->setObject(kCFBundleNameKey,
955 scratchString.get());
956 assert(setResult);
957 }
958
959 return fakeKext;
960 }
961
962 /* static */
963 void
initialize(void)964 OSKext::initialize(void)
965 {
966 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
967 IORegistryEntry * registryRoot = NULL;// do not release
968 OSSharedPtr<OSNumber> kernelCPUType;
969 OSSharedPtr<OSNumber> kernelCPUSubtype;
970 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
971 bool setResult = false;
972 uint64_t * timestamp = NULL;
973 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
974
975 /* This must be the first thing allocated. Everything else grabs this lock.
976 */
977 sKextLock = IORecursiveLockAlloc();
978 sKextInnerLock = IORecursiveLockAlloc();
979 sKextSummariesLock = IOLockAlloc();
980 sKextLoggingLock = IOLockAlloc();
981 assert(sKextLock);
982 assert(sKextInnerLock);
983 assert(sKextSummariesLock);
984 assert(sKextLoggingLock);
985
986 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
987 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
988 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
989 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
990 sKernelRequests = OSArray::withCapacity(0);
991 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
992 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
993 sRequestCallbackRecords = OSArray::withCapacity(0);
994 sDriverKitToUpgradeByID = OSDictionary::withCapacity(kOSKextTypicalUpgradeCount);
995
996 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
997 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
998 sRequestCallbackRecords && sUnloadedPrelinkedKexts && sDriverKitToUpgradeByID);
999
1000 /* Read the log flag boot-args and set the log flags.
1001 */
1002 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
1003 sBootArgLogFilterFound = true;
1004 sKernelLogFilter = bootLogFilter;
1005 // log this if any flags are set
1006 OSKextLog(/* kext */ NULL,
1007 kOSKextLogBasicLevel |
1008 kOSKextLogFlagsMask,
1009 "Kernel kext log filter 0x%x per kextlog boot arg.",
1010 (unsigned)sKernelLogFilter);
1011 }
1012
1013 #if !defined(__arm__) && !defined(__arm64__)
1014 /*
1015 * On our ARM targets, the kernelcache/boot kernel collection contains
1016 * the set of kexts required to boot, as specified by KCB. Safeboot is
1017 * either unsupported, or is supported by the bootloader only loading
1018 * the boot kernel collection; as a result OSKext has no role to play
1019 * in safeboot policy on ARM.
1020 */
1021 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
1022 sizeof(bootArgBuffer)) ? true : false;
1023 #endif /* defined(__arm__) && defined(__arm64__) */
1024
1025 if (sSafeBoot) {
1026 OSKextLog(/* kext */ NULL,
1027 kOSKextLogWarningLevel |
1028 kOSKextLogGeneralFlag,
1029 "SAFE BOOT DETECTED - "
1030 "only valid OSBundleRequired kexts will be loaded.");
1031 }
1032
1033 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
1034 #if CONFIG_DTRACE
1035 if (dtrace_keep_kernel_symbols()) {
1036 sKeepSymbols = true;
1037 }
1038 #endif /* CONFIG_DTRACE */
1039 #if KASAN_DYNAMIC_DENYLIST
1040 /* needed for function lookup */
1041 sKeepSymbols = true;
1042 #endif /* KASAN_DYNAMIC_DENYLIST */
1043
1044 /*
1045 * Should we panic when the SystemKC is not linked against the
1046 * BootKC that was loaded by the booter? By default: yes, if the
1047 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
1048 * on mis-match and instead just print an error and continue.
1049 */
1050 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
1051 sizeof(bootArgBuffer)) ? false : true;
1052
1053 /* Set up an OSKext instance to represent the kernel itself. */
1054 sKernelKext = allocAndInitFakeKext(&g_kernel_kmod_info);
1055 assert(sKernelKext);
1056
1057 #if CONFIG_SPTM
1058 /* Set up OSKext instances to represent the SPTM/TXM. */
1059 OSKext *SPTMKext = allocAndInitFakeKext(&g_sptm_kmod_info);
1060 OSKext *TXMKext = allocAndInitFakeKext(&g_txm_kmod_info);
1061 #endif
1062
1063 /* Add the kernel kext to the bookkeeping dictionaries. Note that
1064 * the kernel kext doesn't have a kmod_info struct. copyInfo()
1065 * gathers info from other places anyhow.
1066 */
1067 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
1068 assert(setResult);
1069 setResult = sLoadedKexts->setObject(sKernelKext);
1070 assert(setResult);
1071
1072 #if CONFIG_SPTM
1073 setResult = sKextsByID->setObject(SPTMKext->bundleID.get(), SPTMKext);
1074 assert(setResult);
1075 setResult = sLoadedKexts->setObject(SPTMKext);
1076 assert(setResult);
1077
1078 setResult = sKextsByID->setObject(TXMKext->bundleID.get(), TXMKext);
1079 assert(setResult);
1080 setResult = sLoadedKexts->setObject(TXMKext);
1081 assert(setResult);
1082 #endif /* CONFIG_SPTM */
1083
1084 // XXX: better way with OSSharedPtr?
1085 // sKernelKext remains a valid pointer even after the decref
1086 sKernelKext->release();
1087 #if CONFIG_SPTM
1088 SPTMKext->release();
1089 TXMKext->release();
1090 #endif /* CONFIG_SPTM */
1091
1092 registryRoot = IORegistryEntry::getRegistryRoot();
1093 kernelCPUType = OSNumber::withNumber(
1094 (long long unsigned int)_mh_execute_header.cputype,
1095 8 * sizeof(_mh_execute_header.cputype));
1096 kernelCPUSubtype = OSNumber::withNumber(
1097 (long long unsigned int)_mh_execute_header.cpusubtype,
1098 8 * sizeof(_mh_execute_header.cpusubtype));
1099 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
1100
1101 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
1102 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
1103
1104 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
1105 if (gBuiltinKmodsSectionInfo) {
1106 uint32_t count;
1107
1108 assert(gBuiltinKmodsSectionInfo->addr);
1109 assert(gBuiltinKmodsSectionInfo->size);
1110 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
1111 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
1112
1113 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
1114 assert(gBuiltinKmodsSectionStart);
1115 assert(gBuiltinKmodsSectionStart->addr);
1116 assert(gBuiltinKmodsSectionStart->size);
1117 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
1118 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
1119 // one extra pointer for the end of last kmod
1120 assert(count == (gBuiltinKmodsCount + 1));
1121
1122 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
1123 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
1124 }
1125
1126 // Don't track this object -- it's never released
1127 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
1128
1129 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
1130 *timestamp = 0;
1131 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
1132 *timestamp = 0;
1133 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
1134 *timestamp = 0;
1135
1136 OSKextLog(/* kext */ NULL,
1137 kOSKextLogProgressLevel |
1138 kOSKextLogGeneralFlag,
1139 "Kext system initialized.");
1140
1141 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
1142 #if CONFIG_SPTM
1143 notifyKextLoadObservers(SPTMKext, SPTMKext->kmod_info);
1144 notifyKextLoadObservers(TXMKext, TXMKext->kmod_info);
1145 #endif
1146
1147 return;
1148 }
1149
1150 /*********************************************************************
1151 * This is expected to be called exactly once, from exactly one thread
1152 * context, during kernel bootstrap.
1153 *********************************************************************/
1154 /* static */
1155 OSReturn
removeKextBootstrap(void)1156 OSKext::removeKextBootstrap(void)
1157 {
1158 OSReturn result = kOSReturnError;
1159
1160 const char * dt_kernel_header_name = "Kernel-__HEADER";
1161 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
1162 kernel_mach_header_t * dt_mach_header = NULL;
1163 int dt_mach_header_size = 0;
1164 struct symtab_command * dt_symtab = NULL;
1165 int dt_symtab_size = 0;
1166 int dt_result = 0;
1167
1168 kernel_segment_command_t * seg_kld = NULL;
1169 kernel_segment_command_t * seg_klddata = NULL;
1170 kernel_segment_command_t * seg_linkedit = NULL;
1171
1172 const char __unused * dt_segment_name = NULL;
1173 void __unused * segment_paddress = NULL;
1174 int __unused segment_size = 0;
1175
1176 OSKextLog(/* kext */ NULL,
1177 kOSKextLogProgressLevel |
1178 kOSKextLogGeneralFlag,
1179 "Jettisoning kext bootstrap segments.");
1180
1181 /*
1182 * keep the linkedit segment around when booted from a new MH_FILESET
1183 * KC because all the kexts shared a linkedit segment.
1184 */
1185 kc_format_t kc_format;
1186 if (!PE_get_primary_kc_format(&kc_format)) {
1187 OSKextLog(/* kext */ NULL,
1188 kOSKextLogErrorLevel |
1189 kOSKextLogGeneralFlag,
1190 "Unable to determine primary KC format");
1191 }
1192
1193 /*****
1194 * Dispose of unnecessary stuff that the booter didn't need to load.
1195 */
1196 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1197 (void **)&dt_mach_header, &dt_mach_header_size);
1198 if (dt_result == 0 && dt_mach_header) {
1199 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1200 round_page_32(dt_mach_header_size));
1201 }
1202 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1203 (void **)&dt_symtab, &dt_symtab_size);
1204 if (dt_result == 0 && dt_symtab) {
1205 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1206 round_page_32(dt_symtab_size));
1207 }
1208
1209 /*****
1210 * KLD & KLDDATA bootstrap segments.
1211 */
1212 // xxx - should rename KLD segment
1213 seg_kld = getsegbyname("__KLD");
1214 seg_klddata = getsegbyname("__KLDDATA");
1215 if (seg_klddata) {
1216 // __mod_term_func is part of __KLDDATA
1217 OSRuntimeUnloadCPPForSegment(seg_klddata);
1218 }
1219
1220 #if __arm__ || __arm64__
1221 /* Free the memory that was set up by iBoot.
1222 */
1223 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1224 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1225 * is covered by the contiguous rorgn.
1226 */
1227 dt_segment_name = "Kernel-__KLD";
1228 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1229 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1230 (int)segment_size); // calls ml_static_mfree
1231 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1232 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1233 #if !CONFIG_SPTM
1234 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1235 seg_kld->vmsize);
1236 #else
1237 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1238 #endif
1239 }
1240 #endif
1241 dt_segment_name = "Kernel-__KLDDATA";
1242 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1243 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1244 (int)segment_size); // calls ml_static_mfree
1245 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1246 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1247 #if !CONFIG_SPTM
1248 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1249 seg_klddata->vmsize);
1250 #else
1251 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1252 #endif
1253 }
1254 #elif __i386__ || __x86_64__
1255 /* On x86, use the mapping data from the segment load command to
1256 * unload KLD & KLDDATA directly.
1257 * This may invalidate any assumptions about "avail_start"
1258 * defining the lower bound for valid physical addresses.
1259 */
1260 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1261 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1262 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1263 }
1264 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1265 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1266 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1267 }
1268 #else
1269 #error arch
1270 #endif
1271
1272 /*****
1273 * Prelinked kernel's symtab (if there is one).
1274 */
1275 if (kc_format != KCFormatFileset) {
1276 kernel_section_t * sect;
1277 sect = getsectbyname("__PRELINK", "__symtab");
1278 if (sect && sect->addr && sect->size) {
1279 ml_static_mfree(sect->addr, sect->size);
1280 }
1281 }
1282
1283 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1284
1285 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1286 * pageable, unless keepsyms is set. To do that, we have to copy it from
1287 * its booter-allocated memory, free the booter memory, reallocate proper
1288 * managed memory, then copy the segment back in.
1289 *
1290 * NOTE: This optimization is not valid for fileset KCs because each
1291 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1292 * that points to one fileset-global LINKEDIT segment. This
1293 * optimization is also only valid for platforms that support vm
1294 * mapped kexts or mapped kext collections (pageable KCs)
1295 */
1296 #if VM_MAPPED_KEXTS
1297 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1298 kern_return_t mem_result;
1299 void *seg_copy = NULL;
1300 void *seg_data = NULL;
1301 vm_map_offset_t seg_offset = 0;
1302 vm_map_offset_t seg_copy_offset = 0;
1303 vm_map_size_t seg_length = 0;
1304
1305 seg_data = (void *) seg_linkedit->vmaddr;
1306 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1307 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1308
1309 /* Allocate space for the LINKEDIT copy.
1310 */
1311 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1312 seg_length, KMA_ZERO, VM_KERN_MEMORY_KEXT);
1313 if (mem_result != KERN_SUCCESS) {
1314 OSKextLog(/* kext */ NULL,
1315 kOSKextLogErrorLevel |
1316 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1317 "Can't copy __LINKEDIT segment for VM reassign.");
1318 return result;
1319 }
1320 seg_copy_offset = (vm_map_offset_t) seg_copy;
1321
1322 /* Copy it out.
1323 */
1324 memcpy(seg_copy, seg_data, seg_length);
1325
1326 /* Dump the booter memory.
1327 */
1328 ml_static_mfree(seg_offset, seg_length);
1329
1330 /* Set up the VM region.
1331 */
1332 mem_result = mach_vm_map_kernel(
1333 kernel_map,
1334 &seg_offset,
1335 seg_length, /* mask */ 0,
1336 VM_MAP_KERNEL_FLAGS_FIXED(.vmf_overwrite = true),
1337 (ipc_port_t)NULL,
1338 (vm_object_offset_t) 0,
1339 /* copy */ FALSE,
1340 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1341 /* max_protection */ VM_PROT_ALL,
1342 /* inheritance */ VM_INHERIT_DEFAULT);
1343 if ((mem_result != KERN_SUCCESS) ||
1344 (seg_offset != (vm_map_offset_t) seg_data)) {
1345 OSKextLog(/* kext */ NULL,
1346 kOSKextLogErrorLevel |
1347 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1348 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1349 seg_data, seg_length, mem_result);
1350 return result;
1351 }
1352
1353 /* And copy it back.
1354 */
1355 memcpy(seg_data, seg_copy, seg_length);
1356
1357 /* Free the copy.
1358 */
1359 kmem_free(kernel_map, seg_copy_offset, seg_length);
1360 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1361 /* Remove the linkedit segment of the Boot KC */
1362 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1363 OSKext::jettisonFileSetLinkeditSegment(mh);
1364 }
1365 #else // !VM_MAPPED_KEXTS
1366 /*****
1367 * Dump the LINKEDIT segment, unless keepsyms is set.
1368 */
1369 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1370 dt_segment_name = "Kernel-__LINKEDIT";
1371 if (0 == IODTGetLoaderInfo(dt_segment_name,
1372 &segment_paddress, &segment_size)) {
1373 #ifdef SECURE_KERNEL
1374 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1375 bzero((void*)vmaddr, segment_size);
1376 #endif
1377 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1378 (int)segment_size);
1379 }
1380 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1381 /* Remove the linkedit segment of the Boot KC */
1382 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1383 OSKext::jettisonFileSetLinkeditSegment(mh);
1384 } else {
1385 OSKextLog(/* kext */ NULL,
1386 kOSKextLogBasicLevel |
1387 kOSKextLogGeneralFlag,
1388 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1389 }
1390 #endif // VM_MAPPED_KEXTS
1391
1392 result = kOSReturnSuccess;
1393
1394 return result;
1395 }
1396
1397 #if CONFIG_KXLD
1398 /*********************************************************************
1399 *********************************************************************/
1400 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1401 OSKext::flushNonloadedKexts(
1402 Boolean flushPrelinkedKexts)
1403 {
1404 OSSharedPtr<OSSet> keepKexts;
1405
1406 /* TODO: make this more efficient with MH_FILESET kexts */
1407
1408 // Do not unload prelinked kexts on arm because the kernelcache is not
1409 // structured in a way that allows them to be unmapped
1410 #if !defined(__x86_64__)
1411 flushPrelinkedKexts = false;
1412 #endif /* defined(__x86_64__) */
1413
1414 IORecursiveLockLock(sKextLock);
1415
1416 OSKextLog(/* kext */ NULL,
1417 kOSKextLogProgressLevel |
1418 kOSKextLogKextBookkeepingFlag,
1419 "Flushing nonloaded kexts and other unused data.");
1420
1421 OSKext::considerDestroyingLinkContext();
1422
1423 /* If we aren't flushing unused prelinked kexts, we have to put them
1424 * aside while we flush everything else so make a container for them.
1425 */
1426 keepKexts = OSSet::withCapacity(16);
1427 if (!keepKexts) {
1428 goto finish;
1429 }
1430
1431 /* Set aside prelinked kexts (in-use or not) and break
1432 * any lingering inter-kext references for nonloaded kexts
1433 * so they have min. retain counts.
1434 */
1435 {
1436 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1437 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1438 if (!thisKext) {
1439 return false;
1440 }
1441 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1442 keepKexts->setObject(thisKext);
1443 } else if (!thisKext->declaresExecutable()) {
1444 /*
1445 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1446 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1447 * flushNonloadedKexts().
1448 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1449 */
1450 keepKexts->setObject(thisKext);
1451 } else if (thisKext->isInFileset()) {
1452 /* keep all kexts in the new MH_FILESET KC */
1453 keepKexts->setObject(thisKext);
1454 }
1455
1456 thisKext->flushDependencies(/* forceIfLoaded */ false);
1457 return false;
1458 });
1459 }
1460 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1461 */
1462 sKextsByID->flushCollection();
1463
1464 /* Now put the loaded kexts back into the ID dictionary.
1465 */
1466 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1467 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1468 if (!thisKext) {
1469 return false;
1470 }
1471 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1472 return false;
1473 });
1474
1475 /* Finally, put back the kept kexts if we saved any.
1476 */
1477 keepKexts->iterateObjects(^bool (OSObject * obj) {
1478 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1479 if (!thisKext) {
1480 return false;
1481 }
1482 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1483 return false;
1484 });
1485
1486 finish:
1487 IORecursiveLockUnlock(sKextLock);
1488 return;
1489 }
1490 #else /* !CONFIG_KXLD */
1491
1492 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1493 OSKext::flushNonloadedKexts(
1494 Boolean flushPrelinkedKexts __unused)
1495 {
1496 IORecursiveLockLock(sKextLock);
1497
1498 OSKextLog(/* kext */ NULL,
1499 kOSKextLogProgressLevel |
1500 kOSKextLogKextBookkeepingFlag,
1501 "Flushing dependency info for non-loaded kexts.");
1502
1503 /*
1504 * In a world where we don't dynamically link kexts, they all come
1505 * from a kext collection that's either in wired memory, or
1506 * wire-on-demand. We don't need to mess around with moving kexts in
1507 * and out of the sKextsByID array - they can all just stay there.
1508 * Here we just flush the dependency list for kexts that are not
1509 * loaded.
1510 */
1511 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1512 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1513 if (!thisKext) {
1514 return false;
1515 }
1516 thisKext->flushDependencies(/* forceIfLoaded */ false);
1517 return false;
1518 });
1519
1520 IORecursiveLockUnlock(sKextLock);
1521 return;
1522 }
1523
1524 #endif /* CONFIG_KXLD */
1525
1526 /*********************************************************************
1527 *********************************************************************/
1528 /* static */
1529 void
setIOKitDaemonActive(bool active)1530 OSKext::setIOKitDaemonActive(bool active)
1531 {
1532 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1533 IORecursiveLockLock(sKextLock);
1534 sIOKitDaemonActive = active;
1535 if (sKernelRequests->getCount()) {
1536 OSKext::pingIOKitDaemon();
1537 }
1538 IORecursiveLockUnlock(sKextLock);
1539
1540 return;
1541 }
1542
1543 /*********************************************************************
1544 * OSKextLib.cpp might need access to this someday but for now it's
1545 * private.
1546 *********************************************************************/
1547 extern "C" {
1548 extern void ipc_port_release_send(ipc_port_t);
1549 };
1550
1551 /* static */
1552 OSReturn
pingIOKitDaemon(void)1553 OSKext::pingIOKitDaemon(void)
1554 {
1555 OSReturn result = kOSReturnError;
1556 #if !NO_KEXTD
1557 mach_port_t kextd_port = IPC_PORT_NULL;
1558
1559 if (!sIOKitDaemonActive) {
1560 result = kOSKextReturnDisabled; // basically unavailable
1561 goto finish;
1562 }
1563
1564 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1565 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1566 OSKextLog(/* kext */ NULL,
1567 kOSKextLogErrorLevel |
1568 kOSKextLogIPCFlag,
1569 "Can't get " kIOKitDaemonName " port.");
1570 goto finish;
1571 }
1572
1573 result = kextd_ping(kextd_port);
1574 if (result != KERN_SUCCESS) {
1575 OSKextLog(/* kext */ NULL,
1576 kOSKextLogErrorLevel |
1577 kOSKextLogIPCFlag,
1578 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1579 goto finish;
1580 }
1581
1582 finish:
1583 if (IPC_PORT_VALID(kextd_port)) {
1584 ipc_port_release_send(kextd_port);
1585 }
1586 #endif
1587
1588 return result;
1589 }
1590
1591 /*********************************************************************
1592 *********************************************************************/
1593 /* static */
1594 bool
driverkitEnabled(void)1595 OSKext::driverkitEnabled(void)
1596 {
1597 #if XNU_TARGET_OS_WATCH
1598 return false;
1599 #else //!XNU_TARGET_OS_WATCH
1600 return true;
1601 #endif //XNU_TARGET_OS_WATCH
1602 }
1603
1604 /*********************************************************************
1605 *********************************************************************/
1606 /* static */
1607 bool
iokitDaemonAvailable(void)1608 OSKext::iokitDaemonAvailable(void)
1609 {
1610 #if !XNU_TARGET_OS_IOS && !XNU_TARGET_OS_OSX
1611 int notused;
1612 if (PE_parse_boot_argn("-restore", ¬used, sizeof(notused))) {
1613 return false;
1614 }
1615 #endif //!XNU_TARGET_OS_IOS && !XNU_TARGET_OS_OSX
1616 return driverkitEnabled();
1617 }
1618
1619 /*********************************************************************
1620 *********************************************************************/
1621 /* static */
1622 void
setDeferredLoadSucceeded(Boolean succeeded)1623 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1624 {
1625 IORecursiveLockLock(sKextLock);
1626 sDeferredLoadSucceeded = succeeded;
1627 IORecursiveLockUnlock(sKextLock);
1628
1629 return;
1630 }
1631
1632 /*********************************************************************
1633 * Called from IOSystemShutdownNotification.
1634 *********************************************************************/
1635 /* static */
1636 void
willShutdown(void)1637 OSKext::willShutdown(void)
1638 {
1639 #if !NO_KEXTD
1640 OSReturn checkResult = kOSReturnError;
1641 #endif
1642 OSSharedPtr<OSDictionary> exitRequest;
1643
1644 IORecursiveLockLock(sKextLock);
1645
1646 OSKext::setLoadEnabled(false);
1647 OSKext::setUnloadEnabled(false);
1648 OSKext::setAutounloadsEnabled(false);
1649 OSKext::setKernelRequestsEnabled(false);
1650
1651 #if defined(__x86_64__) || defined(__i386__)
1652 if (IOPMRootDomainGetWillShutdown()) {
1653 OSKext::freeKCFileSetcontrol();
1654 }
1655 #endif // (__x86_64__) || defined(__i386__)
1656
1657 #if !NO_KEXTD
1658 OSKextLog(/* kext */ NULL,
1659 kOSKextLogProgressLevel |
1660 kOSKextLogGeneralFlag,
1661 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1662
1663 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1664 exitRequest);
1665 if (checkResult != kOSReturnSuccess) {
1666 goto finish;
1667 }
1668 if (!sKernelRequests->setObject(exitRequest.get())) {
1669 goto finish;
1670 }
1671
1672 OSKext::pingIOKitDaemon();
1673
1674 finish:
1675 #endif
1676
1677 IORecursiveLockUnlock(sKextLock);
1678 return;
1679 }
1680
1681 void
willUserspaceReboot(void)1682 OSKext::willUserspaceReboot(void)
1683 {
1684 OSKext::willShutdown();
1685 IOService::userSpaceWillReboot();
1686 gIOCatalogue->terminateDriversForUserspaceReboot();
1687 }
1688
1689 void
resetAfterUserspaceReboot(void)1690 OSKext::resetAfterUserspaceReboot(void)
1691 {
1692 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1693 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1694
1695 IORecursiveLockLock(sKextLock);
1696 gIOCatalogue->resetAfterUserspaceReboot();
1697 IOService::userSpaceDidReboot();
1698 OSKext::removeDaemonExitRequests();
1699 OSKext::setLoadEnabled(true);
1700 OSKext::setUnloadEnabled(true);
1701 OSKext::setAutounloadsEnabled(true);
1702 OSKext::setKernelRequestsEnabled(true);
1703 sOSKextWasResetAfterUserspaceReboot = true;
1704 IORecursiveLockUnlock(sKextLock);
1705 }
1706
1707 extern "C" void
OSKextResetAfterUserspaceReboot(void)1708 OSKextResetAfterUserspaceReboot(void)
1709 {
1710 OSKext::resetAfterUserspaceReboot();
1711 }
1712
1713 /*
1714 * Remove daemon exit requests from sKernelRequests
1715 *
1716 * If we sent a daemon exit request during a userspace reboot and launchd
1717 * killed the IOKit daemon before it was able to dequeue the exit request, the
1718 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1719 *
1720 * This removes exit requests so that this does not happen.
1721 */
1722 void
removeDaemonExitRequests(void)1723 OSKext::removeDaemonExitRequests(void)
1724 {
1725 OSDictionary * current = NULL;
1726 OSString * predicate = NULL;
1727 size_t index = 0;
1728 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1729
1730 while (index < sKernelRequests->getCount()) {
1731 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1732 if (current) {
1733 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1734 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1735 sKernelRequests->removeObject(index);
1736 continue;
1737 }
1738 }
1739 index++;
1740 }
1741 }
1742
1743 /*********************************************************************
1744 *********************************************************************/
1745 /* static */
1746 bool
getLoadEnabled(void)1747 OSKext::getLoadEnabled(void)
1748 {
1749 bool result;
1750
1751 IORecursiveLockLock(sKextLock);
1752 result = sLoadEnabled;
1753 IORecursiveLockUnlock(sKextLock);
1754 return result;
1755 }
1756
1757 /*********************************************************************
1758 *********************************************************************/
1759 /* static */
1760 bool
setLoadEnabled(bool flag)1761 OSKext::setLoadEnabled(bool flag)
1762 {
1763 bool result;
1764
1765 IORecursiveLockLock(sKextLock);
1766 result = sLoadEnabled;
1767 sLoadEnabled = (flag ? true : false);
1768
1769 if (sLoadEnabled != result) {
1770 OSKextLog(/* kext */ NULL,
1771 kOSKextLogBasicLevel |
1772 kOSKextLogLoadFlag,
1773 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1774 }
1775
1776 IORecursiveLockUnlock(sKextLock);
1777
1778 return result;
1779 }
1780
1781 /*********************************************************************
1782 *********************************************************************/
1783 /* static */
1784 bool
getUnloadEnabled(void)1785 OSKext::getUnloadEnabled(void)
1786 {
1787 bool result;
1788
1789 IORecursiveLockLock(sKextLock);
1790 result = sUnloadEnabled;
1791 IORecursiveLockUnlock(sKextLock);
1792 return result;
1793 }
1794
1795 /*********************************************************************
1796 *********************************************************************/
1797 /* static */
1798 bool
setUnloadEnabled(bool flag)1799 OSKext::setUnloadEnabled(bool flag)
1800 {
1801 bool result;
1802
1803 IORecursiveLockLock(sKextLock);
1804 result = sUnloadEnabled;
1805 sUnloadEnabled = (flag ? true : false);
1806 IORecursiveLockUnlock(sKextLock);
1807
1808 if (sUnloadEnabled != result) {
1809 OSKextLog(/* kext */ NULL,
1810 kOSKextLogBasicLevel |
1811 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1812 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1813 }
1814
1815 return result;
1816 }
1817
1818 /*********************************************************************
1819 * Do not call any function that takes sKextLock here!
1820 *********************************************************************/
1821 /* static */
1822 bool
getAutounloadEnabled(void)1823 OSKext::getAutounloadEnabled(void)
1824 {
1825 #if XNU_TARGET_OS_OSX
1826 bool result;
1827
1828 IORecursiveLockLock(sKextInnerLock);
1829 result = sAutounloadEnabled ? true : false;
1830 IORecursiveLockUnlock(sKextInnerLock);
1831 return result;
1832 #else
1833 return false;
1834 #endif /* XNU_TARGET_OS_OSX */
1835 }
1836
1837 /*********************************************************************
1838 * Do not call any function that takes sKextLock here!
1839 *********************************************************************/
1840 /* static */
1841 bool
setAutounloadsEnabled(bool flag)1842 OSKext::setAutounloadsEnabled(bool flag)
1843 {
1844 #if XNU_TARGET_OS_OSX
1845 bool result;
1846
1847 IORecursiveLockLock(sKextInnerLock);
1848
1849 result = sAutounloadEnabled;
1850 sAutounloadEnabled = (flag ? true : false);
1851 if (!sAutounloadEnabled && sUnloadCallout) {
1852 thread_call_cancel(sUnloadCallout);
1853 }
1854
1855 if (sAutounloadEnabled != result) {
1856 OSKextLog(/* kext */ NULL,
1857 kOSKextLogBasicLevel |
1858 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1859 "Kext autounloading now %sabled.",
1860 sAutounloadEnabled ? "en" : "dis");
1861 }
1862
1863 IORecursiveLockUnlock(sKextInnerLock);
1864
1865 return result;
1866 #else
1867 (void)flag;
1868 return false;
1869 #endif /* XNU_TARGET_OS_OSX */
1870 }
1871
1872 /*********************************************************************
1873 *********************************************************************/
1874 /* instance method operating on OSKext field */
1875 bool
setAutounloadEnabled(bool flag)1876 OSKext::setAutounloadEnabled(bool flag)
1877 {
1878 bool result = flags.autounloadEnabled ? true : false;
1879 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1880
1881 if (result != (flag ? true : false)) {
1882 OSKextLog(this,
1883 kOSKextLogProgressLevel |
1884 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1885 "Autounloading for kext %s now %sabled.",
1886 getIdentifierCString(),
1887 flags.autounloadEnabled ? "en" : "dis");
1888 }
1889 return result;
1890 }
1891
1892 /*********************************************************************
1893 *********************************************************************/
1894 /* static */
1895 bool
setKernelRequestsEnabled(bool flag)1896 OSKext::setKernelRequestsEnabled(bool flag)
1897 {
1898 bool result;
1899
1900 IORecursiveLockLock(sKextLock);
1901 result = sKernelRequestsEnabled;
1902 sKernelRequestsEnabled = flag ? true : false;
1903
1904 if (sKernelRequestsEnabled != result) {
1905 OSKextLog(/* kext */ NULL,
1906 kOSKextLogBasicLevel |
1907 kOSKextLogGeneralFlag,
1908 "Kernel requests now %sabled.",
1909 sKernelRequestsEnabled ? "en" : "dis");
1910 }
1911 IORecursiveLockUnlock(sKextLock);
1912 return result;
1913 }
1914
1915 /*********************************************************************
1916 *********************************************************************/
1917 /* static */
1918 bool
getKernelRequestsEnabled(void)1919 OSKext::getKernelRequestsEnabled(void)
1920 {
1921 bool result;
1922
1923 IORecursiveLockLock(sKextLock);
1924 result = sKernelRequestsEnabled;
1925 IORecursiveLockUnlock(sKextLock);
1926 return result;
1927 }
1928
1929 static bool
segmentIsMutable(kernel_segment_command_t * seg)1930 segmentIsMutable(kernel_segment_command_t *seg)
1931 {
1932 /* Mutable segments have to have VM_PROT_WRITE */
1933 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1934 return false;
1935 }
1936 /* Exclude the __DATA_CONST segment */
1937 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1938 return false;
1939 }
1940 /* Exclude __LINKEDIT */
1941 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1942 return false;
1943 }
1944 return true;
1945 }
1946
1947 #if PRAGMA_MARK
1948 #pragma mark Kext Life Cycle
1949 #endif
1950 /*********************************************************************
1951 *********************************************************************/
1952 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1953 OSKext::withPrelinkedInfoDict(
1954 OSDictionary * anInfoDict,
1955 bool doCoalescedSlides,
1956 kc_kind_t type)
1957 {
1958 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1959
1960 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1961 return NULL;
1962 }
1963
1964 return newKext;
1965 }
1966
1967 OSData *
parseDextUniqueID(OSDictionary * anInfoDict,const char * dextIDCS)1968 OSKext::parseDextUniqueID(
1969 OSDictionary * anInfoDict,
1970 const char *dextIDCS)
1971 {
1972 OSData *ret = NULL;
1973 OSData *data_duid = OSDynamicCast(OSData, anInfoDict->getObject(kOSBundleDextUniqueIdentifierKey));
1974 if (data_duid != NULL) {
1975 if (data_duid->getLength() > KOSBundleDextUniqueIdentifierMaxLength) {
1976 OSKextLog(NULL,
1977 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1978 "Dext %s DextUniqueIdentifier too long.",
1979 dextIDCS);
1980 } else {
1981 /*
1982 * If the DextUniqueID exists it should be
1983 * present also into the personalities.
1984 */
1985 setDextUniqueIDInPersonalities(anInfoDict, data_duid);
1986 ret = data_duid;
1987 }
1988 } else {
1989 OSKextLog(NULL,
1990 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1991 "Dext %s does not have a DextUniqueIdentifier",
1992 dextIDCS);
1993 }
1994 return ret;
1995 }
1996
1997 void
setDextUniqueIDInPersonalities(OSDictionary * anInfoDict,OSData * dextUniqueID)1998 OSKext::setDextUniqueIDInPersonalities(
1999 OSDictionary * anInfoDict,
2000 OSData * dextUniqueID)
2001 {
2002 OSDictionary * dextPersonalities = NULL;
2003 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
2004 OSString * personalityName = NULL;
2005
2006 dextPersonalities = OSDynamicCast(OSDictionary,
2007 anInfoDict->getObject(kIOKitPersonalitiesKey));
2008 if (!dextPersonalities || !dextPersonalities->getCount()) {
2009 return;
2010 }
2011
2012 personalitiesIterator =
2013 OSCollectionIterator::withCollection(dextPersonalities);
2014 if (!personalitiesIterator) {
2015 return;
2016 }
2017 while ((personalityName = OSDynamicCast(OSString,
2018 personalitiesIterator->getNextObject()))) {
2019 OSDictionary * personality = OSDynamicCast(OSDictionary,
2020 dextPersonalities->getObject(personalityName));
2021 if (personality) {
2022 OSObject *duid = personality->getObject(kOSBundleDextUniqueIdentifierKey);
2023 if (duid == NULL) {
2024 personality->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID);
2025 }
2026 }
2027 }
2028 }
2029 /*********************************************************************
2030 *********************************************************************/
2031 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)2032 OSKext::initWithPrelinkedInfoDict(
2033 OSDictionary * anInfoDict,
2034 bool doCoalescedSlides,
2035 kc_kind_t type)
2036 {
2037 bool result = false;
2038 OSString * kextPath = NULL; // do not release
2039 OSNumber * addressNum = NULL; // reused; do not release
2040 OSNumber * lengthNum = NULL; // reused; do not release
2041 OSBoolean * scratchBool = NULL; // do not release
2042 void * data = NULL; // do not free
2043 void * srcData = NULL; // do not free
2044 OSSharedPtr<OSData> prelinkedExecutable;
2045 uint32_t length = 0; // reused
2046 uintptr_t kext_slide = PE_get_kc_slide(type);
2047 bool shouldSaveSegments = false;
2048 kc_format format = KCFormatUnknown;
2049
2050 if (!super::init()) {
2051 goto finish;
2052 }
2053
2054 /* Get the path. Don't look for an arch-specific path property.
2055 */
2056 kextPath = OSDynamicCast(OSString,
2057 anInfoDict->getObject(kPrelinkBundlePathKey));
2058
2059 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2060 goto finish;
2061 }
2062
2063 #if KASLR_KEXT_DEBUG
2064 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
2065 #endif
2066
2067 /* Also get the executable's bundle-relative path if present.
2068 * Don't look for an arch-specific path property.
2069 */
2070 executableRelPath.reset(OSDynamicCast(OSString,
2071 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
2072 userExecutableRelPath.reset(OSDynamicCast(OSString,
2073 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2074
2075 /* Don't need the paths to be in the info dictionary any more.
2076 */
2077 anInfoDict->removeObject(kPrelinkBundlePathKey);
2078 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
2079
2080 scratchBool = OSDynamicCast(OSBoolean,
2081 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2082 if (scratchBool == kOSBooleanTrue) {
2083 flags.requireExplicitLoad = 1;
2084 }
2085
2086 /* Create an OSData wrapper around the linked executable.
2087 */
2088 addressNum = OSDynamicCast(OSNumber,
2089 anInfoDict->getObject(kPrelinkExecutableLoadKey));
2090 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
2091 lengthNum = OSDynamicCast(OSNumber,
2092 anInfoDict->getObject(kPrelinkExecutableSizeKey));
2093 if (!lengthNum) {
2094 OSKextLog(this,
2095 kOSKextLogErrorLevel |
2096 kOSKextLogArchiveFlag,
2097 "Kext %s can't find prelinked kext executable size.",
2098 getIdentifierCString());
2099 return result;
2100 }
2101
2102 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2103 length = (uint32_t) (lengthNum->unsigned32BitValue());
2104
2105 #if KASLR_KEXT_DEBUG
2106 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
2107 (unsigned long)ml_static_unslide((vm_offset_t)data),
2108 (unsigned long)data,
2109 length);
2110 #endif
2111
2112 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
2113 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
2114
2115 /* If the kext's load address differs from its source address, allocate
2116 * space in the kext map at the load address and copy the kext over.
2117 */
2118 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
2119 if (addressNum) {
2120 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2121
2122 #if KASLR_KEXT_DEBUG
2123 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
2124 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
2125 (unsigned long)srcData);
2126 #endif
2127
2128 if (data != srcData) {
2129 #if __LP64__
2130 kern_return_t alloc_result;
2131
2132 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
2133 if (alloc_result != KERN_SUCCESS) {
2134 OSKextLog(this,
2135 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2136 "Failed to allocate space for prelinked kext %s.",
2137 getIdentifierCString());
2138 goto finish;
2139 }
2140 memcpy(data, srcData, length);
2141 #else
2142 OSKextLog(this,
2143 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2144 "Error: prelinked kext %s - source and load addresses "
2145 "differ on ILP32 architecture.",
2146 getIdentifierCString());
2147 goto finish;
2148 #endif /* __LP64__ */
2149 }
2150
2151 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
2152 }
2153
2154 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
2155 if (!prelinkedExecutable) {
2156 OSKextLog(this,
2157 kOSKextLogErrorLevel |
2158 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
2159 "Kext %s failed to create executable wrapper.",
2160 getIdentifierCString());
2161 goto finish;
2162 }
2163
2164 /*
2165 * Fileset KCs are mapped as a whole by iBoot.
2166 * Individual kext executables should not be unmapped
2167 * by xnu.
2168 * Doing so may result in panics like rdar://85419651
2169 */
2170 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
2171 prelinkedExecutable->setDeallocFunction(NULL);
2172 } else { // Not from a Fileset KC
2173 #if VM_MAPPED_KEXTS
2174 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
2175 #else
2176 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
2177 #endif
2178 }
2179 setLinkedExecutable(prelinkedExecutable.get());
2180 addressNum = OSDynamicCast(OSNumber,
2181 anInfoDict->getObject(kPrelinkKmodInfoKey));
2182 if (!addressNum) {
2183 OSKextLog(this,
2184 kOSKextLogErrorLevel |
2185 kOSKextLogArchiveFlag,
2186 "Kext %s can't find prelinked kext kmod_info address.",
2187 getIdentifierCString());
2188 goto finish;
2189 }
2190
2191 if (addressNum->unsigned64BitValue() != 0) {
2192 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2193 if (kmod_info->address) {
2194 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
2195 } else {
2196 kmod_info->address = (uintptr_t)data;
2197 kmod_info->size = length;
2198 }
2199 #if KASLR_KEXT_DEBUG
2200 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
2201 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
2202 (unsigned long)kmod_info);
2203 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
2204 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
2205 (unsigned long)kmod_info->address);
2206 #endif
2207 }
2208
2209 anInfoDict->removeObject(kPrelinkKmodInfoKey);
2210 }
2211
2212 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
2213 uintptr_t builtinTextStart;
2214 uintptr_t builtinTextEnd;
2215
2216 flags.builtin = true;
2217 builtinKmodIdx = addressNum->unsigned32BitValue();
2218 assert(builtinKmodIdx < gBuiltinKmodsCount);
2219
2220 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
2221 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
2222
2223 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
2224 kmod_info->address = builtinTextStart;
2225 kmod_info->size = builtinTextEnd - builtinTextStart;
2226 }
2227
2228 /* If the plist has a UUID for an interface, save that off.
2229 */
2230 if (isInterface()) {
2231 interfaceUUID.reset(OSDynamicCast(OSData,
2232 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
2233 if (interfaceUUID) {
2234 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
2235 }
2236 }
2237
2238 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
2239 if (!result) {
2240 goto finish;
2241 }
2242
2243 kc_type = type;
2244 /* Exclude builtin and codeless kexts */
2245 if (prelinkedExecutable && kmod_info) {
2246 switch (kc_type) {
2247 case KCKindPrimary:
2248 shouldSaveSegments = (
2249 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
2250 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
2251 if (shouldSaveSegments) {
2252 flags.resetSegmentsFromImmutableCopy = 1;
2253 } else {
2254 flags.unloadUnsupported = 1;
2255 }
2256 break;
2257 case KCKindPageable:
2258 flags.resetSegmentsFromVnode = 1;
2259 break;
2260 case KCKindAuxiliary:
2261 if (!pageableKCloaded) {
2262 flags.resetSegmentsFromImmutableCopy = 1;
2263 } else if (resetAuxKCSegmentOnUnload) {
2264 flags.resetSegmentsFromVnode = 1;
2265 } else {
2266 flags.unloadUnsupported = 1;
2267 }
2268 break;
2269 default:
2270 break;
2271 }
2272 }
2273
2274 if (flags.resetSegmentsFromImmutableCopy) {
2275 /* Save a pristine copy of the mutable segments */
2276 kernel_segment_command_t *seg = NULL;
2277 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
2278
2279 savedMutableSegments = OSArray::withCapacity(0);
2280
2281 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
2282 if (!segmentIsMutable(seg)) {
2283 continue;
2284 }
2285 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
2286 uint64_t vmsize = seg->vmsize;
2287 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2288 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2289 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
2290 if (!savedSegment) {
2291 OSKextLog(this,
2292 kOSKextLogErrorLevel |
2293 kOSKextLogGeneralFlag,
2294 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2295 result = false;
2296 goto finish;
2297 }
2298 savedMutableSegments->setObject(savedSegment);
2299 }
2300 }
2301
2302 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2303 /*
2304 * set VM protections now, wire pages for the old style Aux KC now,
2305 * wire pages for the rest of the KC types at load time.
2306 */
2307 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2308 if (!result) {
2309 goto finish;
2310 }
2311 }
2312
2313 flags.prelinked = true;
2314
2315 if (isDriverKit()) {
2316 dextStatistics = OSDextStatistics::create();
2317 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2318 dextLaunchedCount = 0;
2319 }
2320
2321 /* If we created a kext from prelink info,
2322 * we must be booting from a prelinked kernel.
2323 */
2324 sPrelinkBoot = true;
2325
2326 result = (registerIdentifier() == kOSKextInitialized);
2327 finish:
2328 return result;
2329 }
2330
2331 /*********************************************************************
2332 *********************************************************************/
2333 /* static */
2334 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict,OSKextInitResult * result)2335 OSKext::withCodelessInfo(OSDictionary * anInfoDict, OSKextInitResult *result)
2336 {
2337 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2338 if (!newKext) {
2339 return NULL;
2340 }
2341
2342 OSKextInitResult ret = newKext->initWithCodelessInfo(anInfoDict);
2343 if (result != NULL) {
2344 *result = ret;
2345 }
2346 if (ret != kOSKextInitialized) {
2347 return NULL;
2348 }
2349
2350 return newKext;
2351 }
2352
2353 /*********************************************************************
2354 *********************************************************************/
2355 OSKextInitResult
initWithCodelessInfo(OSDictionary * anInfoDict)2356 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2357 {
2358 OSKextInitResult result = kOSKextInitFailure;
2359 OSString * kextPath = NULL; // do not release
2360 OSBoolean * scratchBool = NULL; // do not release
2361
2362 if (anInfoDict == NULL || !super::init()) {
2363 goto finish;
2364 }
2365
2366 /*
2367 * Get the path. Don't look for an arch-specific path property.
2368 */
2369 kextPath = OSDynamicCast(OSString,
2370 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2371 if (!kextPath) {
2372 OSKextLog(NULL,
2373 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2374 "Requested codeless kext dictionary does not contain the '%s' key",
2375 kKextRequestArgumentCodelessInfoBundlePathKey);
2376 goto finish;
2377 }
2378
2379 uniquePersonalityProperties(anInfoDict);
2380
2381 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2382 goto finish;
2383 }
2384
2385 /*
2386 * This path is meant to initialize codeless kexts only. Refuse
2387 * anything that looks like it has an executable and/or declares
2388 * itself as a kernel component.
2389 */
2390 if (declaresExecutable() || isKernelComponent()) {
2391 OSKextLog(NULL,
2392 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2393 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2394 getIdentifierCString());
2395 goto finish;
2396 }
2397
2398 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2399 boolean_t updated = updateExcludeList(infoDict.get());
2400 if (updated) {
2401 OSKextLog(this,
2402 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2403 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2404 }
2405 }
2406
2407 kc_type = KCKindNone;
2408
2409 scratchBool = OSDynamicCast(OSBoolean,
2410 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2411 if (scratchBool == kOSBooleanTrue) {
2412 flags.requireExplicitLoad = 1;
2413 }
2414
2415 /* Also get the executable's bundle-relative path if present.
2416 * Don't look for an arch-specific path property.
2417 */
2418 userExecutableRelPath.reset(OSDynamicCast(OSString,
2419 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2420
2421 /* remove unnecessary paths from the info dict */
2422 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2423
2424 if (isDriverKit()) {
2425 dextStatistics = OSDextStatistics::create();
2426 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2427 dextLaunchedCount = 0;
2428 }
2429
2430 result = registerIdentifier();
2431
2432 finish:
2433 return result;
2434 }
2435
2436 /*********************************************************************
2437 *********************************************************************/
2438 /* static */
2439 void
setAllVMAttributes(void)2440 OSKext::setAllVMAttributes(void)
2441 {
2442 OSSharedPtr<OSCollectionIterator> kextIterator;
2443 const OSSymbol * thisID = NULL; // do not release
2444
2445 IORecursiveLockLock(sKextLock);
2446
2447 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2448 if (!kextIterator) {
2449 goto finish;
2450 }
2451
2452 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2453 OSKext * thisKext; // do not release
2454
2455 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2456 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2457 continue;
2458 }
2459
2460 if (!thisKext->flags.resetSegmentsFromVnode) {
2461 /*
2462 * set VM protections now, wire pages for the old style Aux KC now,
2463 * wire pages for the rest of the KC types at load time.
2464 */
2465 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2466 }
2467 }
2468
2469 finish:
2470 IORecursiveLockUnlock(sKextLock);
2471
2472 return;
2473 }
2474
2475 /*********************************************************************
2476 *********************************************************************/
2477 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2478 OSKext::withBooterData(
2479 OSString * deviceTreeName,
2480 OSData * booterData)
2481 {
2482 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2483
2484 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2485 return NULL;
2486 }
2487
2488 return newKext;
2489 }
2490
2491 /*********************************************************************
2492 *********************************************************************/
2493 typedef struct _BooterKextFileInfo {
2494 uint32_t infoDictPhysAddr;
2495 uint32_t infoDictLength;
2496 uint32_t executablePhysAddr;
2497 uint32_t executableLength;
2498 uint32_t bundlePathPhysAddr;
2499 uint32_t bundlePathLength;
2500 } _BooterKextFileInfo;
2501
2502 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2503 OSKext::initWithBooterData(
2504 OSString * deviceTreeName,
2505 OSData * booterData)
2506 {
2507 bool result = false;
2508 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2509 char * infoDictAddr = NULL; // do not free
2510 void * executableAddr = NULL; // do not free
2511 char * bundlePathAddr = NULL; // do not free
2512
2513 OSDictionary * theInfoDict = NULL; // do not release
2514 OSSharedPtr<OSObject> parsedXML;
2515 OSSharedPtr<OSString> kextPath;
2516
2517 OSSharedPtr<OSString> errorString;
2518 OSSharedPtr<OSData> executable;
2519
2520 if (!super::init()) {
2521 goto finish;
2522 }
2523
2524 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2525 if (!kextFileInfo) {
2526 OSKextLog(this,
2527 kOSKextLogErrorLevel |
2528 kOSKextLogGeneralFlag,
2529 "No booter-provided data for kext device tree entry %s.",
2530 deviceTreeName->getCStringNoCopy());
2531 goto finish;
2532 }
2533
2534 /* The info plist must exist or we can't read the kext.
2535 */
2536 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2537 OSKextLog(this,
2538 kOSKextLogErrorLevel |
2539 kOSKextLogGeneralFlag,
2540 "No kext info dictionary for booter device tree entry %s.",
2541 deviceTreeName->getCStringNoCopy());
2542 goto finish;
2543 }
2544
2545 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2546 if (!infoDictAddr) {
2547 OSKextLog(this,
2548 kOSKextLogErrorLevel |
2549 kOSKextLogGeneralFlag,
2550 "Can't translate physical address 0x%x of kext info dictionary "
2551 "for device tree entry %s.",
2552 (int)kextFileInfo->infoDictPhysAddr,
2553 deviceTreeName->getCStringNoCopy());
2554 goto finish;
2555 }
2556
2557 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2558 if (parsedXML) {
2559 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2560 }
2561 if (!theInfoDict) {
2562 const char * errorCString = "(unknown error)";
2563
2564 if (errorString && errorString->getCStringNoCopy()) {
2565 errorCString = errorString->getCStringNoCopy();
2566 } else if (parsedXML) {
2567 errorCString = "not a dictionary";
2568 }
2569 OSKextLog(this,
2570 kOSKextLogErrorLevel |
2571 kOSKextLogGeneralFlag,
2572 "Error unserializing info dictionary for device tree entry %s: %s.",
2573 deviceTreeName->getCStringNoCopy(), errorCString);
2574 goto finish;
2575 }
2576
2577 /* A bundle path is not mandatory.
2578 */
2579 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2580 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2581 if (!bundlePathAddr) {
2582 OSKextLog(this,
2583 kOSKextLogErrorLevel |
2584 kOSKextLogGeneralFlag,
2585 "Can't translate physical address 0x%x of kext bundle path "
2586 "for device tree entry %s.",
2587 (int)kextFileInfo->bundlePathPhysAddr,
2588 deviceTreeName->getCStringNoCopy());
2589 goto finish;
2590 }
2591 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2592
2593 kextPath = OSString::withCString(bundlePathAddr);
2594 if (!kextPath) {
2595 OSKextLog(this,
2596 kOSKextLogErrorLevel |
2597 kOSKextLogGeneralFlag,
2598 "Failed to create wrapper for device tree entry %s kext path %s.",
2599 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2600 goto finish;
2601 }
2602 }
2603
2604 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2605 goto finish;
2606 }
2607
2608 /* An executable is not mandatory.
2609 */
2610 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2611 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2612 if (!executableAddr) {
2613 OSKextLog(this,
2614 kOSKextLogErrorLevel |
2615 kOSKextLogGeneralFlag,
2616 "Can't translate physical address 0x%x of kext executable "
2617 "for device tree entry %s.",
2618 (int)kextFileInfo->executablePhysAddr,
2619 deviceTreeName->getCStringNoCopy());
2620 goto finish;
2621 }
2622
2623 executable = OSData::withBytesNoCopy(executableAddr,
2624 kextFileInfo->executableLength);
2625 if (!executable) {
2626 OSKextLog(this,
2627 kOSKextLogErrorLevel |
2628 kOSKextLogGeneralFlag,
2629 "Failed to create executable wrapper for device tree entry %s.",
2630 deviceTreeName->getCStringNoCopy());
2631 goto finish;
2632 }
2633
2634 /* A kext with an executable needs to retain the whole booterData
2635 * object to keep the executable in memory.
2636 */
2637 if (!setExecutable(executable.get(), booterData)) {
2638 OSKextLog(this,
2639 kOSKextLogErrorLevel |
2640 kOSKextLogGeneralFlag,
2641 "Failed to set kext executable for device tree entry %s.",
2642 deviceTreeName->getCStringNoCopy());
2643 goto finish;
2644 }
2645 }
2646
2647 if (isDriverKit()) {
2648 dextStatistics = OSDextStatistics::create();
2649 dextUniqueID.reset(parseDextUniqueID(theInfoDict, getIdentifierCString()), OSRetain);
2650 dextLaunchedCount = 0;
2651 }
2652
2653 result = (registerIdentifier() == kOSKextInitialized);
2654
2655 finish:
2656 return result;
2657 }
2658
2659 /*********************************************************************
2660 *********************************************************************/
2661 OSKextInitResult
registerIdentifier(void)2662 OSKext::registerIdentifier(void)
2663 {
2664 OSKextInitResult result = kOSKextInitFailure;
2665 OSKext * existingKext = NULL; // do not release
2666 bool existingIsLoaded = false;
2667 bool existingIsPrelinked = false;
2668 bool existingIsCodeless = false;
2669 bool existingIsDext = false;
2670 OSKextVersion newVersion = -1;
2671 OSKextVersion existingVersion = -1;
2672 char newVersionCString[kOSKextVersionMaxLength];
2673 char existingVersionCString[kOSKextVersionMaxLength];
2674 OSSharedPtr<OSData> newUUID;
2675 OSSharedPtr<OSData> existingUUID;
2676 const char *newDextUniqueIDCString = NULL;
2677 const char *existingDextUniqueIDCString = NULL;
2678 unsigned int newDextUniqueIDCStringSize = 0;
2679 unsigned int existingDextUniqueIDCStringSize = 0;
2680
2681 IORecursiveLockLock(sKextLock);
2682
2683 /* Get the new kext's version for checks & log messages.
2684 */
2685 newVersion = getVersion();
2686 OSKextVersionGetString(newVersion, newVersionCString,
2687 kOSKextVersionMaxLength);
2688
2689 /* If we don't have an existing kext with this identifier,
2690 * just record the new kext and we're done!
2691 */
2692 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2693 if (!existingKext) {
2694 sKextsByID->setObject(bundleID.get(), this);
2695 result = kOSKextInitialized;
2696 goto finish;
2697 }
2698
2699 /* Get the existing kext's version for checks & log messages.
2700 */
2701 existingVersion = existingKext->getVersion();
2702 OSKextVersionGetString(existingVersion,
2703 existingVersionCString, kOSKextVersionMaxLength);
2704
2705 existingIsLoaded = existingKext->isLoaded();
2706 existingIsPrelinked = existingKext->isPrelinked();
2707 existingIsDext = existingKext->isDriverKit();
2708 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2709
2710 /*
2711 * Check if we are trying to upgrade a dext
2712 * with another dext.
2713 */
2714 if (isDriverKit() && existingIsDext) {
2715 OSData *newDextUID = getDextUniqueID();
2716 if (!newDextUID) {
2717 OSKextLog(this,
2718 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2719 "New dext %s, v%s requested does not have a unique dext identifier\n",
2720 getIdentifierCString(), newVersionCString);
2721 goto finish;
2722 }
2723 newDextUniqueIDCString = getDextUniqueIDCString(newDextUID, &newDextUniqueIDCStringSize);
2724 assert(newDextUniqueIDCString != NULL);
2725
2726 OSData *existingDextUID = existingKext->getDextUniqueID();
2727 if (!existingDextUID) {
2728 OSKextLog(this,
2729 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2730 "Found a dext %s, v%s: with no unique dext identifier\n",
2731 existingKext->getIdentifierCString(), existingVersionCString);
2732 goto finish;
2733 }
2734 existingDextUniqueIDCString = getDextUniqueIDCString(existingDextUID, &existingDextUniqueIDCStringSize);
2735 assert(existingDextUniqueIDCString != NULL);
2736
2737 /*
2738 * We might get multiple requests to save the same dext.
2739 * Check if we already have saved it or if this is an upgrade
2740 * for a dext with the same BundleID.
2741 * Dexts are uniquely identified by DextUniqueID, if a new DextUniqueID
2742 * is requested for a BundleID we are going to upgrade to the newest
2743 * received irrespective from the dext version.
2744 */
2745 if (newDextUID->isEqualTo(existingDextUID) && existingKext->flags.dextToReplace == 0) {
2746 OSKextLog(this,
2747 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2748 "Refusing new dext %s, v%s:"
2749 "a dext v %s with the same unique dext identifier (%s) already exists\n",
2750 getIdentifierCString(), newVersionCString,
2751 existingVersionCString, newDextUniqueIDCString);
2752 result = kOSKextAlreadyExist;
2753 goto finish;
2754 }
2755
2756 bool upgraded = upgradeDext(existingKext, this);
2757 if (upgraded) {
2758 /* If the dext was upgraded existingKext might have been deallocated */
2759 existingKext = NULL;
2760 OSKextLog(this,
2761 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2762 "Dext %s, v%s , unique dext identifier %s "
2763 "Upgraded to v%s, unique dext identifier %s \n",
2764 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2765 newVersionCString, newDextUniqueIDCString);
2766 result = kOSKextInitialized;
2767 } else {
2768 OSKextLog(this,
2769 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2770 "Upgrade delayed for %s v%s, unique dext identifier %s "
2771 "with v%s, unique dext identifier %s.\n",
2772 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2773 newVersionCString, newDextUniqueIDCString);
2774 result = kOSKextAlreadyExist;
2775 }
2776
2777 goto finish;
2778 }
2779
2780 /* If we have a non-codeless kext with this identifier that's already
2781 * loaded/prelinked, we can't use the new one, but let's be really
2782 * thorough and check how the two are related for a precise diagnostic
2783 * log message.
2784 *
2785 * This check is valid for kexts that declare an executable and for
2786 * dexts, but not for codeless kexts - we can just replace those.
2787 */
2788 if ((!existingIsCodeless || existingIsDext) &&
2789 (existingIsLoaded || existingIsPrelinked)) {
2790 bool sameVersion = (newVersion == existingVersion);
2791 bool sameExecutable = true; // assume true unless we have UUIDs
2792
2793 /* Only get the UUID if the existing kext is loaded. Doing so
2794 * might have to uncompress an mkext executable and we shouldn't
2795 * take that hit when neither kext is loaded.
2796 *
2797 * Note: there is no decompression that happens when all kexts
2798 * are loaded from kext collecitons.
2799 */
2800 newUUID = copyUUID();
2801 existingUUID = existingKext->copyUUID();
2802
2803 if (existingIsDext && !isDriverKit()) {
2804 OSKextLog(this,
2805 kOSKextLogWarningLevel |
2806 kOSKextLogKextBookkeepingFlag,
2807 "Notice - new kext %s, v%s matches a %s dext"
2808 "with the same bundle ID, v%s.",
2809 getIdentifierCString(), newVersionCString,
2810 (existingIsLoaded ? "loaded" : "prelinked"),
2811 existingVersionCString);
2812 goto finish;
2813 }
2814
2815 /* I'm entirely too paranoid about checking equivalence of executables,
2816 * but I remember nasty problems with it in the past.
2817 *
2818 * - If we have UUIDs for both kexts, compare them.
2819 * - If only one kext has a UUID, they're definitely different.
2820 */
2821 if (newUUID && existingUUID) {
2822 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2823 } else if (newUUID || existingUUID) {
2824 sameExecutable = false;
2825 }
2826
2827 if (!newUUID && !existingUUID) {
2828 /* If there are no UUIDs, we can't really tell that the executables
2829 * are *different* without a lot of work; the loaded kext's
2830 * unrelocated executable is no longer around (and we never had it
2831 * in-kernel for a prelinked kext). We certainly don't want to do
2832 * a whole fake link for the new kext just to compare, either.
2833 */
2834 OSKextLog(this,
2835 kOSKextLogWarningLevel |
2836 kOSKextLogKextBookkeepingFlag,
2837 "Notice - new kext %s, v%s matches %s kext "
2838 "but can't determine if executables are the same (no UUIDs).",
2839 getIdentifierCString(),
2840 newVersionCString,
2841 (existingIsLoaded ? "loaded" : "prelinked"));
2842 }
2843
2844 if (sameVersion && sameExecutable) {
2845 OSKextLog(this,
2846 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2847 kOSKextLogKextBookkeepingFlag,
2848 "Refusing new kext %s, v%s: a %s copy is already present "
2849 "(same version and executable).",
2850 getIdentifierCString(), newVersionCString,
2851 (existingIsLoaded ? "loaded" : "prelinked"));
2852 } else {
2853 if (!sameVersion) {
2854 /* This condition is significant so log it under warnings.
2855 */
2856 OSKextLog(this,
2857 kOSKextLogWarningLevel |
2858 kOSKextLogKextBookkeepingFlag,
2859 "Refusing new kext %s, v%s: already have %s v%s.",
2860 getIdentifierCString(),
2861 newVersionCString,
2862 (existingIsLoaded ? "loaded" : "prelinked"),
2863 existingVersionCString);
2864 } else {
2865 /* This condition is significant so log it under warnings.
2866 */
2867 OSKextLog(this,
2868 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2869 "Refusing new kext %s, v%s: a %s copy with a different "
2870 "executable UUID is already present.",
2871 getIdentifierCString(), newVersionCString,
2872 (existingIsLoaded ? "loaded" : "prelinked"));
2873 }
2874 }
2875 goto finish;
2876 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2877
2878 /* Refuse to allow an existing loaded codeless kext be replaced by a
2879 * normal kext with the same bundle ID.
2880 */
2881 if (existingIsCodeless && declaresExecutable()) {
2882 OSKextLog(this,
2883 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2884 "Refusing new kext %s, v%s: a codeless copy is already %s",
2885 getIdentifierCString(), newVersionCString,
2886 (existingIsLoaded ? "loaded" : "prelinked"));
2887 goto finish;
2888 }
2889
2890 /* Dexts packaged in the BootKC will be protected against replacement
2891 * by non-dexts by the logic above which checks if they are prelinked.
2892 * Dexts which are prelinked into the System KC will be registered
2893 * before any other kexts in the AuxKC are registered, and we never
2894 * put dexts in the AuxKC. Therefore, there is no need to check if an
2895 * existing object is a dext and is being replaced by a non-dext.
2896 * The scenario cannot happen by construction.
2897 *
2898 * See: OSKext::loadFileSetKexts()
2899 */
2900
2901
2902 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2903 * user loads are happening or if we're still in early boot. User agents are
2904 * supposed to resolve dependencies topside and include only the exact
2905 * kexts needed; so we always accept the new kext (in fact we should never
2906 * see an older unloaded copy hanging around).
2907 */
2908 if (sUserLoadsActive) {
2909 sKextsByID->setObject(bundleID.get(), this);
2910 result = kOSKextInitialized;
2911
2912 OSKextLog(this,
2913 kOSKextLogStepLevel |
2914 kOSKextLogKextBookkeepingFlag,
2915 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2916 getIdentifierCString(),
2917 existingVersionCString,
2918 newVersionCString);
2919
2920 goto finish;
2921 }
2922
2923 /* During early boot, the kext with the highest version always wins out.
2924 * Prelinked kernels will never hit this, but mkexts and booter-read
2925 * kexts might have duplicates.
2926 */
2927 if (newVersion > existingVersion) {
2928 sKextsByID->setObject(bundleID.get(), this);
2929 result = kOSKextInitialized;
2930
2931 OSKextLog(this,
2932 kOSKextLogStepLevel |
2933 kOSKextLogKextBookkeepingFlag,
2934 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2935 existingVersionCString,
2936 getIdentifierCString(),
2937 newVersionCString);
2938 } else {
2939 OSKextLog(this,
2940 kOSKextLogStepLevel |
2941 kOSKextLogKextBookkeepingFlag,
2942 "Kext %s is already registered with a higher/same version (v%s); "
2943 "dropping newly-added (v%s).",
2944 getIdentifierCString(),
2945 existingVersionCString,
2946 newVersionCString);
2947 }
2948
2949 /* result has been set appropriately by now. */
2950
2951 finish:
2952
2953 IORecursiveLockUnlock(sKextLock);
2954
2955 if (newDextUniqueIDCString != NULL) {
2956 kfree_data(newDextUniqueIDCString, newDextUniqueIDCStringSize);
2957 }
2958 if (existingDextUniqueIDCString != NULL) {
2959 kfree_data(existingDextUniqueIDCString, existingDextUniqueIDCStringSize);
2960 }
2961
2962 if (result == kOSKextInitialized) {
2963 OSKextLog(this,
2964 kOSKextLogStepLevel |
2965 kOSKextLogKextBookkeepingFlag,
2966 "Kext %s, v%s registered and available for loading.",
2967 getIdentifierCString(), newVersionCString);
2968 }
2969
2970 return result;
2971 }
2972
2973 /*********************************************************************
2974 * Does the bare minimum validation to look up a kext.
2975 * All other validation is done on the spot as needed.
2976 **********************************************************************/
2977 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)2978 OSKext::setInfoDictionaryAndPath(
2979 OSDictionary * aDictionary,
2980 OSString * aPath)
2981 {
2982 bool result = false;
2983 OSString * bundleIDString = NULL; // do not release
2984 OSString * versionString = NULL; // do not release
2985 OSString * compatibleVersionString = NULL; // do not release
2986 const char * versionCString = NULL; // do not free
2987 const char * compatibleVersionCString = NULL; // do not free
2988 OSBoolean * scratchBool = NULL; // do not release
2989 OSDictionary * scratchDict = NULL; // do not release
2990
2991 if (infoDict) {
2992 panic("Attempt to set info dictionary on a kext "
2993 "that already has one (%s).",
2994 getIdentifierCString());
2995 }
2996
2997 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2998 goto finish;
2999 }
3000
3001 infoDict.reset(aDictionary, OSRetain);
3002
3003 /* Check right away if the info dictionary has any log flags.
3004 */
3005 scratchBool = OSDynamicCast(OSBoolean,
3006 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
3007 if (scratchBool == kOSBooleanTrue) {
3008 flags.loggingEnabled = 1;
3009 }
3010
3011 /* The very next thing to get is the bundle identifier. Unlike
3012 * in user space, a kext with no bundle identifier gets axed
3013 * immediately.
3014 */
3015 bundleIDString = OSDynamicCast(OSString,
3016 getPropertyForHostArch(kCFBundleIdentifierKey));
3017 if (!bundleIDString) {
3018 OSKextLog(this,
3019 kOSKextLogErrorLevel |
3020 kOSKextLogValidationFlag,
3021 "CFBundleIdentifier missing/invalid type in kext %s.",
3022 aPath ? aPath->getCStringNoCopy() : "(unknown)");
3023 goto finish;
3024 }
3025 bundleID = OSSymbol::withString(bundleIDString);
3026 if (!bundleID) {
3027 OSKextLog(this,
3028 kOSKextLogErrorLevel |
3029 kOSKextLogValidationFlag,
3030 "Can't copy bundle identifier as symbol for kext %s.",
3031 bundleIDString->getCStringNoCopy());
3032 goto finish;
3033 }
3034
3035 /* Save the path if we got one (it should always be available but it's
3036 * just something nice to have for bookkeeping).
3037 */
3038 if (aPath) {
3039 path.reset(aPath, OSRetain);
3040 }
3041
3042 /*****
3043 * Minimal validation to initialize. We'll do other validation on the spot.
3044 */
3045 if (bundleID->getLength() >= KMOD_MAX_NAME) {
3046 OSKextLog(this,
3047 kOSKextLogErrorLevel |
3048 kOSKextLogValidationFlag,
3049 "Kext %s error - CFBundleIdentifier over max length %d.",
3050 getIdentifierCString(), KMOD_MAX_NAME - 1);
3051 goto finish;
3052 }
3053
3054 version = compatibleVersion = -1;
3055
3056 versionString = OSDynamicCast(OSString,
3057 getPropertyForHostArch(kCFBundleVersionKey));
3058 if (!versionString) {
3059 OSKextLog(this,
3060 kOSKextLogErrorLevel |
3061 kOSKextLogValidationFlag,
3062 "Kext %s error - CFBundleVersion missing/invalid type.",
3063 getIdentifierCString());
3064 goto finish;
3065 }
3066 versionCString = versionString->getCStringNoCopy();
3067 version = OSKextParseVersionString(versionCString);
3068 if (version < 0) {
3069 OSKextLog(this,
3070 kOSKextLogErrorLevel |
3071 kOSKextLogValidationFlag,
3072 "Kext %s error - CFBundleVersion bad value '%s'.",
3073 getIdentifierCString(), versionCString);
3074 goto finish;
3075 }
3076
3077 compatibleVersion = -1; // set to illegal value for kexts that don't have
3078
3079 compatibleVersionString = OSDynamicCast(OSString,
3080 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
3081 if (compatibleVersionString) {
3082 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
3083 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
3084 if (compatibleVersion < 0) {
3085 OSKextLog(this,
3086 kOSKextLogErrorLevel |
3087 kOSKextLogValidationFlag,
3088 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
3089 getIdentifierCString(), compatibleVersionCString);
3090 goto finish;
3091 }
3092
3093 if (compatibleVersion > version) {
3094 OSKextLog(this,
3095 kOSKextLogErrorLevel |
3096 kOSKextLogValidationFlag,
3097 "Kext %s error - %s %s > %s %s (must be <=).",
3098 getIdentifierCString(),
3099 kOSBundleCompatibleVersionKey, compatibleVersionCString,
3100 kCFBundleVersionKey, versionCString);
3101 goto finish;
3102 }
3103 }
3104
3105 /* Check to see if this kext is in exclude list */
3106 if (isInExcludeList()) {
3107 OSKextLog(this,
3108 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3109 "Kext %s is in exclude list, not loadable",
3110 getIdentifierCString());
3111 goto finish;
3112 }
3113
3114 /* Set flags for later use if the infoDict gets flushed. We only
3115 * check for true values, not false ones(!)
3116 */
3117 scratchBool = OSDynamicCast(OSBoolean,
3118 getPropertyForHostArch(kOSBundleIsInterfaceKey));
3119 if (scratchBool == kOSBooleanTrue) {
3120 flags.interface = 1;
3121 }
3122
3123 scratchBool = OSDynamicCast(OSBoolean,
3124 getPropertyForHostArch(kOSKernelResourceKey));
3125 if (scratchBool == kOSBooleanTrue) {
3126 flags.kernelComponent = 1;
3127 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
3128 flags.started = 1;
3129
3130 /* A kernel component has one implicit dependency on the kernel.
3131 */
3132 flags.hasAllDependencies = 1;
3133 }
3134
3135 /* Make sure common string values in personalities are uniqued to OSSymbols.
3136 */
3137 scratchDict = OSDynamicCast(OSDictionary,
3138 getPropertyForHostArch(kIOKitPersonalitiesKey));
3139 if (scratchDict) {
3140 uniquePersonalityProperties(scratchDict);
3141 }
3142
3143 result = true;
3144
3145 finish:
3146
3147 return result;
3148 }
3149
3150 /*********************************************************************
3151 * Not used for prelinked kernel boot as there is no unrelocated
3152 * executable.
3153 *********************************************************************/
3154 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)3155 OSKext::setExecutable(
3156 OSData * anExecutable,
3157 OSData * externalData,
3158 bool externalDataIsMkext)
3159 {
3160 bool result = false;
3161 const char * executableKey = NULL; // do not free
3162
3163 if (!anExecutable) {
3164 infoDict->removeObject(_kOSKextExecutableKey);
3165 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3166 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3167 result = true;
3168 goto finish;
3169 }
3170
3171 if (infoDict->getObject(_kOSKextExecutableKey) ||
3172 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
3173 panic("Attempt to set an executable on a kext "
3174 "that already has one (%s).",
3175 getIdentifierCString());
3176 goto finish;
3177 }
3178
3179 if (externalDataIsMkext) {
3180 executableKey = _kOSKextMkextExecutableReferenceKey;
3181 } else {
3182 executableKey = _kOSKextExecutableKey;
3183 }
3184
3185 if (anExecutable) {
3186 infoDict->setObject(executableKey, anExecutable);
3187 if (externalData) {
3188 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
3189 }
3190 }
3191
3192 result = true;
3193
3194 finish:
3195 return result;
3196 }
3197
3198 /*********************************************************************
3199 *********************************************************************/
3200 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)3201 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
3202 {
3203 OSObject * value = NULL; // do not release
3204 OSString * stringValue = NULL; // do not release
3205 OSSharedPtr<const OSSymbol> symbolValue;
3206
3207 value = dict->getObject(key);
3208 if (!value) {
3209 goto finish;
3210 }
3211 if (OSDynamicCast(OSSymbol, value)) {
3212 /* this is already an OSSymbol: we're good */
3213 goto finish;
3214 }
3215
3216 stringValue = OSDynamicCast(OSString, value);
3217 if (!stringValue) {
3218 goto finish;
3219 }
3220
3221 symbolValue = OSSymbol::withString(stringValue);
3222 if (!symbolValue) {
3223 goto finish;
3224 }
3225
3226 dict->setObject(key, symbolValue.get());
3227
3228 finish:
3229 return;
3230 }
3231
3232 /*********************************************************************
3233 *********************************************************************/
3234 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)3235 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
3236 {
3237 OSObject * value = NULL; // do not release
3238 OSString * stringValue = NULL; // do not release
3239 OSSharedPtr<const OSSymbol> symbolValue;
3240
3241 value = dict->getObject(key);
3242 if (!value) {
3243 goto finish;
3244 }
3245 if (OSDynamicCast(OSSymbol, value)) {
3246 /* this is already an OSSymbol: we're good */
3247 goto finish;
3248 }
3249
3250 stringValue = OSDynamicCast(OSString, value);
3251 if (!stringValue) {
3252 goto finish;
3253 }
3254
3255 symbolValue = OSSymbol::withString(stringValue);
3256 if (!symbolValue) {
3257 goto finish;
3258 }
3259
3260 dict->setObject(key, symbolValue.get());
3261
3262 finish:
3263 return;
3264 }
3265
3266 void
uniquePersonalityProperties(OSDictionary * personalityDict)3267 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
3268 {
3269 OSKext::uniquePersonalityProperties(personalityDict, true);
3270 }
3271
3272 /*********************************************************************
3273 * Replace common personality property values with uniqued instances
3274 * to save on wired memory.
3275 *********************************************************************/
3276 /* static */
3277 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)3278 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
3279 {
3280 /* Properties every personality has.
3281 */
3282 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
3283 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
3284 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
3285 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
3286 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
3287 } else if (defaultAddKernelBundleIdentifier) {
3288 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
3289 }
3290
3291 /* Other commonly used properties.
3292 */
3293 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
3294 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
3295 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
3296
3297 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
3298 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
3299 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
3300 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
3301 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
3302 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
3303 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
3304 uniqueStringPlistProperty(personalityDict, "Vendor");
3305 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
3306 uniqueStringPlistProperty(personalityDict, "Vendor Name");
3307 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
3308 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
3309 uniqueStringPlistProperty(personalityDict, "idProduct");
3310
3311 return;
3312 }
3313
3314 /*********************************************************************
3315 *********************************************************************/
3316 void
free(void)3317 OSKext::free(void)
3318 {
3319 if (isLoaded()) {
3320 panic("Attempt to free loaded kext %s.", getIdentifierCString());
3321 }
3322
3323 if (isDriverKit()) {
3324 if (dextLaunchedCount > 0) {
3325 panic("Freeing dext %s but dextLaunchedCount is %d\n", getIdentifierCString(), dextLaunchedCount);
3326 }
3327 }
3328
3329 infoDict.reset();
3330 bundleID.reset();
3331 path.reset();
3332 executableRelPath.reset();
3333 userExecutableRelPath.reset();
3334 dependencies.reset();
3335 linkedExecutable.reset();
3336 metaClasses.reset();
3337 interfaceUUID.reset();
3338 driverKitUUID.reset();
3339 dextStatistics.reset();
3340 dextUniqueID.reset();
3341
3342 if (isInterface() && kmod_info) {
3343 kfree_type(kmod_info_t, kmod_info);
3344 }
3345
3346 super::free();
3347 return;
3348 }
3349
3350 #if PRAGMA_MARK
3351 #pragma mark Mkext files
3352 #endif
3353
3354 #if CONFIG_KXLD
3355 /*
3356 * mkext archives are really only relevant on kxld-enabled kernels.
3357 * Without a dynamic kernel linker, we don't need to support any mkexts.
3358 */
3359
3360 /*********************************************************************
3361 *********************************************************************/
3362 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)3363 OSKext::readMkextArchive(OSData * mkextData,
3364 uint32_t * checksumPtr)
3365 {
3366 OSReturn result = kOSKextReturnBadData;
3367 uint32_t mkextLength = 0;
3368 mkext_header * mkextHeader = NULL; // do not free
3369 uint32_t mkextVersion = 0;
3370
3371 /* Note default return of kOSKextReturnBadData above.
3372 */
3373 mkextLength = mkextData->getLength();
3374 if (mkextLength < sizeof(mkext_basic_header)) {
3375 OSKextLog(/* kext */ NULL,
3376 kOSKextLogErrorLevel |
3377 kOSKextLogArchiveFlag,
3378 "Mkext archive too small to be valid.");
3379 goto finish;
3380 }
3381
3382 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
3383
3384 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
3385 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
3386 OSKextLog(/* kext */ NULL,
3387 kOSKextLogErrorLevel |
3388 kOSKextLogArchiveFlag,
3389 "Mkext archive has invalid magic or signature.");
3390 goto finish;
3391 }
3392
3393 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
3394 OSKextLog(/* kext */ NULL,
3395 kOSKextLogErrorLevel |
3396 kOSKextLogArchiveFlag,
3397 "Mkext archive recorded length doesn't match actual file length.");
3398 goto finish;
3399 }
3400
3401 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3402
3403 if (mkextVersion == MKEXT_VERS_2) {
3404 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
3405 } else {
3406 OSKextLog(/* kext */ NULL,
3407 kOSKextLogErrorLevel |
3408 kOSKextLogArchiveFlag,
3409 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3410 result = kOSKextReturnUnsupported;
3411 }
3412
3413 finish:
3414 return result;
3415 }
3416
3417 /*********************************************************************
3418 * Assumes magic, signature, version, length have been checked.
3419 * xxx - need to add further bounds checking for each file entry
3420 *
3421 * Should keep track of all kexts created so far, and if we hit a
3422 * fatal error halfway through, remove those kexts. If we've dropped
3423 * an older version that had already been read, whoops! Might want to
3424 * add a level of buffering?
3425 *********************************************************************/
3426 /* static */
3427 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3428 OSKext::readMkext2Archive(
3429 OSData * mkextData,
3430 OSDictionary ** mkextPlistOut,
3431 uint32_t * checksumPtr)
3432 {
3433 OSReturn result = kOSReturnError;
3434 uint32_t mkextLength;
3435 mkext2_header * mkextHeader = NULL; // do not free
3436 void * mkextEnd = NULL; // do not free
3437 uint32_t mkextVersion;
3438 uint8_t * crc_address = NULL;
3439 size_t crc_buffer_size = 0;
3440 uint32_t checksum;
3441 uint32_t mkextPlistOffset;
3442 uint32_t mkextPlistCompressedSize;
3443 char * mkextPlistEnd = NULL; // do not free
3444 uint32_t mkextPlistFullSize;
3445 OSSharedPtr<OSString> errorString;
3446 OSSharedPtr<OSData> mkextPlistUncompressedData;
3447 const char * mkextPlistDataBuffer = NULL; // do not free
3448 OSSharedPtr<OSObject> parsedXML;
3449 OSDictionary * mkextPlist = NULL; // do not release
3450 OSArray * mkextInfoDictArray = NULL; // do not release
3451 uint32_t count, i;
3452 kc_format_t kc_format;
3453
3454 if (!PE_get_primary_kc_format(&kc_format)) {
3455 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3456 "Unable to determine primary KC format");
3457 goto finish;
3458 }
3459
3460 mkextLength = mkextData->getLength();
3461 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3462 mkextEnd = (char *)mkextHeader + mkextLength;
3463 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3464
3465 crc_address = (u_int8_t *)&mkextHeader->version;
3466 crc_buffer_size = (uintptr_t)mkextHeader +
3467 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3468 if (crc_buffer_size > INT32_MAX) {
3469 OSKextLog(/* kext */ NULL,
3470 kOSKextLogErrorLevel |
3471 kOSKextLogArchiveFlag,
3472 "Mkext archive size is too large (%lu > INT32_MAX).",
3473 crc_buffer_size);
3474 result = kOSKextReturnBadData;
3475 goto finish;
3476 }
3477 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3478
3479 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3480 OSKextLog(/* kext */ NULL,
3481 kOSKextLogErrorLevel |
3482 kOSKextLogArchiveFlag,
3483 "Mkext archive has bad checksum.");
3484 result = kOSKextReturnBadData;
3485 goto finish;
3486 }
3487
3488 if (checksumPtr) {
3489 *checksumPtr = checksum;
3490 }
3491
3492 /* Check that the CPU type & subtype match that of the running kernel. */
3493 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3494 OSKextLog(/* kext */ NULL,
3495 kOSKextLogErrorLevel |
3496 kOSKextLogArchiveFlag,
3497 "Mkext archive must have a specific CPU type.");
3498 result = kOSKextReturnBadData;
3499 goto finish;
3500 } else {
3501 if ((UInt32)_mh_execute_header.cputype !=
3502 MKEXT_GET_CPUTYPE(mkextHeader)) {
3503 OSKextLog(/* kext */ NULL,
3504 kOSKextLogErrorLevel |
3505 kOSKextLogArchiveFlag,
3506 "Mkext archive does not match the running kernel's CPU type.");
3507 result = kOSKextReturnArchNotFound;
3508 goto finish;
3509 }
3510 }
3511
3512 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3513 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3514 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3515 mkextPlistCompressedSize;
3516 if (mkextPlistEnd > mkextEnd) {
3517 OSKextLog(/* kext */ NULL,
3518 kOSKextLogErrorLevel |
3519 kOSKextLogArchiveFlag,
3520 "Mkext archive file overrun.");
3521 result = kOSKextReturnBadData;
3522 }
3523
3524 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3525 if (mkextPlistCompressedSize) {
3526 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3527 (UInt8 *)mkextHeader + mkextPlistOffset,
3528 "plist",
3529 mkextPlistCompressedSize, mkextPlistFullSize);
3530 if (!mkextPlistUncompressedData) {
3531 goto finish;
3532 }
3533 mkextPlistDataBuffer = (const char *)
3534 mkextPlistUncompressedData->getBytesNoCopy();
3535 } else {
3536 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3537 }
3538
3539 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3540 */
3541 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3542 if (parsedXML) {
3543 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3544 }
3545 if (!mkextPlist) {
3546 const char * errorCString = "(unknown error)";
3547
3548 if (errorString && errorString->getCStringNoCopy()) {
3549 errorCString = errorString->getCStringNoCopy();
3550 } else if (parsedXML) {
3551 errorCString = "not a dictionary";
3552 }
3553 OSKextLog(/* kext */ NULL,
3554 kOSKextLogErrorLevel |
3555 kOSKextLogArchiveFlag,
3556 "Error unserializing mkext plist: %s.", errorCString);
3557 goto finish;
3558 }
3559
3560 mkextInfoDictArray = OSDynamicCast(OSArray,
3561 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3562 if (!mkextInfoDictArray) {
3563 OSKextLog(/* kext */ NULL,
3564 kOSKextLogErrorLevel |
3565 kOSKextLogArchiveFlag,
3566 "Mkext archive contains no kext info dictionaries.");
3567 goto finish;
3568 }
3569
3570 count = mkextInfoDictArray->getCount();
3571 for (i = 0; i < count; i++) {
3572 OSDictionary * infoDict;
3573
3574
3575 infoDict = OSDynamicCast(OSDictionary,
3576 mkextInfoDictArray->getObject(i));
3577
3578 /* Create the kext for the entry, then release it, because the
3579 * kext system keeps them around until explicitly removed.
3580 * Any creation/registration failures are already logged for us.
3581 */
3582 if (infoDict) {
3583 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3584
3585 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3586 if (kc_format == KCFormatFileset &&
3587 newKext &&
3588 !(newKext->isPrelinked()) &&
3589 newKext->declaresExecutable()) {
3590 result = kOSReturnError;
3591 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3592 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3593
3594 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3595 "Dynamic loading of kext denied for kext %s\n",
3596 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3597 goto finish;
3598 }
3599 }
3600 }
3601
3602 /* If the caller needs the plist, hand them back our copy
3603 */
3604 if (mkextPlistOut) {
3605 *mkextPlistOut = mkextPlist;
3606 parsedXML.detach();
3607 }
3608
3609 /* Even if we didn't keep any kexts from the mkext, we may have a load
3610 * request to process, so we are successful (no errors occurred).
3611 */
3612 result = kOSReturnSuccess;
3613
3614 finish:
3615 return result;
3616 }
3617
3618 /* static */
3619 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3620 OSKext::readMkext2Archive(
3621 OSData * mkextData,
3622 OSSharedPtr<OSDictionary> &mkextPlistOut,
3623 uint32_t * checksumPtr)
3624 {
3625 OSDictionary * mkextPlist = NULL;
3626 OSReturn ret;
3627
3628 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3629 &mkextPlist,
3630 checksumPtr))) {
3631 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3632 }
3633 return ret;
3634 }
3635
3636 /*********************************************************************
3637 *********************************************************************/
3638 /* static */
3639 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3640 OSKext::withMkext2Info(
3641 OSDictionary * anInfoDict,
3642 OSData * mkextData)
3643 {
3644 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3645
3646 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3647 return NULL;
3648 }
3649
3650 return newKext;
3651 }
3652
3653 /*********************************************************************
3654 *********************************************************************/
3655 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3656 OSKext::initWithMkext2Info(
3657 OSDictionary * anInfoDict,
3658 OSData * mkextData)
3659 {
3660 bool result = false;
3661 OSString * kextPath = NULL; // do not release
3662 OSNumber * executableOffsetNum = NULL; // do not release
3663 OSSharedPtr<OSData> executable;
3664
3665 if (anInfoDict == NULL || !super::init()) {
3666 goto finish;
3667 }
3668
3669 /* Get the path. Don't look for an arch-specific path property.
3670 */
3671 kextPath = OSDynamicCast(OSString,
3672 anInfoDict->getObject(kMKEXTBundlePathKey));
3673
3674 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3675 goto finish;
3676 }
3677
3678 /* If we have a path to the executable, save it.
3679 */
3680 executableRelPath.reset(OSDynamicCast(OSString,
3681 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3682
3683 /* Don't need the paths to be in the info dictionary any more.
3684 */
3685 anInfoDict->removeObject(kMKEXTBundlePathKey);
3686 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3687
3688 executableOffsetNum = OSDynamicCast(OSNumber,
3689 infoDict->getObject(kMKEXTExecutableKey));
3690 if (executableOffsetNum) {
3691 executable = createMkext2FileEntry(mkextData,
3692 executableOffsetNum, "executable");
3693 infoDict->removeObject(kMKEXTExecutableKey);
3694 if (!executable) {
3695 goto finish;
3696 }
3697 if (!setExecutable(executable.get(), mkextData, true)) {
3698 goto finish;
3699 }
3700 }
3701
3702 result = (registerIdentifier() == kOSKextInitialized);
3703 finish:
3704 return result;
3705 }
3706
3707 /*********************************************************************
3708 *********************************************************************/
3709 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3710 OSKext::createMkext2FileEntry(
3711 OSData * mkextData,
3712 OSNumber * offsetNum,
3713 const char * name)
3714 {
3715 OSSharedPtr<OSData> result;
3716 MkextEntryRef entryRef;
3717 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3718 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3719
3720 result = OSData::withCapacity(sizeof(entryRef));
3721 if (!result) {
3722 goto finish;
3723 }
3724
3725 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3726 entryRef.fileinfo = mkextBuffer + entryOffset;
3727 if (!result->appendValue(entryRef)) {
3728 result.reset();
3729 goto finish;
3730 }
3731
3732 finish:
3733 if (!result) {
3734 OSKextLog(this,
3735 kOSKextLogErrorLevel |
3736 kOSKextLogArchiveFlag,
3737 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3738 name, getIdentifierCString());
3739 }
3740 return result;
3741 }
3742
3743 /*********************************************************************
3744 *********************************************************************/
3745 extern "C" {
3746 static void * z_alloc(void *, u_int items, u_int size);
3747 static void z_free(void *, void *ptr);
3748
3749 typedef struct z_mem {
3750 uint32_t alloc_size;
3751 uint8_t data[0];
3752 } z_mem;
3753
3754 /*
3755 * Space allocation and freeing routines for use by zlib routines.
3756 */
3757 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3758 z_alloc(void * notused __unused, u_int num_items, u_int size)
3759 {
3760 void * result = NULL;
3761 z_mem * zmem = NULL;
3762
3763 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3764 //Check for overflow due to multiplication
3765 if (total > UINT32_MAX) {
3766 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3767 notused, num_items, size, num_items, size);
3768 }
3769
3770 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3771 //Check for overflow due to addition
3772 if (allocSize64 > UINT32_MAX) {
3773 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3774 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3775 }
3776 uint32_t allocSize = (uint32_t)allocSize64;
3777
3778 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3779 VM_KERN_MEMORY_OSKEXT);
3780 if (!zmem) {
3781 goto finish;
3782 }
3783 zmem->alloc_size = allocSize;
3784 result = (void *)&(zmem->data);
3785 finish:
3786 return result;
3787 }
3788
3789 void
z_free(void * notused __unused,void * ptr)3790 z_free(void * notused __unused, void * ptr)
3791 {
3792 uint32_t * skipper = (uint32_t *)ptr - 1;
3793 z_mem * zmem = (z_mem *)skipper;
3794 kfree_data(zmem, zmem->alloc_size);
3795 }
3796 };
3797
3798 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3799 OSKext::extractMkext2FileData(
3800 UInt8 * data,
3801 const char * name,
3802 uint32_t compressedSize,
3803 uint32_t fullSize)
3804 {
3805 OSSharedPtr<OSData> result;
3806 OSSharedPtr<OSData> uncompressedData; // release on error
3807
3808 uint8_t * uncompressedDataBuffer = NULL; // do not free
3809 unsigned long uncompressedSize;
3810 z_stream zstream;
3811 bool zstream_inited = false;
3812 int zlib_result;
3813
3814 /* If the file isn't compressed, we want to make a copy
3815 * so that we don't have the tie to the larger mkext file buffer any more.
3816 */
3817 if (!compressedSize) {
3818 uncompressedData = OSData::withBytes(data, fullSize);
3819 // xxx - no check for failure?
3820 result = uncompressedData;
3821 goto finish;
3822 }
3823
3824 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3825 (vm_offset_t*)&uncompressedDataBuffer, fullSize,
3826 KMA_DATA, VM_KERN_MEMORY_OSKEXT)) {
3827 /* How's this for cheesy? The kernel is only asked to extract
3828 * kext plists so we tailor the log messages.
3829 */
3830 if (isKernel()) {
3831 OSKextLog(this,
3832 kOSKextLogErrorLevel |
3833 kOSKextLogArchiveFlag,
3834 "Allocation failure extracting %s from mkext.", name);
3835 } else {
3836 OSKextLog(this,
3837 kOSKextLogErrorLevel |
3838 kOSKextLogArchiveFlag,
3839 "Allocation failure extracting %s from mkext for kext %s.",
3840 name, getIdentifierCString());
3841 }
3842
3843 goto finish;
3844 }
3845 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3846 if (!uncompressedData) {
3847 if (isKernel()) {
3848 OSKextLog(this,
3849 kOSKextLogErrorLevel |
3850 kOSKextLogArchiveFlag,
3851 "Allocation failure extracting %s from mkext.", name);
3852 } else {
3853 OSKextLog(this,
3854 kOSKextLogErrorLevel |
3855 kOSKextLogArchiveFlag,
3856 "Allocation failure extracting %s from mkext for kext %s.",
3857 name, getIdentifierCString());
3858 }
3859 goto finish;
3860 }
3861 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3862
3863 if (isKernel()) {
3864 OSKextLog(this,
3865 kOSKextLogDetailLevel |
3866 kOSKextLogArchiveFlag,
3867 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3868 name, compressedSize, fullSize);
3869 } else {
3870 OSKextLog(this,
3871 kOSKextLogDetailLevel |
3872 kOSKextLogArchiveFlag,
3873 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3874 getIdentifierCString(), name, compressedSize, fullSize);
3875 }
3876
3877 bzero(&zstream, sizeof(zstream));
3878 zstream.next_in = (UInt8 *)data;
3879 zstream.avail_in = compressedSize;
3880
3881 zstream.next_out = uncompressedDataBuffer;
3882 zstream.avail_out = fullSize;
3883
3884 zstream.zalloc = z_alloc;
3885 zstream.zfree = z_free;
3886
3887 zlib_result = inflateInit(&zstream);
3888 if (Z_OK != zlib_result) {
3889 if (isKernel()) {
3890 OSKextLog(this,
3891 kOSKextLogErrorLevel |
3892 kOSKextLogArchiveFlag,
3893 "Mkext error; zlib inflateInit failed (%d) for %s.",
3894 zlib_result, name);
3895 } else {
3896 OSKextLog(this,
3897 kOSKextLogErrorLevel |
3898 kOSKextLogArchiveFlag,
3899 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3900 getIdentifierCString(), zlib_result, name);
3901 }
3902 goto finish;
3903 } else {
3904 zstream_inited = true;
3905 }
3906
3907 zlib_result = inflate(&zstream, Z_FINISH);
3908
3909 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3910 uncompressedSize = zstream.total_out;
3911 } else {
3912 if (isKernel()) {
3913 OSKextLog(this,
3914 kOSKextLogErrorLevel |
3915 kOSKextLogArchiveFlag,
3916 "Mkext error; zlib inflate failed (%d) for %s.",
3917 zlib_result, name);
3918 } else {
3919 OSKextLog(this,
3920 kOSKextLogErrorLevel |
3921 kOSKextLogArchiveFlag,
3922 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3923 getIdentifierCString(), zlib_result, name);
3924 }
3925 if (zstream.msg) {
3926 OSKextLog(this,
3927 kOSKextLogErrorLevel |
3928 kOSKextLogArchiveFlag,
3929 "zlib error: %s.", zstream.msg);
3930 }
3931 goto finish;
3932 }
3933
3934 if (uncompressedSize != fullSize) {
3935 if (isKernel()) {
3936 OSKextLog(this,
3937 kOSKextLogErrorLevel |
3938 kOSKextLogArchiveFlag,
3939 "Mkext error; zlib inflate discrepancy for %s, "
3940 "uncompressed size != original size.", name);
3941 } else {
3942 OSKextLog(this,
3943 kOSKextLogErrorLevel |
3944 kOSKextLogArchiveFlag,
3945 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3946 "uncompressed size != original size.",
3947 getIdentifierCString(), name);
3948 }
3949 goto finish;
3950 }
3951
3952 result = os::move(uncompressedData);
3953
3954 finish:
3955 /* Don't bother checking return, nothing we can do on fail.
3956 */
3957 if (zstream_inited) {
3958 inflateEnd(&zstream);
3959 }
3960
3961 return result;
3962 }
3963
3964 /*********************************************************************
3965 *********************************************************************/
3966 /* static */
3967 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3968 OSKext::loadFromMkext(
3969 OSKextLogSpec clientLogFilter,
3970 char * mkextBuffer,
3971 uint32_t mkextBufferLength,
3972 char ** logInfoOut,
3973 uint32_t * logInfoLengthOut)
3974 {
3975 OSReturn result = kOSReturnError;
3976 OSReturn tempResult = kOSReturnError;
3977
3978 OSSharedPtr<OSData> mkextData;
3979 OSSharedPtr<OSDictionary> mkextPlist;
3980
3981 OSSharedPtr<OSArray> logInfoArray;
3982 OSSharedPtr<OSSerialize> serializer;
3983
3984 OSString * predicate = NULL; // do not release
3985 OSDictionary * requestArgs = NULL; // do not release
3986
3987 OSString * kextIdentifier = NULL; // do not release
3988 OSNumber * startKextExcludeNum = NULL; // do not release
3989 OSNumber * startMatchingExcludeNum = NULL; // do not release
3990 OSBoolean * delayAutounloadBool = NULL; // do not release
3991 OSArray * personalityNames = NULL; // do not release
3992
3993 /* Default values for these two options: regular autounload behavior,
3994 * load all kexts, send no personalities.
3995 */
3996 Boolean delayAutounload = false;
3997 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3998 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3999
4000 IORecursiveLockLock(sKextLock);
4001
4002 if (logInfoOut) {
4003 *logInfoOut = NULL;
4004 *logInfoLengthOut = 0;
4005 }
4006
4007 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
4008
4009 OSKextLog(/* kext */ NULL,
4010 kOSKextLogDebugLevel |
4011 kOSKextLogIPCFlag,
4012 "Received kext load request from user space.");
4013
4014 /* Regardless of processing, the fact that we have gotten here means some
4015 * user-space program is up and talking to us, so we'll switch our kext
4016 * registration to reflect that.
4017 */
4018 if (!sUserLoadsActive) {
4019 OSKextLog(/* kext */ NULL,
4020 kOSKextLogProgressLevel |
4021 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
4022 "Switching to late startup (user-space) kext loading policy.");
4023
4024 sUserLoadsActive = true;
4025 }
4026
4027 if (!sLoadEnabled) {
4028 OSKextLog(/* kext */ NULL,
4029 kOSKextLogErrorLevel |
4030 kOSKextLogLoadFlag,
4031 "Kext loading is disabled.");
4032 result = kOSKextReturnDisabled;
4033 goto finish;
4034 }
4035
4036 /* Note that we do not set a dealloc function on this OSData
4037 * object! No references to it can remain after the loadFromMkext()
4038 * call since we are in a MIG function, and will vm_deallocate()
4039 * the buffer.
4040 */
4041 mkextData = OSData::withBytesNoCopy(mkextBuffer,
4042 mkextBufferLength);
4043 if (!mkextData) {
4044 OSKextLog(/* kext */ NULL,
4045 kOSKextLogErrorLevel |
4046 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4047 "Failed to create wrapper for kext load request.");
4048 result = kOSKextReturnNoMemory;
4049 goto finish;
4050 }
4051
4052 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
4053 if (result != kOSReturnSuccess) {
4054 OSKextLog(/* kext */ NULL,
4055 kOSKextLogErrorLevel |
4056 kOSKextLogLoadFlag,
4057 "Failed to read kext load request.");
4058 goto finish;
4059 }
4060
4061 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
4062 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
4063 OSKextLog(/* kext */ NULL,
4064 kOSKextLogErrorLevel |
4065 kOSKextLogLoadFlag,
4066 "Received kext load request with no predicate; skipping.");
4067 result = kOSKextReturnInvalidArgument;
4068 goto finish;
4069 }
4070
4071 requestArgs = OSDynamicCast(OSDictionary,
4072 mkextPlist->getObject(kKextRequestArgumentsKey));
4073 if (!requestArgs || !requestArgs->getCount()) {
4074 OSKextLog(/* kext */ NULL,
4075 kOSKextLogErrorLevel |
4076 kOSKextLogLoadFlag,
4077 "Received kext load request with no arguments.");
4078 result = kOSKextReturnInvalidArgument;
4079 goto finish;
4080 }
4081
4082 kextIdentifier = OSDynamicCast(OSString,
4083 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
4084
4085 if (!kextIdentifier) {
4086 OSKextLog(/* kext */ NULL,
4087 kOSKextLogErrorLevel |
4088 kOSKextLogLoadFlag,
4089 "Received kext load request with no kext identifier.");
4090 result = kOSKextReturnInvalidArgument;
4091 goto finish;
4092 }
4093
4094 startKextExcludeNum = OSDynamicCast(OSNumber,
4095 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
4096 startMatchingExcludeNum = OSDynamicCast(OSNumber,
4097 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
4098 delayAutounloadBool = OSDynamicCast(OSBoolean,
4099 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
4100 personalityNames = OSDynamicCast(OSArray,
4101 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
4102
4103 if (delayAutounloadBool) {
4104 delayAutounload = delayAutounloadBool->getValue();
4105 }
4106 if (startKextExcludeNum) {
4107 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
4108 }
4109 if (startMatchingExcludeNum) {
4110 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
4111 }
4112
4113 OSKextLog(/* kext */ NULL,
4114 kOSKextLogProgressLevel |
4115 kOSKextLogIPCFlag,
4116 "Received request from user space to load kext %s.",
4117 kextIdentifier->getCStringNoCopy());
4118
4119 /* Load the kext, with no deferral, since this is a load from outside
4120 * the kernel.
4121 * xxx - Would like a better way to handle the default values for the
4122 * xxx - start/match opt args.
4123 */
4124 result = OSKext::loadKextWithIdentifier(
4125 kextIdentifier,
4126 /* kextRef */ NULL,
4127 /* allowDefer */ false,
4128 delayAutounload,
4129 startKextExcludeLevel,
4130 startMatchingExcludeLevel,
4131 personalityNames);
4132 if (result != kOSReturnSuccess) {
4133 goto finish;
4134 }
4135 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
4136 * for matching via a separate IOKit calldown.
4137 */
4138
4139 finish:
4140
4141 /* Gather up the collected log messages for user space. Any
4142 * error messages past this call will not make it up as log messages
4143 * but will be in the system log.
4144 */
4145 logInfoArray = OSKext::clearUserSpaceLogFilter();
4146
4147 if (logInfoArray && logInfoOut && logInfoLengthOut) {
4148 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
4149 logInfoOut, logInfoLengthOut);
4150 if (tempResult != kOSReturnSuccess) {
4151 result = tempResult;
4152 }
4153 }
4154
4155 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
4156
4157 IORecursiveLockUnlock(sKextLock);
4158
4159 /* Note: mkextDataObject will have been retained by every kext w/an
4160 * executable in it. That should all have been flushed out at the
4161 * and of the load operation, but you never know....
4162 */
4163 if (mkextData && mkextData->getRetainCount() > 1) {
4164 OSKextLog(/* kext */ NULL,
4165 kOSKextLogErrorLevel |
4166 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4167 "Kext load request buffer from user space still retained by a kext; "
4168 "probable memory leak.");
4169 }
4170
4171 return result;
4172 }
4173
4174 #endif // CONFIG_KXLD
4175
4176 /*********************************************************************
4177 *********************************************************************/
4178 /* static */
4179 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)4180 OSKext::serializeLogInfo(
4181 OSArray * logInfoArray,
4182 char ** logInfoOut,
4183 uint32_t * logInfoLengthOut)
4184 {
4185 OSReturn result = kOSReturnError;
4186 char * buffer = NULL;
4187 kern_return_t kmem_result = KERN_FAILURE;
4188 OSSharedPtr<OSSerialize> serializer;
4189 char * logInfo = NULL; // returned by reference
4190 uint32_t logInfoLength = 0;
4191
4192 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
4193 OSKextLog(/* kext */ NULL,
4194 kOSKextLogErrorLevel |
4195 kOSKextLogIPCFlag,
4196 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
4197 /* Bad programmer. */
4198 result = kOSKextReturnInvalidArgument;
4199 goto finish;
4200 }
4201
4202 serializer = OSSerialize::withCapacity(0);
4203 if (!serializer) {
4204 OSKextLog(/* kext */ NULL,
4205 kOSKextLogErrorLevel |
4206 kOSKextLogIPCFlag,
4207 "Failed to create serializer on log info for request from user space.");
4208 /* Incidental error; we're going to (try to) allow the request
4209 * itself to succeed. */
4210 } else {
4211 if (!logInfoArray->serialize(serializer.get())) {
4212 OSKextLog(/* kext */ NULL,
4213 kOSKextLogErrorLevel |
4214 kOSKextLogIPCFlag,
4215 "Failed to serialize log info for request from user space.");
4216 /* Incidental error; we're going to (try to) allow the request
4217 * itself to succeed. */
4218 } else {
4219 logInfo = serializer->text();
4220 logInfoLength = serializer->getLength();
4221
4222 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength),
4223 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
4224 if (kmem_result != KERN_SUCCESS) {
4225 OSKextLog(/* kext */ NULL,
4226 kOSKextLogErrorLevel |
4227 kOSKextLogIPCFlag,
4228 "Failed to copy log info for request from user space.");
4229 /* Incidental error; we're going to (try to) allow the request
4230 * to succeed. */
4231 } else {
4232 /* 11981737 - clear uninitialized data in last page */
4233 bzero((void *)(buffer + logInfoLength),
4234 (round_page(logInfoLength) - logInfoLength));
4235 memcpy(buffer, logInfo, logInfoLength);
4236 *logInfoOut = buffer;
4237 *logInfoLengthOut = logInfoLength;
4238 }
4239 }
4240 }
4241
4242 result = kOSReturnSuccess;
4243 finish:
4244 return result;
4245 }
4246
4247 #if PRAGMA_MARK
4248 #pragma mark Instance Management Methods
4249 #endif
4250 /*********************************************************************
4251 *********************************************************************/
4252 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)4253 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
4254 {
4255 OSSharedPtr<OSKext> foundKext;
4256
4257 IORecursiveLockLock(sKextLock);
4258 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
4259 IORecursiveLockUnlock(sKextLock);
4260
4261 return foundKext;
4262 }
4263
4264 /*********************************************************************
4265 *********************************************************************/
4266 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)4267 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
4268 {
4269 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
4270 }
4271
4272 /*********************************************************************
4273 *********************************************************************/
4274 OSSharedPtr<OSKext>
lookupDextWithIdentifier(OSString * dextIdentifier,OSData * dextUniqueIdentifier)4275 OSKext::lookupDextWithIdentifier(OSString * dextIdentifier, OSData *dextUniqueIdentifier)
4276 {
4277 OSSharedPtr<OSKext> foundDext;
4278 foundDext.reset();
4279
4280 IORecursiveLockLock(sKextLock);
4281 OSKext *dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIdentifier->getCStringNoCopy()));
4282 if (dext != NULL && dext->isDriverKit()) {
4283 if (dext->dextUniqueID == NULL || dext->dextUniqueID->isEqualTo(dextUniqueIdentifier)) {
4284 foundDext.reset(dext, OSRetain);
4285 }
4286 }
4287 IORecursiveLockUnlock(sKextLock);
4288
4289 return foundDext;
4290 }
4291
4292 /*********************************************************************
4293 *********************************************************************/
4294 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)4295 OSKext::lookupKextWithLoadTag(uint32_t aTag)
4296 {
4297 OSSharedPtr<OSKext> foundKext; // returned
4298 uint32_t i, j;
4299 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4300 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4301
4302 IORecursiveLockLock(sKextLock);
4303
4304 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4305 for (i = 0; i < count[j]; i++) {
4306 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4307 if (thisKext->getLoadTag() == aTag) {
4308 foundKext.reset(thisKext, OSRetain);
4309 goto finish;
4310 }
4311 }
4312 }
4313
4314 finish:
4315 IORecursiveLockUnlock(sKextLock);
4316
4317 return foundKext;
4318 }
4319
4320 /*********************************************************************
4321 *********************************************************************/
4322 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)4323 OSKext::lookupKextWithAddress(vm_address_t address)
4324 {
4325 OSSharedPtr<OSKext> foundKext; // returned
4326 uint32_t count, i;
4327 kmod_info_t *kmod_info;
4328 vm_address_t originalAddress;
4329 #if defined(__arm64__)
4330 uint64_t textExecBase;
4331 size_t textExecSize;
4332 #endif /* defined(__arm64__) */
4333
4334 originalAddress = address;
4335 #if __has_feature(ptrauth_calls)
4336 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
4337 #endif /* __has_feature(ptrauth_calls) */
4338
4339 IORecursiveLockLock(sKextLock);
4340
4341 count = sLoadedKexts->getCount();
4342 for (i = 0; i < count; i++) {
4343 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
4344 if (thisKext == sKernelKext) {
4345 continue;
4346 }
4347 if (thisKext->kmod_info && thisKext->kmod_info->address) {
4348 kmod_info = thisKext->kmod_info;
4349 vm_address_t kext_start = kmod_info->address;
4350 vm_address_t kext_end = kext_start + kmod_info->size;
4351 if ((kext_start <= address) && (address < kext_end)) {
4352 foundKext.reset(thisKext, OSRetain);
4353 goto finish;
4354 }
4355 #if defined(__arm64__)
4356 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
4357
4358 /**
4359 * If the addresses within the Mach-O are unslid, then manually
4360 * slide any addresses coming from the Mach-O before usage.
4361 */
4362 if (thisKext->flags.unslidMachO) {
4363 textExecBase = (uintptr_t) ml_static_slide((vm_offset_t) textExecBase);
4364 }
4365
4366 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4367 foundKext.reset(thisKext, OSRetain);
4368 goto finish;
4369 }
4370 #endif /* defined (__arm64__) */
4371 }
4372 }
4373 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4374 foundKext.reset(sKernelKext, OSRetain);
4375 goto finish;
4376 }
4377 /*
4378 * DriverKit userspace executables do not have a kernel linkedExecutable,
4379 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4380 * here, so use the original address passed to this method.
4381 *
4382 * This is supposed to be used for logging reasons only. When logd
4383 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4384 * remove it here before checking it against the LoadTag.
4385 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4386 */
4387
4388 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4389 count = sLoadedDriverKitKexts->getCount();
4390 for (i = 0; i < count; i++) {
4391 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4392 if (thisKext->getLoadTag() == address) {
4393 foundKext.reset(thisKext, OSRetain);
4394 }
4395 }
4396
4397 finish:
4398 IORecursiveLockUnlock(sKextLock);
4399
4400 return foundKext;
4401 }
4402
4403 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)4404 OSKext::copyKextUUIDForAddress(OSNumber *address)
4405 {
4406 OSSharedPtr<OSData> uuid;
4407 OSSharedPtr<OSKext> kext;
4408
4409 if (!address) {
4410 return NULL;
4411 }
4412
4413 #if CONFIG_MACF
4414 /* Is the calling process allowed to query kext info? */
4415 if (current_task() != kernel_task) {
4416 int macCheckResult = 0;
4417 kauth_cred_t cred = NULL;
4418
4419 cred = kauth_cred_get_with_ref();
4420 macCheckResult = mac_kext_check_query(cred);
4421 kauth_cred_unref(&cred);
4422
4423 if (macCheckResult != 0) {
4424 OSKextLog(/* kext */ NULL,
4425 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4426 "Failed to query kext UUID (MAC policy error 0x%x).",
4427 macCheckResult);
4428 return NULL;
4429 }
4430 }
4431 #endif
4432
4433 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4434 if (slidAddress != 0) {
4435 kext = lookupKextWithAddress(slidAddress);
4436 if (kext) {
4437 uuid = kext->copyTextUUID();
4438 }
4439 }
4440
4441 if (!uuid) {
4442 /*
4443 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4444 * a kext. This might have happened because the log message came from a dext.
4445 *
4446 * Try again with the original address.
4447 */
4448 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4449 if (kext && kext->isDriverKit()) {
4450 uuid = kext->copyTextUUID();
4451 }
4452 }
4453
4454 return uuid;
4455 }
4456
4457 /*********************************************************************
4458 *********************************************************************/
4459 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4460 OSKext::lookupKextWithUUID(uuid_t wanted)
4461 {
4462 OSSharedPtr<OSKext> foundKext; // returned
4463 uint32_t j, i;
4464 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4465 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4466
4467
4468 IORecursiveLockLock(sKextLock);
4469
4470 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4471 for (i = 0; i < count[j]; i++) {
4472 OSKext * thisKext = NULL;
4473
4474 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4475 if (!thisKext) {
4476 continue;
4477 }
4478
4479 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4480 if (!uuid_data) {
4481 continue;
4482 }
4483
4484 uuid_t uuid;
4485 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4486
4487 if (0 == uuid_compare(wanted, uuid)) {
4488 foundKext.reset(thisKext, OSRetain);
4489 goto finish;
4490 }
4491 }
4492 }
4493 finish:
4494 IORecursiveLockUnlock(sKextLock);
4495
4496 return foundKext;
4497 }
4498
4499
4500
4501
4502 /*********************************************************************
4503 *********************************************************************/
4504 /* static */
4505 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4506 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4507 {
4508 bool result = false;
4509 OSKext * foundKext = NULL; // returned
4510
4511 IORecursiveLockLock(sKextLock);
4512
4513 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4514 if (foundKext && foundKext->isLoaded()) {
4515 result = true;
4516 }
4517
4518 IORecursiveLockUnlock(sKextLock);
4519
4520 return result;
4521 }
4522
4523 /*********************************************************************
4524 * xxx - should spawn a separate thread so a kext can safely have
4525 * xxx - itself unloaded.
4526 *********************************************************************/
4527 /* static */
4528 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4529 OSKext::removeKext(
4530 OSKext * aKext,
4531 #if CONFIG_EMBEDDED
4532 __unused
4533 #endif
4534 bool terminateServicesAndRemovePersonalitiesFlag)
4535 {
4536 #if CONFIG_EMBEDDED
4537 if (!aKext->isDriverKit()) {
4538 OSKextLog(aKext,
4539 kOSKextLogErrorLevel |
4540 kOSKextLogKextBookkeepingFlag,
4541 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4542 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4543
4544 return kOSReturnSuccess;
4545 }
4546 #endif /* CONFIG_EMBEDDED */
4547 OSReturn result = kOSKextReturnInUse;
4548 OSKext * checkKext = NULL; // do not release
4549 #if CONFIG_MACF
4550 int macCheckResult = 0;
4551 kauth_cred_t cred = NULL;
4552 #endif
4553
4554 IORecursiveLockLock(sKextLock);
4555
4556 /* If the kext has no identifier, it failed to init
4557 * so isn't in sKextsByID and it isn't loaded.
4558 */
4559 if (!aKext->getIdentifier()) {
4560 result = kOSReturnSuccess;
4561 goto finish;
4562 }
4563
4564 checkKext = OSDynamicCast(OSKext,
4565 sKextsByID->getObject(aKext->getIdentifier()));
4566 if (checkKext != aKext) {
4567 result = kOSKextReturnNotFound;
4568 goto finish;
4569 }
4570
4571 if (aKext->isLoaded() || aKext->isDriverKit()) {
4572 #if CONFIG_MACF
4573 if (current_task() != kernel_task) {
4574 cred = kauth_cred_get_with_ref();
4575 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4576 kauth_cred_unref(&cred);
4577 }
4578
4579 if (macCheckResult != 0) {
4580 result = kOSReturnError;
4581 OSKextLog(aKext,
4582 kOSKextLogErrorLevel |
4583 kOSKextLogKextBookkeepingFlag,
4584 "Failed to remove kext %s (MAC policy error 0x%x).",
4585 aKext->getIdentifierCString(), macCheckResult);
4586 goto finish;
4587 }
4588 #endif
4589
4590 /* make sure there are no resource requests in flight - 17187548 */
4591 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4592 goto finish;
4593 }
4594 if (aKext->flags.unloadUnsupported) {
4595 result = kOSKextReturnInUse;
4596 OSKextLog(aKext,
4597 kOSKextLogErrorLevel |
4598 kOSKextLogKextBookkeepingFlag,
4599 "Can't remove kext %s; unsupported by cache.",
4600 aKext->getIdentifierCString());
4601 goto finish;
4602 }
4603
4604 /* If we are terminating, send the request to the IOCatalogue
4605 * (which will actually call us right back but that's ok we have
4606 * a recursive lock don't you know) but do not ask the IOCatalogue
4607 * to call back with an unload, we'll do that right here.
4608 */
4609 if (terminateServicesAndRemovePersonalitiesFlag) {
4610 result = gIOCatalogue->terminateDriversForModule(
4611 aKext->getIdentifierCString(), /* unload */ false);
4612 if (result != kOSReturnSuccess) {
4613 OSKextLog(aKext,
4614 kOSKextLogErrorLevel |
4615 kOSKextLogKextBookkeepingFlag,
4616 "Can't remove kext %s; services failed to terminate - 0x%x.",
4617 aKext->getIdentifierCString(), result);
4618 goto finish;
4619 }
4620 }
4621
4622 result = aKext->unload();
4623 if (result != kOSReturnSuccess) {
4624 OSKextLog(aKext,
4625 kOSKextLogErrorLevel |
4626 kOSKextLogKextBookkeepingFlag,
4627 "Can't remove kext %s; kext failed to unload - 0x%x.",
4628 aKext->getIdentifierCString(), result);
4629 goto finish;
4630 }
4631 }
4632
4633 /* Remove personalities as requested. This is a bit redundant for a loaded
4634 * kext as IOCatalogue::terminateDriversForModule() removes driver
4635 * personalities, but it doesn't restart matching, which we always want
4636 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4637 * that happens.
4638 */
4639 if (terminateServicesAndRemovePersonalitiesFlag) {
4640 aKext->removePersonalitiesFromCatalog();
4641 }
4642
4643 if (aKext->isInFileset()) {
4644 OSKextLog(aKext,
4645 kOSKextLogProgressLevel |
4646 kOSKextLogKextBookkeepingFlag,
4647 "Fileset kext %s unloaded.",
4648 aKext->getIdentifierCString());
4649 } else {
4650 OSKextLog(aKext,
4651 kOSKextLogProgressLevel |
4652 kOSKextLogKextBookkeepingFlag,
4653 "Removing kext %s.",
4654 aKext->getIdentifierCString());
4655
4656 sKextsByID->removeObject(aKext->getIdentifier());
4657 }
4658 result = kOSReturnSuccess;
4659
4660 finish:
4661 IORecursiveLockUnlock(sKextLock);
4662 return result;
4663 }
4664
4665 /*********************************************************************
4666 *********************************************************************/
4667 /* static */
4668 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4669 OSKext::removeKextWithIdentifier(
4670 const char * kextIdentifier,
4671 bool terminateServicesAndRemovePersonalitiesFlag)
4672 {
4673 OSReturn result = kOSReturnError;
4674
4675 IORecursiveLockLock(sKextLock);
4676
4677 OSKext * aKext = OSDynamicCast(OSKext,
4678 sKextsByID->getObject(kextIdentifier));
4679 if (!aKext) {
4680 result = kOSKextReturnNotFound;
4681 OSKextLog(/* kext */ NULL,
4682 kOSKextLogErrorLevel |
4683 kOSKextLogKextBookkeepingFlag,
4684 "Can't remove kext %s - not found.",
4685 kextIdentifier);
4686 goto finish;
4687 }
4688
4689 result = OSKext::removeKext(aKext,
4690 terminateServicesAndRemovePersonalitiesFlag);
4691
4692 finish:
4693 IORecursiveLockUnlock(sKextLock);
4694
4695 return result;
4696 }
4697
4698 /*********************************************************************
4699 *********************************************************************/
4700 /* static */
4701 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4702 OSKext::removeKextWithLoadTag(
4703 OSKextLoadTag loadTag,
4704 bool terminateServicesAndRemovePersonalitiesFlag)
4705 {
4706 OSReturn result = kOSReturnError;
4707 OSKext * foundKext = NULL;
4708 uint32_t i, j;
4709 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4710 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4711
4712
4713 IORecursiveLockLock(sKextLock);
4714
4715 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4716 for (i = 0; i < count[j]; i++) {
4717 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4718 if (thisKext->loadTag == loadTag) {
4719 foundKext = thisKext;
4720 break;
4721 }
4722 }
4723 }
4724
4725 if (!foundKext) {
4726 result = kOSKextReturnNotFound;
4727 OSKextLog(/* kext */ NULL,
4728 kOSKextLogErrorLevel |
4729 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4730 "Can't remove kext with load tag %d - not found.",
4731 loadTag);
4732 goto finish;
4733 }
4734
4735 result = OSKext::removeKext(foundKext,
4736 terminateServicesAndRemovePersonalitiesFlag);
4737
4738 finish:
4739 IORecursiveLockUnlock(sKextLock);
4740
4741 return result;
4742 }
4743
4744 /*********************************************************************
4745 *********************************************************************/
4746 OSSharedPtr<OSDictionary>
copyKexts(void)4747 OSKext::copyKexts(void)
4748 {
4749 OSSharedPtr<OSDictionary> result;
4750
4751 IORecursiveLockLock(sKextLock);
4752 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4753 IORecursiveLockUnlock(sKextLock);
4754
4755 return result;
4756 }
4757
4758 /*********************************************************************
4759 *********************************************************************/
4760 #define BOOTER_KEXT_PREFIX "Driver-"
4761
4762 typedef struct _DeviceTreeBuffer {
4763 uint32_t paddr;
4764 uint32_t length;
4765 } _DeviceTreeBuffer;
4766
4767 /*********************************************************************
4768 * Create a dictionary of excluded kexts from the given booter data.
4769 *********************************************************************/
4770 /* static */
4771 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4772 OSKext::createExcludeListFromBooterData(
4773 OSDictionary * theDictionary,
4774 OSCollectionIterator * theIterator )
4775 {
4776 OSString * deviceTreeName = NULL; // do not release
4777 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4778 char * booterDataPtr = NULL; // do not release
4779 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4780 char * infoDictAddr = NULL; // do not release
4781 OSSharedPtr<OSObject> parsedXML;
4782 OSDictionary * theInfoDict = NULL; // do not release
4783
4784 theIterator->reset();
4785
4786 /* look for AppleKextExcludeList.kext */
4787 while ((deviceTreeName =
4788 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4789 const char * devTreeNameCString;
4790 OSData * deviceTreeEntry; // do not release
4791 OSString * myBundleID; // do not release
4792
4793 deviceTreeEntry =
4794 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4795 if (!deviceTreeEntry) {
4796 continue;
4797 }
4798
4799 /* Make sure it is a kext */
4800 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4801 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4802 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4803 OSKextLog(NULL,
4804 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4805 "\"%s\" not a kext",
4806 devTreeNameCString);
4807 continue;
4808 }
4809
4810 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4811 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4812 if (!deviceTreeBuffer) {
4813 continue;
4814 }
4815
4816 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4817 if (!booterDataPtr) {
4818 continue;
4819 }
4820
4821 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4822 if (!kextFileInfo->infoDictPhysAddr ||
4823 !kextFileInfo->infoDictLength) {
4824 continue;
4825 }
4826
4827 infoDictAddr = (char *)
4828 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4829 if (!infoDictAddr) {
4830 continue;
4831 }
4832
4833 parsedXML = OSUnserializeXML(infoDictAddr);
4834 if (!parsedXML) {
4835 continue;
4836 }
4837
4838 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4839 if (!theInfoDict) {
4840 continue;
4841 }
4842
4843 myBundleID =
4844 OSDynamicCast(OSString,
4845 theInfoDict->getObject(kCFBundleIdentifierKey));
4846 if (myBundleID &&
4847 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4848 boolean_t updated = updateExcludeList(theInfoDict);
4849 if (!updated) {
4850 /* 25322874 */
4851 panic("Missing OSKextExcludeList dictionary");
4852 }
4853 break;
4854 }
4855 } // while ( (deviceTreeName = ...) )
4856
4857 return;
4858 }
4859
4860 /*********************************************************************
4861 * Create a dictionary of excluded kexts from the given prelink
4862 * info (kernelcache).
4863 *********************************************************************/
4864 /* static */
4865 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4866 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4867 {
4868 OSDictionary * myInfoDict = NULL; // do not release
4869 OSString * myBundleID; // do not release
4870 u_int i;
4871
4872 /* Find the Apple Kext Exclude List. */
4873 for (i = 0; i < theInfoArray->getCount(); i++) {
4874 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4875 if (!myInfoDict) {
4876 continue;
4877 }
4878 myBundleID =
4879 OSDynamicCast(OSString,
4880 myInfoDict->getObject(kCFBundleIdentifierKey));
4881 if (myBundleID &&
4882 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4883 boolean_t updated = updateExcludeList(myInfoDict);
4884 if (!updated) {
4885 /* 25322874 */
4886 panic("Missing OSKextExcludeList dictionary");
4887 }
4888 break;
4889 }
4890 } // for (i = 0; i < theInfoArray->getCount()...
4891
4892 return;
4893 }
4894
4895 /* static */
4896 boolean_t
updateExcludeList(OSDictionary * infoDict)4897 OSKext::updateExcludeList(OSDictionary *infoDict)
4898 {
4899 OSDictionary *myTempDict = NULL; // do not free
4900 OSString *myTempString = NULL; // do not free
4901 OSKextVersion newVersion = 0;
4902 boolean_t updated = false;
4903
4904 if (!infoDict) {
4905 return false;
4906 }
4907
4908 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4909 if (!myTempDict) {
4910 return false;
4911 }
4912
4913 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4914 if (!myTempString) {
4915 return false;
4916 }
4917
4918 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4919 if (newVersion == 0) {
4920 return false;
4921 }
4922
4923 IORecursiveLockLock(sKextLock);
4924
4925 if (newVersion > sExcludeListVersion) {
4926 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4927 sExcludeListVersion = newVersion;
4928 updated = true;
4929 }
4930
4931 IORecursiveLockUnlock(sKextLock);
4932 return updated;
4933 }
4934
4935 #if PRAGMA_MARK
4936 #pragma mark Accessors
4937 #endif
4938
4939 /*********************************************************************
4940 *********************************************************************/
4941 const OSObject *
getBundleExecutable(void)4942 OSKext::getBundleExecutable(void)
4943 {
4944 return infoDict->getObject(kCFBundleExecutableKey);
4945 }
4946
4947 /*********************************************************************
4948 *********************************************************************/
4949 const OSSymbol *
getIdentifier(void)4950 OSKext::getIdentifier(void)
4951 {
4952 return bundleID.get();
4953 }
4954
4955 /*********************************************************************
4956 * A kext must have a bundle identifier to even survive initialization;
4957 * this is guaranteed to exist past then.
4958 *********************************************************************/
4959 const char *
getIdentifierCString(void)4960 OSKext::getIdentifierCString(void)
4961 {
4962 return bundleID->getCStringNoCopy();
4963 }
4964
4965 /*********************************************************************
4966 *********************************************************************/
4967 OSKextVersion
getVersion(void)4968 OSKext::getVersion(void)
4969 {
4970 return version;
4971 }
4972
4973 /*********************************************************************
4974 *********************************************************************/
4975 OSKextVersion
getCompatibleVersion(void)4976 OSKext::getCompatibleVersion(void)
4977 {
4978 return compatibleVersion;
4979 }
4980
4981 /*********************************************************************
4982 *********************************************************************/
4983 bool
isLibrary(void)4984 OSKext::isLibrary(void)
4985 {
4986 return getCompatibleVersion() > 0;
4987 }
4988
4989 /*********************************************************************
4990 *********************************************************************/
4991 bool
isCompatibleWithVersion(OSKextVersion aVersion)4992 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4993 {
4994 if ((compatibleVersion > -1 && version > -1) &&
4995 (compatibleVersion <= version && aVersion <= version)) {
4996 return true;
4997 }
4998 return false;
4999 }
5000
5001 /*********************************************************************
5002 *********************************************************************/
5003 bool
declaresExecutable(void)5004 OSKext::declaresExecutable(void)
5005 {
5006 if (isDriverKit()) {
5007 return false;
5008 }
5009 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
5010 }
5011
5012 /*********************************************************************
5013 *********************************************************************/
5014 OSData *
getExecutable(void)5015 OSKext::getExecutable(void)
5016 {
5017 OSData * result = NULL;
5018 OSSharedPtr<OSData> extractedExecutable;
5019
5020 if (flags.builtin) {
5021 return sKernelKext->linkedExecutable.get();
5022 }
5023
5024 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
5025 if (result) {
5026 return result;
5027 }
5028
5029 #if CONFIG_KXLD
5030 OSData * mkextExecutableRef = NULL; // do not release
5031 mkextExecutableRef = OSDynamicCast(OSData,
5032 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
5033
5034 if (mkextExecutableRef) {
5035 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
5036 mkextExecutableRef->getBytesNoCopy();
5037 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
5038 if (mkextVersion == MKEXT_VERS_2) {
5039 mkext2_file_entry * fileinfo =
5040 (mkext2_file_entry *)mkextEntryRef->fileinfo;
5041 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
5042 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
5043 extractedExecutable = extractMkext2FileData(
5044 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
5045 compressedSize, fullSize);
5046 } else {
5047 OSKextLog(this, kOSKextLogErrorLevel |
5048 kOSKextLogArchiveFlag,
5049 "Kext %s - unknown mkext version 0x%x for executable.",
5050 getIdentifierCString(), mkextVersion);
5051 }
5052
5053 /* Regardless of success, remove the mkext executable,
5054 * and drop one reference on the mkext. (setExecutable() does not
5055 * replace, it removes, or panics if asked to replace.)
5056 */
5057 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
5058 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
5059
5060 if (extractedExecutable && extractedExecutable->getLength()) {
5061 if (!setExecutable(extractedExecutable.get())) {
5062 goto finish;
5063 }
5064 result = extractedExecutable.get();
5065 } else {
5066 goto finish;
5067 }
5068 }
5069
5070 finish:
5071 #endif // CONFIG_KXLD
5072 return result;
5073 }
5074
5075 /*********************************************************************
5076 *********************************************************************/
5077 bool
isInterface(void)5078 OSKext::isInterface(void)
5079 {
5080 return flags.interface;
5081 }
5082
5083 /*********************************************************************
5084 *********************************************************************/
5085 bool
isKernel(void)5086 OSKext::isKernel(void)
5087 {
5088 return this == sKernelKext;
5089 }
5090
5091 /*********************************************************************
5092 *********************************************************************/
5093 bool
isKernelComponent(void)5094 OSKext::isKernelComponent(void)
5095 {
5096 return flags.kernelComponent ? true : false;
5097 }
5098
5099 /*********************************************************************
5100 *********************************************************************/
5101 bool
isExecutable(void)5102 OSKext::isExecutable(void)
5103 {
5104 return !isKernel() && !isInterface() && declaresExecutable();
5105 }
5106
5107 /*********************************************************************
5108 *********************************************************************/
5109 bool
isSpecialKernelBinary(void)5110 OSKext::isSpecialKernelBinary(void)
5111 {
5112 #if CONFIG_SPTM
5113 return (this->kmod_info) &&
5114 ((this->kmod_info->id == kOSKextSPTMLoadTag) ||
5115 (this->kmod_info->id == kOSKextTXMLoadTag));
5116 #else
5117 return false;
5118 #endif
5119 }
5120
5121 /*********************************************************************
5122 * We might want to check this recursively for all dependencies,
5123 * since a subtree of dependencies could get loaded before we hit
5124 * a dependency that isn't safe-boot-loadable.
5125 *
5126 * xxx - Might want to return false if OSBundleEnableKextLogging or
5127 * OSBundleDebugLevel
5128 * or IOKitDebug is nonzero too (we used to do that, but I don't see
5129 * the point except it's usually development drivers, which might
5130 * cause panics on startup, that have those properties). Heh; could
5131 * use a "kx" boot-arg!
5132 *********************************************************************/
5133 bool
isLoadableInSafeBoot(void)5134 OSKext::isLoadableInSafeBoot(void)
5135 {
5136 bool result = false;
5137 OSString * required = NULL; // do not release
5138
5139 if (isKernel()) {
5140 result = true;
5141 goto finish;
5142 }
5143
5144 if (isDriverKit()) {
5145 result = true;
5146 goto finish;
5147 }
5148
5149 required = OSDynamicCast(OSString,
5150 getPropertyForHostArch(kOSBundleRequiredKey));
5151 if (!required) {
5152 goto finish;
5153 }
5154 if (required->isEqualTo(kOSBundleRequiredRoot) ||
5155 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
5156 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
5157 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
5158 required->isEqualTo(kOSBundleRequiredConsole)) {
5159 result = true;
5160 }
5161
5162 finish:
5163 return result;
5164 }
5165
5166 /*********************************************************************
5167 *********************************************************************/
5168 bool
isPrelinked(void)5169 OSKext::isPrelinked(void)
5170 {
5171 return flags.prelinked ? true : false;
5172 }
5173
5174 /*********************************************************************
5175 *********************************************************************/
5176 bool
isLoaded(void)5177 OSKext::isLoaded(void)
5178 {
5179 return flags.loaded ? true : false;
5180 }
5181
5182 /*********************************************************************
5183 *********************************************************************/
5184 bool
isStarted(void)5185 OSKext::isStarted(void)
5186 {
5187 return flags.started ? true : false;
5188 }
5189
5190 /*********************************************************************
5191 *********************************************************************/
5192 bool
isCPPInitialized(void)5193 OSKext::isCPPInitialized(void)
5194 {
5195 return flags.CPPInitialized;
5196 }
5197
5198 /*********************************************************************
5199 *********************************************************************/
5200 void
setCPPInitialized(bool initialized)5201 OSKext::setCPPInitialized(bool initialized)
5202 {
5203 flags.CPPInitialized = initialized;
5204 }
5205
5206 /*********************************************************************
5207 *********************************************************************/
5208 uint32_t
getLoadTag(void)5209 OSKext::getLoadTag(void)
5210 {
5211 return loadTag;
5212 }
5213
5214 /*********************************************************************
5215 *********************************************************************/
5216 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)5217 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5218 {
5219 if (linkedExecutable) {
5220 *loadSize = linkedExecutable->getLength();
5221
5222 /* If we have a kmod_info struct, calculated the wired size
5223 * from that. Otherwise it's the full load size.
5224 */
5225 if (kmod_info) {
5226 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5227 } else {
5228 *wiredSize = *loadSize;
5229 }
5230 } else {
5231 *wiredSize = 0;
5232 *loadSize = 0;
5233 }
5234 }
5235
5236 /*********************************************************************
5237 *********************************************************************/
5238 OSSharedPtr<OSData>
copyUUID(void)5239 OSKext::copyUUID(void)
5240 {
5241 OSSharedPtr<OSData> result;
5242 OSData * theExecutable = NULL; // do not release
5243 const kernel_mach_header_t * header;
5244
5245 /* An interface kext doesn't have a linked executable with an LC_UUID,
5246 * we create one when it's linked.
5247 */
5248 if (interfaceUUID) {
5249 result = interfaceUUID;
5250 goto finish;
5251 }
5252
5253 if (flags.builtin || isInterface()) {
5254 return sKernelKext->copyUUID();
5255 }
5256
5257 if (isDriverKit() && infoDict) {
5258 return driverKitUUID;
5259 }
5260
5261 /* For real kexts, try to get the UUID from the linked executable,
5262 * or if is hasn't been linked yet, the unrelocated executable.
5263 */
5264 theExecutable = linkedExecutable.get();
5265 if (!theExecutable) {
5266 theExecutable = getExecutable();
5267 }
5268
5269 if (!theExecutable) {
5270 goto finish;
5271 }
5272
5273 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5274 result = copyMachoUUID(header);
5275
5276 finish:
5277 return result;
5278 }
5279
5280 /*********************************************************************
5281 *********************************************************************/
5282 OSSharedPtr<OSData>
copyTextUUID(void)5283 OSKext::copyTextUUID(void)
5284 {
5285 if (flags.builtin) {
5286 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
5287 }
5288 return copyUUID();
5289 }
5290
5291 /*********************************************************************
5292 *********************************************************************/
5293 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)5294 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5295 {
5296 OSSharedPtr<OSData> result;
5297 const struct load_command * load_cmd = NULL;
5298 const struct uuid_command * uuid_cmd = NULL;
5299 uint32_t i;
5300
5301 load_cmd = (const struct load_command *)&header[1];
5302
5303 if (header->magic != MH_MAGIC_KERNEL) {
5304 OSKextLog(NULL,
5305 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5306 "%s: bad header %p",
5307 __func__,
5308 header);
5309 goto finish;
5310 }
5311
5312 for (i = 0; i < header->ncmds; i++) {
5313 if (load_cmd->cmd == LC_UUID) {
5314 uuid_cmd = (struct uuid_command *)load_cmd;
5315 result = OSData::withValue(uuid_cmd->uuid);
5316 goto finish;
5317 }
5318 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5319 }
5320
5321 finish:
5322 return result;
5323 }
5324
5325 void
setDriverKitUUID(OSData * uuid)5326 OSKext::setDriverKitUUID(OSData *uuid)
5327 {
5328 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5329 OSSafeReleaseNULL(uuid);
5330 }
5331 }
5332
5333 OSData *
getDextUniqueID(void)5334 OSKext::getDextUniqueID(void)
5335 {
5336 if (isDriverKit() && dextUniqueID != NULL) {
5337 return dextUniqueID.get();
5338 }
5339
5340 return NULL;
5341 }
5342
5343 /*
5344 * In case a DextUniqueID exists this function returns
5345 * an allocated char* with the hexadecimal represantition of
5346 * DextUniqueID.
5347 * The returned pinter needs to be freed with kfree_data, the
5348 * size of the allocated buffer is returned in size.
5349 */
5350 static const char *
getDextUniqueIDCString(OSData * dextUniqueID,unsigned int * size)5351 getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5352 {
5353 if (dextUniqueID != NULL) {
5354 char *s_buffer = NULL;
5355 unsigned int d_length = dextUniqueID->getLength();
5356 /*
5357 * We are converting in hex, so for every byte we will have
5358 * 2 hex chars and one last \0.
5359 */
5360 unsigned int s_length = d_length * 2 + 1;
5361 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5362
5363 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5364 int cpos = 0;
5365 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5366 int ret = snprintf(s_buffer + cpos, s_length - cpos - 1, "%02X", uid[i]);
5367 if (ret <= 0) {
5368 break;
5369 }
5370 cpos += ret;
5371 }
5372 *size = s_length;
5373
5374 return s_buffer;
5375 }
5376
5377 return NULL;
5378 }
5379
5380 /*
5381 * Atomically swaps the olddext with newdext.
5382 * olddext will be unloaded, so it might be freed
5383 * after this call unless it was previously retained.
5384 *
5385 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5386 */
5387 void
replaceDextInternal(OSKext * olddext,OSKext * newdext)5388 OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5389 {
5390 OSReturn result;
5391 const OSSymbol * dextID = olddext->getIdentifier();
5392 OSData * oldDextUniqueIdentifier = olddext->getDextUniqueID();
5393 OSSharedPtr<OSArray> new_personalities;
5394 OSSharedPtr<OSString> kextIdentifier;
5395 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5396 assert(lock_held);
5397
5398 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5399 dextID->retain();
5400
5401 if (newdext != NULL) {
5402 __assert_only bool eq = dextID->isEqualTo(newdext->getIdentifier());
5403 assert(eq);
5404 }
5405
5406 if (newdext != NULL) {
5407 /*
5408 * Swap the catalog personalities.
5409 */
5410 new_personalities = newdext->copyPersonalitiesArray();
5411 olddext->updatePersonalitiesInCatalog(new_personalities.get());
5412 }
5413
5414 if (NULL != oldDextUniqueIdentifier) {
5415 oldDextUniqueIdentifier->retain();
5416 }
5417
5418 /*
5419 * Unload the dext.
5420 */
5421 result = olddext->unload();
5422 if (result != kOSReturnSuccess) {
5423 OSKextLog(NULL,
5424 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5425 "Cannot unload dext for upgrade %s: %d\n",
5426 dextID->getCStringNoCopy(), result);
5427 }
5428
5429 if (newdext != NULL) {
5430 /*
5431 * Swap the dexts on the OSKext dictionary.
5432 * This might free the dext.
5433 */
5434 sKextsByID->setObject(dextID, newdext);
5435 } else {
5436 /*
5437 * Remove the old dext
5438 */
5439 removeKext(olddext, true);
5440 }
5441
5442 /*
5443 * Inform userspace.
5444 */
5445 if (newdext != NULL) {
5446 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), newdext->getDextUniqueID());
5447 if (result != kOSReturnSuccess) {
5448 OSKextLog(NULL,
5449 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5450 "Cannot send upgrade notification for %s\n",
5451 dextID->getCStringNoCopy());
5452 }
5453 } else {
5454 // notify dext removal
5455 queueKextNotification(kKextRequestPredicateUnloadNotification,
5456 OSDynamicCast(OSString, dextID), oldDextUniqueIdentifier);
5457 }
5458
5459 OSSafeReleaseNULL(dextID);
5460 OSSafeReleaseNULL(oldDextUniqueIdentifier);
5461 }
5462
5463 /*
5464 * To be called with sKextLock held.
5465 * NOTE: this could unload the olddext.
5466 */
5467 bool
upgradeDext(OSKext * olddext,OSKext * newdext)5468 OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5469 {
5470 const char * dextIDCS = newdext->getIdentifierCString();
5471 __assert_only bool old_isDext = olddext->isDriverKit();
5472 __assert_only bool new_isDext = newdext->isDriverKit();
5473 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5474
5475 assert(old_isDext && new_isDext);
5476 assert(lock_held);
5477
5478 /*
5479 * New dext and old dext have the same ID.
5480 * We use this ID as key on the OSKext
5481 * dictionarys/arrays.
5482 */
5483 const OSSymbol * dextID = newdext->getIdentifier();
5484 __assert_only bool eq = dextID->isEqualTo(olddext->getIdentifier());
5485 assert(eq);
5486
5487 /*
5488 * Set this OSKect as to update.
5489 * Note that this flags will never be removed once set.
5490 * When a OSKext is marked, it will be substitued by a new
5491 * OSKext, and every subsystem having a reference on this
5492 * OSKext need to know they have check if they can use
5493 * this OSKext or look for a new one.
5494 */
5495 olddext->flags.dextToReplace = 1;
5496
5497 /*
5498 * Check if the current OSKext has any
5499 * userspace processes launched.
5500 * In this case we cannot upgrade and we have to
5501 * delay the upgrade until all processes
5502 * are done.
5503 */
5504 if (olddext->dextLaunchedCount == 0) {
5505 /*
5506 * Be sure that if there are no launched dexts, no
5507 * pending upgrades exist.
5508 * This is an error if it happens, as the decrement
5509 * should have removed the dext from sDriverKitToUpgradeByID
5510 * in case it reached 0.
5511 */
5512 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(dextID);
5513 if (pending_upgdare != NULL) {
5514 OSKextLog(NULL,
5515 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5516 "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5517 dextIDCS);
5518 goto out;
5519 }
5520
5521 replaceDextInternal(olddext, newdext);
5522 return true;
5523 }
5524
5525 out:
5526
5527 /*
5528 * Delay the upgrade.
5529 * Make the new dext available in sDriverKitToUpgradeByID.
5530 * In case there was already a pending upgrade, this will
5531 * overwrite it.
5532 */
5533 sDriverKitToUpgradeByID->setObject(dextID, newdext);
5534 return false;
5535 }
5536
5537 /*
5538 * To be called with sKextLock held.
5539 * NOTE: this could unload the dext.
5540 */
5541 bool
removeDext(OSKext * dext)5542 OSKext::removeDext(OSKext *dext)
5543 {
5544 __assert_only bool dext_isDext = dext->isDriverKit();
5545 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5546 IOReturn result;
5547
5548 assert(dext_isDext);
5549 assert(lock_held);
5550
5551 /*
5552 * Set this OSKext to be unloaded when all running instances exit.
5553 */
5554 dext->flags.dextToReplace = 1;
5555
5556 result = gIOCatalogue->terminateDriversForModule(
5557 dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5558 if (result != kOSReturnSuccess) {
5559 OSKextLog(dext,
5560 kOSKextLogErrorLevel |
5561 kOSKextLogKextBookkeepingFlag,
5562 "%s services failed to terminate - 0x%x.",
5563 dext->getIdentifierCString(), result);
5564 }
5565
5566 dext->removePersonalitiesFromCatalog();
5567 sDriverKitToUpgradeByID->removeObject(dext->getIdentifier());
5568
5569 /*
5570 * Check if the current OSKext has any
5571 * userspace processes launched.
5572 * In this case we cannot unload and we have to
5573 * delay the unload until all processes
5574 * are done.
5575 */
5576 if (dext->dextLaunchedCount == 0) {
5577 replaceDextInternal(dext, NULL);
5578 return true;
5579 }
5580
5581 return false;
5582 }
5583
5584 bool
incrementDextLaunchCount(OSKext * dext,OSData * dextUniqueIDToMatch)5585 OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5586 {
5587 bool ret = false;
5588 __assert_only bool isDext = dext->isDriverKit();
5589 assert(isDext);
5590
5591 const char * dextIDCS = dext->getIdentifierCString();
5592 OSData *myDextUniqueID = dext->getDextUniqueID();
5593
5594 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5595 OSKextLog(dext,
5596 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5597 "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5598 dextIDCS);
5599 return ret;
5600 }
5601
5602 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5603 const char *dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5604 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueIDToMatch, &dextUniqueIDToMatchCStringSize);
5605 assert(dextUniqueIDCString != NULL);
5606 assert(dextUniqueIDToMatchCString != NULL);
5607
5608 IORecursiveLockLock(sKextLock);
5609
5610 /*
5611 * Check that the dext we are referencing is the same
5612 * looked for the match.
5613 */
5614 if (myDextUniqueID->isEqualTo(dextUniqueIDToMatch)) {
5615 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5616 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5617 OSKextLog(dext,
5618 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5619 "Too many dexts launched for %s UniqueID %s\n",
5620 dextIDCS, dextUniqueIDCString);
5621 } else {
5622 dext->dextLaunchedCount++;
5623 ret = true;
5624
5625 OSKextLog(dext,
5626 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5627 "New dext launched for %s UniqueID %s",
5628 dextIDCS, dextUniqueIDCString);
5629 }
5630 } else {
5631 OSKextLog(dext,
5632 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5633 "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5634 dextIDCS, dextUniqueIDCString);
5635 }
5636 } else {
5637 OSKextLog(dext,
5638 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5639 "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5640 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5641 }
5642
5643 IORecursiveLockUnlock(sKextLock);
5644
5645 if (dextUniqueIDCString != NULL) {
5646 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5647 }
5648 if (dextUniqueIDToMatchCString != NULL) {
5649 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5650 }
5651 return ret;
5652 }
5653
5654 bool
decrementDextLaunchCount(OSString * bundleID)5655 OSKext::decrementDextLaunchCount(OSString *bundleID)
5656 {
5657 bool ret = false;
5658 const char * dextIDCS;
5659 OSData *myDextUniqueID;
5660 unsigned int dextUniqueIDCStringSize = 0;
5661 const char * dextUniqueIDCString = NULL;
5662 OSKext* dext = NULL;
5663
5664 if (!bundleID) {
5665 return ret;
5666 }
5667 dextIDCS = bundleID->getCStringNoCopy();
5668
5669 IORecursiveLockLock(sKextLock);
5670
5671 /*
5672 * Look for the dext with the bundle it. This
5673 * call is triggered only if a previous increment was
5674 * performed. It means that the dext could have not
5675 * been upgraded as its dextLaunchedCount was at least 1.
5676 * Because of this it still needs to be available
5677 * in sKextsByID.
5678 */
5679 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5680 if (!dext || !dext->isDriverKit()) {
5681 OSKextLog(NULL,
5682 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5683 "Cannot find dext for %s, cannot decrement dext launches\n",
5684 dextIDCS);
5685
5686 goto out_locked;
5687 }
5688
5689 myDextUniqueID = dext->getDextUniqueID();
5690 if (!myDextUniqueID) {
5691 OSKextLog(dext,
5692 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5693 "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5694 dextIDCS);
5695
5696 goto out_locked;
5697 }
5698 dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5699 assert(dextUniqueIDCString != NULL);
5700
5701 if (dext->dextLaunchedCount == 0) {
5702 OSKextLog(dext,
5703 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5704 "Over decrementing dext launch for %s UniqueID %s\n",
5705 dextIDCS, dextUniqueIDCString);
5706
5707 goto out_locked;
5708 }
5709
5710 dext->dextLaunchedCount--;
5711
5712 OSKextLog(dext,
5713 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5714 "Dext terminated for %s UniqueID %s",
5715 dextIDCS, dextUniqueIDCString);
5716
5717 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5718 /*
5719 * Find the upgraded dext.
5720 */
5721 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5722 if (newdext) {
5723 OSKextLog(dext,
5724 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5725 "Dext upgrade for %s UniqueID %s",
5726 dextIDCS, dextUniqueIDCString);
5727 replaceDextInternal(dext, newdext);
5728 /* NOTE dext could have been freed past this point */
5729
5730 sDriverKitToUpgradeByID->removeObject(dextIDCS);
5731 } else {
5732 OSKextLog(dext,
5733 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5734 "Dext unload for %s UniqueID %s",
5735 dextIDCS, dextUniqueIDCString);
5736 replaceDextInternal(dext, NULL);
5737 }
5738
5739 ret = true;
5740 }
5741 out_locked:
5742 IORecursiveLockUnlock(sKextLock);
5743
5744 if (dextUniqueIDCString != NULL) {
5745 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5746 }
5747
5748 return ret;
5749 }
5750
5751 /*********************************************************************
5752 *********************************************************************/
5753 #if defined (__arm__)
5754 #include <arm/arch.h>
5755 #endif
5756
5757 #if defined (__x86_64__)
5758 #define ARCHNAME "x86_64"
5759 #elif defined (__arm64__)
5760 #define ARCHNAME "arm64"
5761 #elif defined (__arm__)
5762
5763 #if defined (__ARM_ARCH_7S__)
5764 #define ARCHNAME "armv7s"
5765 #elif defined (__ARM_ARCH_7F__)
5766 #define ARCHNAME "armv7f"
5767 #elif defined (__ARM_ARCH_7K__)
5768 #define ARCHNAME "armv7k"
5769 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5770 #define ARCHNAME "armv7"
5771 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5772 #define ARCHNAME "armv6"
5773 #endif
5774
5775 #elif defined (__arm64__)
5776 #define ARCHNAME "arm64"
5777 #else
5778 #error architecture not supported
5779 #endif
5780
5781 #define ARCH_SEPARATOR_CHAR '_'
5782
5783 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)5784 makeHostArchKey(const char * key, size_t * keySizeOut)
5785 {
5786 char * result = NULL;
5787 size_t keyLength = strlen(key);
5788 size_t keySize;
5789
5790 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5791 */
5792 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5793 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5794
5795 if (!result) {
5796 goto finish;
5797 }
5798 strlcpy(result, key, keySize);
5799 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5800 result[keyLength] = '\0';
5801 strlcat(result, ARCHNAME, keySize);
5802 *keySizeOut = keySize;
5803
5804 finish:
5805 return result;
5806 }
5807
5808 /*********************************************************************
5809 *********************************************************************/
5810 OSObject *
getPropertyForHostArch(const char * key)5811 OSKext::getPropertyForHostArch(const char * key)
5812 {
5813 OSObject * result = NULL;// do not release
5814 size_t hostArchKeySize = 0;
5815 char * hostArchKey = NULL;// must kfree
5816
5817 if (!key || !infoDict) {
5818 goto finish;
5819 }
5820
5821 /* Some properties are not allowed to be arch-variant:
5822 * - Any CFBundle... property.
5823 * - OSBundleIsInterface.
5824 * - OSKernelResource.
5825 */
5826 if (STRING_HAS_PREFIX(key, "OS") ||
5827 STRING_HAS_PREFIX(key, "IO")) {
5828 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
5829 if (!hostArchKey) {
5830 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5831 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5832 "Allocation failure.");
5833 goto finish;
5834 }
5835 result = infoDict->getObject(hostArchKey);
5836 }
5837
5838 if (!result) {
5839 result = infoDict->getObject(key);
5840 }
5841
5842 finish:
5843 if (hostArchKey) {
5844 kfree_data(hostArchKey, hostArchKeySize);
5845 }
5846 return result;
5847 }
5848
5849 #if PRAGMA_MARK
5850 #pragma mark Load/Start/Stop/Unload
5851 #endif
5852
5853 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5854
5855 /*********************************************************************
5856 * sExcludeListByID is a dictionary with keys / values of:
5857 * key = bundleID string of kext we will not allow to load
5858 * value = version string(s) of the kext that is to be denied loading.
5859 * The version strings can be comma delimited. For example if kext
5860 * com.foocompany.fookext has two versions that we want to deny
5861 * loading then the version strings might look like:
5862 * 1.0.0, 1.0.1
5863 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5864 * not load the kext.
5865 *
5866 * Value may also be in the form of "LE 2.0.0" (version numbers
5867 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5868 * number less than 2.0.0 will not load)
5869 *
5870 * NOTE - we cannot use the characters "<=" or "<" because we have code
5871 * that serializes plists and treats '<' as a special character.
5872 *********************************************************************/
5873 bool
isInExcludeList(void)5874 OSKext::isInExcludeList(void)
5875 {
5876 OSString * versionString = NULL; // do not release
5877 char * versionCString = NULL; // do not free
5878 size_t i;
5879 boolean_t wantLessThan = false;
5880 boolean_t wantLessThanEqualTo = false;
5881 boolean_t isInExcludeList = true;
5882 char myBuffer[32];
5883
5884 IORecursiveLockLock(sKextLock);
5885
5886 if (!sExcludeListByID) {
5887 isInExcludeList = false;
5888 } else {
5889 /* look up by bundleID in our exclude list and if found get version
5890 * string (or strings) that we will not allow to load
5891 */
5892 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5893 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5894 isInExcludeList = false;
5895 }
5896 }
5897
5898 IORecursiveLockUnlock(sKextLock);
5899
5900 if (!isInExcludeList) {
5901 return false;
5902 }
5903
5904 /* parse version strings */
5905 versionCString = (char *) versionString->getCStringNoCopy();
5906
5907 /* look for "LT" or "LE" form of version string, must be in first two
5908 * positions.
5909 */
5910 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5911 wantLessThan = true;
5912 versionCString += 2;
5913 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5914 wantLessThanEqualTo = true;
5915 versionCString += 2;
5916 }
5917
5918 for (i = 0; *versionCString != 0x00; versionCString++) {
5919 /* skip whitespace */
5920 if (isWhiteSpace(*versionCString)) {
5921 continue;
5922 }
5923
5924 /* peek ahead for version string separator or null terminator */
5925 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5926 /* OK, we have a version string */
5927 myBuffer[i++] = *versionCString;
5928 myBuffer[i] = 0x00;
5929
5930 OSKextVersion excludeVers;
5931 excludeVers = OSKextParseVersionString(myBuffer);
5932
5933 if (wantLessThanEqualTo) {
5934 if (version <= excludeVers) {
5935 return true;
5936 }
5937 } else if (wantLessThan) {
5938 if (version < excludeVers) {
5939 return true;
5940 }
5941 } else if (version == excludeVers) {
5942 return true;
5943 }
5944
5945 /* reset for the next (if any) version string */
5946 i = 0;
5947 wantLessThan = false;
5948 wantLessThanEqualTo = false;
5949 } else {
5950 /* save valid version character */
5951 myBuffer[i++] = *versionCString;
5952
5953 /* make sure bogus version string doesn't overrun local buffer */
5954 if (i >= sizeof(myBuffer)) {
5955 break;
5956 }
5957 }
5958 }
5959
5960 return false;
5961 }
5962
5963 /*********************************************************************
5964 * sNonLoadableKextsByID is a dictionary with keys / values of:
5965 * key = bundleID string of kext we will not allow to load
5966 * value = boolean (true == loadable, false == not loadable)
5967 *
5968 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5969 * i.e., the value for the kext's bundleID will be false. All kexts in
5970 * the primary and system KCs will always be marked as "loadable."
5971 *
5972 * This list ultimately comes from kexts which have been uninstalled
5973 * in user space by deleting the kext from disk, but which have not
5974 * yet been removed from the AuxKC. Because the user could choose to
5975 * re-install the exact same version of the kext, we need to keep
5976 * a dictionary of boolean values so that user space only needs to
5977 * keep a simple list of "uninstalled" or "missing" bundles. When
5978 * a bundle is re-installed, the iokit daemon can use the
5979 * AucKCBundleAvailable predicate to set the individual kext's
5980 * availability to true.
5981 *********************************************************************/
5982 bool
isLoadable(void)5983 OSKext::isLoadable(void)
5984 {
5985 bool isLoadable = true;
5986
5987 if (kc_type != KCKindAuxiliary) {
5988 /* this filtering only applies to kexts in the auxkc */
5989 return true;
5990 }
5991
5992 IORecursiveLockLock(sKextLock);
5993
5994 if (sNonLoadableKextsByID) {
5995 /* look up by bundleID in our exclude list and if found get version
5996 * string (or strings) that we will not allow to load
5997 */
5998 OSBoolean *loadableVal;
5999 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
6000 if (loadableVal && !loadableVal->getValue()) {
6001 isLoadable = false;
6002 }
6003 }
6004 IORecursiveLockUnlock(sKextLock);
6005
6006 return isLoadable;
6007 }
6008
6009 /*********************************************************************
6010 *********************************************************************/
6011 /* static */
6012 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6013 OSKext::loadKextWithIdentifier(
6014 const char * kextIdentifierCString,
6015 Boolean allowDeferFlag,
6016 Boolean delayAutounloadFlag,
6017 OSKextExcludeLevel startOpt,
6018 OSKextExcludeLevel startMatchingOpt,
6019 OSArray * personalityNames)
6020 {
6021 OSReturn result = kOSReturnError;
6022 OSSharedPtr<OSString> kextIdentifier;
6023
6024 kextIdentifier = OSString::withCString(kextIdentifierCString);
6025 if (!kextIdentifier) {
6026 result = kOSKextReturnNoMemory;
6027 goto finish;
6028 }
6029 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
6030 NULL /* kextRef */,
6031 allowDeferFlag, delayAutounloadFlag,
6032 startOpt, startMatchingOpt, personalityNames);
6033
6034 finish:
6035 return result;
6036 }
6037
6038 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6039 OSKext::loadKextWithIdentifier(
6040 OSString * kextIdentifier,
6041 OSSharedPtr<OSObject> &kextRef,
6042 Boolean allowDeferFlag,
6043 Boolean delayAutounloadFlag,
6044 OSKextExcludeLevel startOpt,
6045 OSKextExcludeLevel startMatchingOpt,
6046 OSArray * personalityNames)
6047 {
6048 OSObject * kextRefRaw = NULL;
6049 OSReturn result;
6050
6051 result = loadKextWithIdentifier(kextIdentifier,
6052 &kextRefRaw,
6053 allowDeferFlag,
6054 delayAutounloadFlag,
6055 startOpt,
6056 startMatchingOpt,
6057 personalityNames);
6058 if ((kOSReturnSuccess == result) && kextRefRaw) {
6059 kextRef.reset(kextRefRaw, OSNoRetain);
6060 }
6061 return result;
6062 }
6063
6064 /*********************************************************************
6065 *********************************************************************/
6066 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6067 OSKext::loadKextWithIdentifier(
6068 OSString * kextIdentifier,
6069 OSObject ** kextRef,
6070 Boolean allowDeferFlag,
6071 Boolean delayAutounloadFlag,
6072 OSKextExcludeLevel startOpt,
6073 OSKextExcludeLevel startMatchingOpt,
6074 OSArray * personalityNames)
6075 {
6076 OSReturn result = kOSReturnError;
6077 OSReturn pingResult = kOSReturnError;
6078 OSKext * theKext = NULL; // do not release
6079 OSSharedPtr<OSDictionary> loadRequest;
6080 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6081
6082 if (kextRef) {
6083 *kextRef = NULL;
6084 }
6085
6086 IORecursiveLockLock(sKextLock);
6087
6088 if (!kextIdentifier) {
6089 result = kOSKextReturnInvalidArgument;
6090 goto finish;
6091 }
6092
6093 OSKext::recordIdentifierRequest(kextIdentifier);
6094
6095 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6096 if (!theKext) {
6097 if (!allowDeferFlag) {
6098 OSKextLog(/* kext */ NULL,
6099 kOSKextLogErrorLevel |
6100 kOSKextLogLoadFlag,
6101 "Can't load kext %s - not found.",
6102 kextIdentifier->getCStringNoCopy());
6103 goto finish;
6104 }
6105
6106 if (!sKernelRequestsEnabled) {
6107 OSKextLog(theKext,
6108 kOSKextLogErrorLevel |
6109 kOSKextLogLoadFlag,
6110 "Can't load kext %s - requests to user space are disabled.",
6111 kextIdentifier->getCStringNoCopy());
6112 result = kOSKextReturnDisabled;
6113 goto finish;
6114 }
6115
6116 /* Create a new request unless one is already sitting
6117 * in sKernelRequests for this bundle identifier
6118 */
6119 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6120 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6121 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
6122 loadRequest);
6123 if (result != kOSReturnSuccess) {
6124 goto finish;
6125 }
6126 if (!_OSKextSetRequestArgument(loadRequest.get(),
6127 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6128 result = kOSKextReturnNoMemory;
6129 goto finish;
6130 }
6131 if (!sKernelRequests->setObject(loadRequest.get())) {
6132 result = kOSKextReturnNoMemory;
6133 goto finish;
6134 }
6135
6136 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6137 result = kOSKextReturnNoMemory;
6138 goto finish;
6139 }
6140
6141 OSKextLog(theKext,
6142 kOSKextLogDebugLevel |
6143 kOSKextLogLoadFlag,
6144 "Kext %s not found; queued load request to user space.",
6145 kextIdentifier->getCStringNoCopy());
6146 }
6147
6148 pingResult = OSKext::pingIOKitDaemon();
6149 if (pingResult == kOSKextReturnDisabled) {
6150 OSKextLog(/* kext */ NULL,
6151 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
6152 kOSKextLogLoadFlag,
6153 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
6154 kextIdentifier->getCStringNoCopy());
6155 }
6156
6157 result = kOSKextReturnDeferred;
6158 goto finish;
6159 }
6160
6161 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
6162
6163 if (result != kOSReturnSuccess) {
6164 OSKextLog(theKext,
6165 kOSKextLogErrorLevel |
6166 kOSKextLogLoadFlag,
6167 "Failed to load kext %s (error 0x%x).",
6168 kextIdentifier->getCStringNoCopy(), (int)result);
6169
6170 if (theKext->kc_type == KCKindUnknown) {
6171 OSKext::removeKext(theKext,
6172 /* terminateService/removePersonalities */ true);
6173 }
6174 goto finish;
6175 }
6176
6177 if (delayAutounloadFlag) {
6178 OSKextLog(theKext,
6179 kOSKextLogProgressLevel |
6180 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6181 "Setting delayed autounload for %s.",
6182 kextIdentifier->getCStringNoCopy());
6183 theKext->flags.delayAutounload = 1;
6184 }
6185
6186 finish:
6187 if ((kOSReturnSuccess == result) && kextRef) {
6188 *kextRef = theKext;
6189 theKext->matchingRefCount++;
6190 theKext->retain();
6191 }
6192
6193 IORecursiveLockUnlock(sKextLock);
6194
6195 return result;
6196 }
6197
6198 /*********************************************************************
6199 *********************************************************************/
6200 /* static */
6201 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)6202 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
6203 {
6204 OSReturn result = kOSReturnError;
6205
6206 OSBoolean *delayAutounloadBool = NULL; // do not release
6207 OSNumber *startKextExcludeNum = NULL; // do not release
6208 OSNumber *startMatchingExcludeNum = NULL; // do not release
6209 OSArray *personalityNames = NULL; // do not release
6210
6211 /*
6212 * Default values for these options:
6213 * regular autounload behavior
6214 * start the kext
6215 * send all personalities to the catalog
6216 */
6217 Boolean delayAutounload = false;
6218 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
6219 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
6220
6221 IORecursiveLockLock(sKextLock);
6222
6223 OSKextLog(/* kext */ NULL,
6224 kOSKextLogDebugLevel |
6225 kOSKextLogIPCFlag,
6226 "Received kext KC load request from user space.");
6227
6228 /* Regardless of processing, the fact that we have gotten here means some
6229 * user-space program is up and talking to us, so we'll switch our kext
6230 * registration to reflect that.
6231 */
6232 if (!sUserLoadsActive) {
6233 OSKextLog(/* kext */ NULL,
6234 kOSKextLogProgressLevel |
6235 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6236 "Switching to late startup (user-space) kext loading policy.");
6237 sUserLoadsActive = true;
6238 }
6239
6240 delayAutounloadBool = OSDynamicCast(OSBoolean,
6241 _OSKextGetRequestArgument(requestDict,
6242 kKextRequestArgumentDelayAutounloadKey));
6243 startKextExcludeNum = OSDynamicCast(OSNumber,
6244 _OSKextGetRequestArgument(requestDict,
6245 kKextRequestArgumentStartExcludeKey));
6246 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6247 _OSKextGetRequestArgument(requestDict,
6248 kKextRequestArgumentStartMatchingExcludeKey));
6249 personalityNames = OSDynamicCast(OSArray,
6250 _OSKextGetRequestArgument(requestDict,
6251 kKextRequestArgumentPersonalityNamesKey));
6252
6253 if (delayAutounloadBool) {
6254 delayAutounload = delayAutounloadBool->getValue();
6255 }
6256 if (startKextExcludeNum) {
6257 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6258 }
6259 if (startMatchingExcludeNum) {
6260 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6261 }
6262
6263 OSKextLog(/* kext */ NULL,
6264 kOSKextLogProgressLevel |
6265 kOSKextLogIPCFlag,
6266 "Received request from user space to load KC kext %s.",
6267 theKext->getIdentifierCString());
6268
6269 /* this could be in the Auxiliary KC, so record the load request */
6270 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6271
6272 /*
6273 * Load the kext
6274 */
6275 result = theKext->load(startKextExcludeLevel,
6276 startMatchingExcludeLevel, personalityNames);
6277
6278 if (result != kOSReturnSuccess) {
6279 OSKextLog(theKext,
6280 kOSKextLogErrorLevel |
6281 kOSKextLogLoadFlag,
6282 "Failed to load kext %s (error 0x%x).",
6283 theKext->getIdentifierCString(), (int)result);
6284
6285 OSKext::removeKext(theKext,
6286 /* terminateService/removePersonalities */ true);
6287 goto finish;
6288 } else {
6289 OSKextLog(theKext,
6290 kOSKextLogProgressLevel |
6291 kOSKextLogLoadFlag,
6292 "Kext %s Loaded successfully from %s KC",
6293 theKext->getIdentifierCString(), theKext->getKCTypeString());
6294 }
6295
6296 if (delayAutounload) {
6297 OSKextLog(theKext,
6298 kOSKextLogProgressLevel |
6299 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6300 "Setting delayed autounload for %s.",
6301 theKext->getIdentifierCString());
6302 theKext->flags.delayAutounload = 1;
6303 }
6304
6305 finish:
6306 IORecursiveLockUnlock(sKextLock);
6307
6308 return result;
6309 }
6310
6311 /*********************************************************************
6312 *********************************************************************/
6313 /* static */
6314 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)6315 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6316 {
6317 OSReturn result = kOSReturnError;
6318 OSDictionary *anInfoDict = NULL; // do not release
6319
6320 anInfoDict = OSDynamicCast(OSDictionary,
6321 _OSKextGetRequestArgument(requestDict,
6322 kKextRequestArgumentCodelessInfoKey));
6323 if (anInfoDict == NULL) {
6324 OSKextLog(/* kext */ NULL,
6325 kOSKextLogErrorLevel |
6326 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6327 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6328 kextIdentifier->getCStringNoCopy());
6329 return kOSKextReturnInvalidArgument;
6330 }
6331
6332 IORecursiveLockLock(sKextLock);
6333
6334 OSKextLog(/* kext */ NULL,
6335 kOSKextLogProgressLevel |
6336 kOSKextLogIPCFlag,
6337 "Received request from user space to load codeless kext %s.",
6338 kextIdentifier->getCStringNoCopy());
6339
6340 {
6341 // instantiate a new kext, and don't hold a reference
6342 // (the kext subsystem will hold one implicitly)
6343 OSKextInitResult ret;
6344 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, &ret);
6345 if (!newKext) {
6346 /*
6347 * We might have failed to create a new OSKext
6348 * because the old one should still be used.
6349 * Check if that is the case.
6350 */
6351 if (ret != kOSKextInitFailure) {
6352 result = kOSReturnSuccess;
6353 goto finish;
6354 }
6355 OSKextLog(/* kext */ NULL,
6356 kOSKextLogErrorLevel |
6357 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6358 "Could not instantiate codeless kext.");
6359 result = kOSKextReturnNotLoadable;
6360 goto finish;
6361 }
6362 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
6363 OSKextLog(/* kext */ NULL,
6364 kOSKextLogErrorLevel |
6365 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6366 "Codeless kext identifiers don't match '%s' != '%s'",
6367 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6368
6369 OSKext::removeKext(newKext.get(), false);
6370 result = kOSKextReturnInvalidArgument;
6371 goto finish;
6372 }
6373
6374 /* Record the request for the codeless kext */
6375 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6376
6377 result = kOSReturnSuccess;
6378 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6379 result = newKext->sendPersonalitiesToCatalog(true, NULL);
6380 }
6381
6382 finish:
6383 IORecursiveLockUnlock(sKextLock);
6384
6385 return result;
6386 }
6387
6388 /*********************************************************************
6389 *********************************************************************/
6390 /* static */
6391 void
dropMatchingReferences(OSSet * kexts)6392 OSKext::dropMatchingReferences(
6393 OSSet * kexts)
6394 {
6395 IORecursiveLockLock(sKextLock);
6396 kexts->iterateObjects(^bool (OSObject * obj) {
6397 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6398 if (!thisKext) {
6399 return false;
6400 }
6401 thisKext->matchingRefCount--;
6402 return false;
6403 });
6404 IORecursiveLockUnlock(sKextLock);
6405 }
6406
6407 /*********************************************************************
6408 *********************************************************************/
6409 /* static */
6410 void
recordIdentifierRequest(OSString * kextIdentifier)6411 OSKext::recordIdentifierRequest(
6412 OSString * kextIdentifier)
6413 {
6414 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6415 bool fail = false;
6416
6417 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6418 goto finish;
6419 }
6420
6421 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6422 if (!kextIdentifierSymbol) {
6423 // xxx - this is really a basic alloc failure
6424 fail = true;
6425 goto finish;
6426 }
6427
6428 IORecursiveLockLock(sKextLock);
6429 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6430 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6431 fail = true;
6432 } else {
6433 // xxx - need to find a way to associate this whole func w/the kext
6434 OSKextLog(/* kext */ NULL,
6435 // xxx - check level
6436 kOSKextLogStepLevel |
6437 kOSKextLogArchiveFlag,
6438 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6439 kextIdentifier->getCStringNoCopy());
6440 }
6441 }
6442 IORecursiveLockUnlock(sKextLock);
6443
6444 finish:
6445
6446 if (fail) {
6447 OSKextLog(/* kext */ NULL,
6448 kOSKextLogErrorLevel |
6449 kOSKextLogArchiveFlag,
6450 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6451 kextIdentifier->getCStringNoCopy());
6452 }
6453 return;
6454 }
6455
6456 /*********************************************************************
6457 *********************************************************************/
6458 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6459 OSKext::load(
6460 OSKextExcludeLevel startOpt,
6461 OSKextExcludeLevel startMatchingOpt,
6462 OSArray * personalityNames)
6463 {
6464 OSReturn result = kOSReturnError;
6465 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6466 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6467 unsigned int i, count;
6468 Boolean alreadyLoaded = false;
6469 OSKext * lastLoadedKext = NULL; // do not release
6470
6471 if (isInExcludeList()) {
6472 OSKextLog(this,
6473 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6474 kOSKextLogLoadFlag,
6475 "Kext %s is in exclude list, not loadable",
6476 getIdentifierCString());
6477
6478 result = kOSKextReturnNotLoadable;
6479 goto finish;
6480 }
6481 if (!isLoadable()) {
6482 OSKextLog(this,
6483 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6484 kOSKextLogLoadFlag,
6485 "Kext %s is not loadable",
6486 getIdentifierCString());
6487
6488 result = kOSKextReturnNotLoadable;
6489 goto finish;
6490 }
6491
6492 if (isLoaded()) {
6493 alreadyLoaded = true;
6494 result = kOSReturnSuccess;
6495
6496 OSKextLog(this,
6497 kOSKextLogDebugLevel |
6498 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6499 "Kext %s is already loaded.",
6500 getIdentifierCString());
6501 goto loaded;
6502 }
6503
6504 #if CONFIG_MACF
6505 /*
6506 * On kxld and on embedded, only call into the MAC hook when on a
6507 * user thread, for access control over userspace kextloads.
6508 *
6509 * On non-kxld systems, additionally check the MAC hook for kexts in
6510 * the Pageable and Aux KCs, regardless of whether we are on a user
6511 * thread or not. This means on Apple silicon devices that the MAC
6512 * hook will only be useful to block 3rd party kexts loaded via
6513 * matching, and any kexts loaded from userspace kextloads.
6514 *
6515 * Note that this should _not_ be called on kexts loaded from the
6516 * kernel bootstrap thread as the kernel proc's cred struct is not
6517 * yet initialized! This won't happen on macOS because all the kexts
6518 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6519 */
6520 if (current_task() != kernel_task
6521 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6522 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6523 #endif
6524 ) {
6525 int macCheckResult = 0;
6526 kauth_cred_t cred = NULL;
6527
6528 cred = kauth_cred_get_with_ref();
6529 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
6530 kauth_cred_unref(&cred);
6531
6532 if (macCheckResult != 0) {
6533 result = kOSReturnError;
6534 OSKextLog(this,
6535 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6536 "Failed to load kext %s (MAC policy error 0x%x).",
6537 getIdentifierCString(), macCheckResult);
6538 goto finish;
6539 }
6540 }
6541 #endif /* CONFIG_MACF */
6542
6543 if (!sLoadEnabled) {
6544 OSKextLog(this,
6545 kOSKextLogErrorLevel |
6546 kOSKextLogLoadFlag,
6547 "Kext loading is disabled (attempt to load kext %s).",
6548 getIdentifierCString());
6549 result = kOSKextReturnDisabled;
6550 goto finish;
6551 }
6552
6553 /* If we've pushed the next available load tag to the invalid value,
6554 * we can't load any more kexts.
6555 */
6556 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6557 OSKextLog(this,
6558 kOSKextLogErrorLevel |
6559 kOSKextLogLoadFlag,
6560 "Can't load kext %s - no more load tags to assign.",
6561 getIdentifierCString());
6562 result = kOSKextReturnNoResources;
6563 goto finish;
6564 }
6565
6566 /* This is a bit of a hack, because we shouldn't be handling
6567 * personalities within the load function.
6568 */
6569 if (!declaresExecutable()) {
6570 /* There is a special case where a non-executable kext can be loaded: the
6571 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6572 * load its metadata into the global data structures, if appropriate
6573 */
6574 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6575 boolean_t updated = updateExcludeList(infoDict.get());
6576 if (updated) {
6577 OSKextLog(this,
6578 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6579 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6580 }
6581 }
6582
6583 if (isDriverKit()) {
6584 if (loadTag == 0) {
6585 sLoadedDriverKitKexts->setObject(this);
6586 loadTag = sNextLoadTag++;
6587 }
6588 }
6589 result = kOSReturnSuccess;
6590 goto loaded;
6591 }
6592
6593 /* Are we in safe boot?
6594 */
6595 if (sSafeBoot && !isLoadableInSafeBoot()) {
6596 OSKextLog(this,
6597 kOSKextLogErrorLevel |
6598 kOSKextLogLoadFlag,
6599 "Can't load kext %s - not loadable during safe boot.",
6600 getIdentifierCString());
6601 result = kOSKextReturnBootLevel;
6602 goto finish;
6603 }
6604
6605 OSKextLog(this,
6606 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6607 "Loading kext %s.",
6608 getIdentifierCString());
6609
6610 #if !VM_MAPPED_KEXTS
6611 if (isPrelinked() == false) {
6612 OSKextLog(this,
6613 kOSKextLogErrorLevel |
6614 kOSKextLogLoadFlag,
6615 "Can't load kext %s - not in a kext collection.",
6616 getIdentifierCString());
6617 result = kOSKextReturnDisabled;
6618 goto finish;
6619 }
6620 #endif /* defined(__x86_64__) */
6621
6622 #if CONFIG_KXLD
6623 if (!sKxldContext) {
6624 kern_return_t kxldResult;
6625 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6626 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6627 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6628 if (kxldResult) {
6629 OSKextLog(this,
6630 kOSKextLogErrorLevel |
6631 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6632 "Can't load kext %s - failed to create link context.",
6633 getIdentifierCString());
6634 result = kOSKextReturnNoMemory;
6635 goto finish;
6636 }
6637 }
6638 #endif // CONFIG_KXLD
6639
6640 /* We only need to resolve dependencies once for the whole graph, but
6641 * resolveDependencies will just return if there's no work to do, so it's
6642 * safe to call it more than once.
6643 */
6644 if (!resolveDependencies()) {
6645 // xxx - check resolveDependencies() for log msg
6646 OSKextLog(this,
6647 kOSKextLogErrorLevel |
6648 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6649 "Can't load kext %s - failed to resolve library dependencies.",
6650 getIdentifierCString());
6651 result = kOSKextReturnDependencies;
6652 goto finish;
6653 }
6654
6655 /* If we are excluding just the kext being loaded now (and not its
6656 * dependencies), drop the exclusion level to none so dependencies
6657 * start and/or add their personalities.
6658 */
6659 if (dependenciesStartOpt == kOSKextExcludeKext) {
6660 dependenciesStartOpt = kOSKextExcludeNone;
6661 }
6662
6663 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6664 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6665 }
6666
6667 /* Load the dependencies, recursively.
6668 */
6669 count = getNumDependencies();
6670 for (i = 0; i < count; i++) {
6671 OSKext * dependency = OSDynamicCast(OSKext,
6672 dependencies->getObject(i));
6673 if (dependency == NULL) {
6674 OSKextLog(this,
6675 kOSKextLogErrorLevel |
6676 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6677 "Internal error loading kext %s; dependency disappeared.",
6678 getIdentifierCString());
6679 result = kOSKextReturnInternalError;
6680 goto finish;
6681 }
6682
6683 /* Dependencies must be started accorting to the opt,
6684 * but not given the personality names of the main kext.
6685 */
6686 result = dependency->load(dependenciesStartOpt,
6687 dependenciesStartMatchingOpt,
6688 /* personalityNames */ NULL);
6689 if (result != KERN_SUCCESS) {
6690 OSKextLog(this,
6691 kOSKextLogErrorLevel |
6692 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6693 "Dependency %s of kext %s failed to load.",
6694 dependency->getIdentifierCString(),
6695 getIdentifierCString());
6696
6697 OSKext::removeKext(dependency,
6698 /* terminateService/removePersonalities */ true);
6699 result = kOSKextReturnDependencyLoadError;
6700
6701 goto finish;
6702 }
6703 }
6704
6705 result = loadExecutable();
6706 if (result != KERN_SUCCESS) {
6707 goto finish;
6708 }
6709
6710 pendingPgoHead.next = &pendingPgoHead;
6711 pendingPgoHead.prev = &pendingPgoHead;
6712
6713 // The kernel PRNG is not initialized when the first kext is
6714 // loaded, so use early random
6715 uuid_generate_early_random(instance_uuid);
6716 account = IOMallocType(OSKextAccount);
6717
6718 account->loadTag = kmod_info->id;
6719 account->site.refcount = 0;
6720 account->site.flags = VM_TAG_KMOD;
6721
6722 #if DEVELOPMENT || DEBUG
6723 /* Setup the task reference group. */
6724 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6725 "task_%s", getIdentifierCString());
6726 account->task_refgrp.grp_name = account->task_refgrp_name;
6727 account->task_refgrp.grp_parent = &task_external_refgrp;
6728 account->task_refgrp.grp_flags = OS_REFGRP_F_ALWAYS_ENABLED;
6729 os_ref_log_init(&account->task_refgrp);
6730 #endif /* DEVELOPMENT || DEBUG */
6731
6732 account->kext = this;
6733 if (gIOSurfaceIdentifier == bundleID) {
6734 vm_tag_alloc(&account->site);
6735 gIOSurfaceTag = account->site.tag;
6736 }
6737
6738 flags.loaded = true;
6739
6740 /* Add the kext to the list of loaded kexts and update the kmod_info
6741 * struct to point to that of the last loaded kext (which is the way
6742 * it's always been done, though I'd rather do them in order now).
6743 */
6744 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6745 sLoadedKexts->setObject(this);
6746
6747 /* Keep the kernel itself out of the kmod list.
6748 */
6749 if (lastLoadedKext->isKernel()) {
6750 lastLoadedKext = NULL;
6751 }
6752
6753 if (lastLoadedKext) {
6754 kmod_info->next = lastLoadedKext->kmod_info;
6755 }
6756
6757 notifyKextLoadObservers(this, kmod_info);
6758
6759 /* Make the global kmod list point at the just-loaded kext. Note that the
6760 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6761 * although we do report it in kextstat these days by using the newer
6762 * OSArray of loaded kexts, which does contain it.
6763 *
6764 * (The OSKext object representing the kernel doesn't even have a kmod_info
6765 * struct, though I suppose we could stick a pointer to it from the
6766 * static struct in OSRuntime.cpp.)
6767 */
6768 kmod = kmod_info;
6769
6770 /* Save the list of loaded kexts in case we panic.
6771 */
6772 OSKext::saveLoadedKextPanicList();
6773
6774 if (isExecutable()) {
6775 OSKext::updateLoadedKextSummaries();
6776 savePanicString(/* isLoading */ true);
6777
6778 #if CONFIG_DTRACE
6779 registerWithDTrace();
6780 #else
6781 jettisonLinkeditSegment();
6782 #endif /* CONFIG_DTRACE */
6783
6784 #if !VM_MAPPED_KEXTS
6785 /* If there is a page (or more) worth of padding after the end
6786 * of the last data section but before the end of the data segment
6787 * then free it in the same manner the LinkeditSegment is freed
6788 */
6789 jettisonDATASegmentPadding();
6790 #endif
6791 }
6792
6793 loaded:
6794 if (isExecutable() && !flags.started) {
6795 if (startOpt == kOSKextExcludeNone) {
6796 result = start();
6797 if (result != kOSReturnSuccess) {
6798 OSKextLog(this,
6799 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6800 "Kext %s start failed (result 0x%x).",
6801 getIdentifierCString(), result);
6802 result = kOSKextReturnStartStopError;
6803 }
6804 }
6805 }
6806
6807 /* If not excluding matching, send the personalities to the kernel.
6808 * This never affects the result of the load operation.
6809 * This is a bit of a hack, because we shouldn't be handling
6810 * personalities within the load function.
6811 */
6812 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6813 result = sendPersonalitiesToCatalog(true, personalityNames);
6814 }
6815
6816 finish:
6817
6818 if (result != kOSReturnSuccess) {
6819 OSKextLog(this,
6820 kOSKextLogErrorLevel |
6821 kOSKextLogLoadFlag,
6822 "Kext %s failed to load (0x%x).",
6823 getIdentifierCString(), (int)result);
6824 } else if (!alreadyLoaded) {
6825 OSKextLog(this,
6826 kOSKextLogProgressLevel |
6827 kOSKextLogLoadFlag,
6828 "Kext %s loaded.",
6829 getIdentifierCString());
6830
6831 queueKextNotification(kKextRequestPredicateLoadNotification,
6832 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
6833 }
6834 return result;
6835 }
6836
6837 #if CONFIG_KXLD
6838 /*********************************************************************
6839 *
6840 *********************************************************************/
6841 static char *
strdup(const char * string)6842 strdup(const char * string)
6843 {
6844 char * result = NULL;
6845 size_t size;
6846
6847 if (!string) {
6848 goto finish;
6849 }
6850
6851 size = 1 + strlen(string);
6852 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6853 if (!result) {
6854 goto finish;
6855 }
6856
6857 memcpy(result, string, size);
6858
6859 finish:
6860 return result;
6861 }
6862 #endif // CONFIG_KXLD
6863
6864 /*********************************************************************
6865 *
6866 *********************************************************************/
6867
6868 kernel_section_t *
lookupSection(const char * segname,const char * secname)6869 OSKext::lookupSection(const char *segname, const char *secname)
6870 {
6871 kernel_section_t * found_section = NULL;
6872 kernel_mach_header_t * mh = NULL;
6873 kernel_segment_command_t * seg = NULL;
6874 kernel_section_t * sec = NULL;
6875
6876 if (!linkedExecutable) {
6877 return NULL;
6878 }
6879
6880 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6881
6882 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6883 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
6884 continue;
6885 }
6886
6887 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6888 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
6889 found_section = sec;
6890 goto out;
6891 }
6892 }
6893 }
6894
6895 out:
6896 return found_section;
6897 }
6898
6899 /*********************************************************************
6900 *
6901 *********************************************************************/
6902
6903 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6904 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6905 {
6906 OSReturn result = kOSKextReturnBadData;
6907 kernel_mach_header_t * mh = NULL;
6908 kernel_segment_command_t * seg = NULL;
6909 kernel_segment_command_t * linkeditSeg = NULL;
6910 kernel_section_t * sec = NULL;
6911 char * linkeditBase = NULL;
6912 bool haveLinkeditBase = false;
6913 char * relocBase = NULL;
6914 bool haveRelocBase = false;
6915 struct dysymtab_command * dysymtab = NULL;
6916 struct linkedit_data_command * segmentSplitInfo = NULL;
6917 struct symtab_command * symtab = NULL;
6918 kernel_nlist_t * sym = NULL;
6919 struct relocation_info * reloc = NULL;
6920 uint32_t i = 0;
6921 int reloc_size;
6922 vm_offset_t new_kextsize;
6923 kc_format format = KCFormatUnknown;
6924
6925 if (linkedExecutable == NULL || flags.builtin) {
6926 result = kOSReturnSuccess;
6927 goto finish;
6928 }
6929
6930 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6931 if (kernel_mach_header_is_in_fileset(mh)) {
6932 // kexts in filesets are slid as part of collection sliding
6933 result = kOSReturnSuccess;
6934 goto finish;
6935 }
6936
6937 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6938
6939 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6940 if (!seg->vmaddr) {
6941 continue;
6942 }
6943
6944 seg->vmaddr = ml_static_slide(seg->vmaddr);
6945
6946 #if KASLR_KEXT_DEBUG
6947 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6948 seg->segname,
6949 (unsigned long)ml_static_unslide(seg->vmaddr),
6950 (unsigned long)seg->vmaddr);
6951 #endif
6952
6953 if (!haveRelocBase) {
6954 relocBase = (char *) seg->vmaddr;
6955 haveRelocBase = true;
6956 }
6957 if (!strcmp(seg->segname, "__LINKEDIT")) {
6958 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6959 haveLinkeditBase = true;
6960 linkeditSeg = seg;
6961 }
6962 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6963 sec->addr = ml_static_slide(sec->addr);
6964
6965 #if KASLR_KEXT_DEBUG
6966 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6967 sec->sectname,
6968 (unsigned long)ml_static_unslide(sec->addr),
6969 (unsigned long)sec->addr);
6970 #endif
6971 }
6972 }
6973
6974 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6975
6976 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6977
6978 if (symtab != NULL && doCoalescedSlides == false) {
6979 /* Some pseudo-kexts have symbol tables without segments.
6980 * Ignore them. */
6981 if (symtab->nsyms > 0 && haveLinkeditBase) {
6982 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6983 for (i = 0; i < symtab->nsyms; i++) {
6984 if (sym[i].n_type & N_STAB) {
6985 continue;
6986 }
6987 sym[i].n_value = ml_static_slide(sym[i].n_value);
6988
6989 #if KASLR_KEXT_DEBUG
6990 #define MAX_SYMS_TO_LOG 5
6991 if (i < MAX_SYMS_TO_LOG) {
6992 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6993 (unsigned long)ml_static_unslide(sym[i].n_value),
6994 (unsigned long)sym[i].n_value);
6995 }
6996 #endif
6997 }
6998 }
6999 }
7000
7001 if (dysymtab != NULL && doCoalescedSlides == false) {
7002 if (dysymtab->nextrel > 0) {
7003 OSKextLog(this,
7004 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7005 kOSKextLogLinkFlag,
7006 "Sliding kext %s: External relocations found.",
7007 getIdentifierCString());
7008 goto finish;
7009 }
7010
7011 if (dysymtab->nlocrel > 0) {
7012 if (!haveLinkeditBase) {
7013 OSKextLog(this,
7014 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7015 kOSKextLogLinkFlag,
7016 "Sliding kext %s: No linkedit segment.",
7017 getIdentifierCString());
7018 goto finish;
7019 }
7020
7021 if (!haveRelocBase) {
7022 OSKextLog(this,
7023 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7024 kOSKextLogLinkFlag,
7025 #if __x86_64__
7026 "Sliding kext %s: No writable segments.",
7027 #else
7028 "Sliding kext %s: No segments.",
7029 #endif
7030 getIdentifierCString());
7031 goto finish;
7032 }
7033
7034 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
7035 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
7036
7037 for (i = 0; i < dysymtab->nlocrel; i++) {
7038 if (reloc[i].r_extern != 0
7039 || reloc[i].r_type != 0
7040 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
7041 ) {
7042 OSKextLog(this,
7043 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7044 kOSKextLogLinkFlag,
7045 "Sliding kext %s: Unexpected relocation found.",
7046 getIdentifierCString());
7047 goto finish;
7048 }
7049 if (reloc[i].r_pcrel != 0) {
7050 continue;
7051 }
7052 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
7053 *relocAddr = ml_static_slide(*relocAddr);
7054
7055 #if KASLR_KEXT_DEBUG
7056 #define MAX_DYSYMS_TO_LOG 5
7057 if (i < MAX_DYSYMS_TO_LOG) {
7058 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
7059 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
7060 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
7061 }
7062 #endif
7063 }
7064
7065 /* We should free these relocations, not just delete the reference to them.
7066 * <rdar://problem/10535549> Free relocations from PIE kexts.
7067 *
7068 * For now, we do not free LINKEDIT for kexts with split segments.
7069 */
7070 new_kextsize = round_page(kmod_info->size - reloc_size);
7071 if (new_kextsize > UINT_MAX) {
7072 OSKextLog(this,
7073 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7074 kOSKextLogLinkFlag,
7075 "Kext %s: new kext size is too large.",
7076 getIdentifierCString());
7077 goto finish;
7078 }
7079 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
7080 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
7081 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
7082 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
7083 size_t bytes_remaining = endofkext - endofrelocInfo;
7084 OSSharedPtr<OSData> new_osdata;
7085
7086 /* fix up symbol offsets if they are after the dsymtab local relocs */
7087 if (symtab) {
7088 if (dysymtab->locreloff < symtab->symoff) {
7089 symtab->symoff -= reloc_size;
7090 }
7091 if (dysymtab->locreloff < symtab->stroff) {
7092 symtab->stroff -= reloc_size;
7093 }
7094 }
7095 if (dysymtab->locreloff < dysymtab->extreloff) {
7096 dysymtab->extreloff -= reloc_size;
7097 }
7098
7099 /* move data behind reloc info down to new offset */
7100 if (endofrelocInfo < endofkext) {
7101 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
7102 }
7103
7104 /* Create a new OSData for the smaller kext object and reflect
7105 * new linkedit segment size.
7106 */
7107 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
7108 linkeditSeg->filesize = linkeditSeg->vmsize;
7109
7110 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
7111 if (new_osdata) {
7112 /* Fix up kmod info and linkedExecutable.
7113 */
7114 kmod_info->size = new_kextsize;
7115 /*
7116 * Fileset KCs are mapped as a whole by iBoot.
7117 * Individual kext executables should not be unmapped
7118 * by xnu.
7119 * Doing so may result in panics like rdar://85419651
7120 */
7121 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7122 new_osdata->setDeallocFunction(NULL);
7123 } else { // Not from a Fileset KC
7124 #if VM_MAPPED_KEXTS
7125 new_osdata->setDeallocFunction(osdata_kext_free);
7126 #else
7127 new_osdata->setDeallocFunction(osdata_phys_free);
7128 #endif
7129 }
7130 linkedExecutable->setDeallocFunction(NULL);
7131 linkedExecutable = os::move(new_osdata);
7132
7133 #if VM_MAPPED_KEXTS
7134 kext_free(new_endofkext, (endofkext - new_endofkext));
7135 #else
7136 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
7137 #endif
7138 }
7139 }
7140 dysymtab->nlocrel = 0;
7141 dysymtab->locreloff = 0;
7142 }
7143 }
7144
7145 result = kOSReturnSuccess;
7146 finish:
7147 return result;
7148 }
7149
7150 /*********************************************************************
7151 * called only by load()
7152 *********************************************************************/
7153 OSReturn
loadExecutable()7154 OSKext::loadExecutable()
7155 {
7156 OSReturn result = kOSReturnError;
7157 OSSharedPtr<OSArray> linkDependencies;
7158 uint32_t num_kmod_refs = 0;
7159 OSData * theExecutable = NULL; // do not release
7160 OSString * versString = NULL; // do not release
7161 const char * versCString = NULL; // do not free
7162 const char * string = NULL; // do not free
7163
7164 #if CONFIG_KXLD
7165 unsigned int i;
7166 uint32_t numDirectDependencies = 0;
7167 kern_return_t kxldResult;
7168 KXLDDependency * kxlddeps = NULL; // must kfree
7169 uint32_t num_kxlddeps = 0;
7170 struct mach_header ** kxldHeaderPtr = NULL; // do not free
7171 struct mach_header * kxld_header = NULL; // xxx - need to free here?
7172 #endif // CONFIG_KXLD
7173
7174 /* We need the version string for a variety of bits below.
7175 */
7176 versString = OSDynamicCast(OSString,
7177 getPropertyForHostArch(kCFBundleVersionKey));
7178 if (!versString) {
7179 goto finish;
7180 }
7181 versCString = versString->getCStringNoCopy();
7182
7183 if (isKernelComponent()) {
7184 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
7185 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
7186 OSKextLog(this,
7187 kOSKextLogErrorLevel |
7188 kOSKextLogLoadFlag,
7189 "Kernel component %s has incorrect version %s; "
7190 "expected %s.",
7191 getIdentifierCString(),
7192 versCString, KERNEL6_VERSION);
7193 result = kOSKextReturnInternalError;
7194 goto finish;
7195 } else if (strcmp(versCString, osrelease)) {
7196 OSKextLog(this,
7197 kOSKextLogErrorLevel |
7198 kOSKextLogLoadFlag,
7199 "Kernel component %s has incorrect version %s; "
7200 "expected %s.",
7201 getIdentifierCString(),
7202 versCString, osrelease);
7203 result = kOSKextReturnInternalError;
7204 goto finish;
7205 }
7206 }
7207 }
7208
7209 #if defined(__x86_64__) || defined(__i386__)
7210 if (flags.resetSegmentsFromVnode) {
7211 /* Fixup the chains and slide the mach headers */
7212 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
7213
7214 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
7215 result = kOSKextReturnValidation;
7216 goto finish;
7217 }
7218 }
7219 #endif //(__x86_64__) || defined(__i386__)
7220
7221 if (isPrelinked()) {
7222 goto register_kmod;
7223 }
7224
7225 /* <rdar://problem/21444003> all callers must be entitled */
7226 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7227 OSKextLog(this,
7228 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7229 "Not entitled to link kext '%s'",
7230 getIdentifierCString());
7231 result = kOSKextReturnNotPrivileged;
7232 goto finish;
7233 }
7234
7235 theExecutable = getExecutable();
7236 if (!theExecutable) {
7237 if (declaresExecutable()) {
7238 OSKextLog(this,
7239 kOSKextLogErrorLevel |
7240 kOSKextLogLoadFlag,
7241 "Can't load kext %s - executable is missing.",
7242 getIdentifierCString());
7243 result = kOSKextReturnValidation;
7244 goto finish;
7245 }
7246 goto register_kmod;
7247 }
7248
7249 if (isInterface()) {
7250 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
7251 if (executableCopy) {
7252 setLinkedExecutable(executableCopy.get());
7253 }
7254 goto register_kmod;
7255 }
7256
7257 #if CONFIG_KXLD
7258 numDirectDependencies = getNumDependencies();
7259
7260 if (flags.hasBleedthrough) {
7261 linkDependencies = dependencies;
7262 } else {
7263 linkDependencies = OSArray::withArray(dependencies.get());
7264 if (!linkDependencies) {
7265 OSKextLog(this,
7266 kOSKextLogErrorLevel |
7267 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7268 "Can't allocate link dependencies to load kext %s.",
7269 getIdentifierCString());
7270 goto finish;
7271 }
7272
7273 for (i = 0; i < numDirectDependencies; ++i) {
7274 OSKext * dependencyKext = OSDynamicCast(OSKext,
7275 dependencies->getObject(i));
7276 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7277 }
7278 }
7279
7280 num_kxlddeps = linkDependencies->getCount();
7281 if (!num_kxlddeps) {
7282 OSKextLog(this,
7283 kOSKextLogErrorLevel |
7284 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7285 "Can't load kext %s - it has no library dependencies.",
7286 getIdentifierCString());
7287 goto finish;
7288 }
7289
7290 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7291 if (!kxlddeps) {
7292 OSKextLog(this,
7293 kOSKextLogErrorLevel |
7294 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7295 "Can't allocate link context to load kext %s.",
7296 getIdentifierCString());
7297 goto finish;
7298 }
7299 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7300
7301 for (i = 0; i < num_kxlddeps; ++i) {
7302 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7303
7304 if (dependency->isInterface()) {
7305 OSKext *interfaceTargetKext = NULL; //do not release
7306 OSData * interfaceTarget = NULL; //do not release
7307
7308 if (dependency->isKernelComponent()) {
7309 interfaceTargetKext = sKernelKext;
7310 interfaceTarget = sKernelKext->linkedExecutable.get();
7311 } else {
7312 interfaceTargetKext = OSDynamicCast(OSKext,
7313 dependency->dependencies->getObject(0));
7314
7315 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7316 }
7317
7318 if (!interfaceTarget) {
7319 // panic?
7320 goto finish;
7321 }
7322
7323 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7324 * it will be useful to have them in the debugger.
7325 * strdup() failing isn't critical right here so we don't check that.
7326 */
7327 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7328 kxlddeps[i].kext_size = interfaceTarget->getLength();
7329 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7330
7331 if (dependency->linkedExecutable != NULL) {
7332 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7333 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7334 } else {
7335 kxlddeps[i].interface = (u_char *) NULL;
7336 kxlddeps[i].interface_size = 0;
7337 }
7338 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7339 } else {
7340 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7341 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7342 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7343 }
7344
7345 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7346 }
7347
7348 kxldHeaderPtr = &kxld_header;
7349
7350 #if DEBUG
7351 OSKextLog(this,
7352 kOSKextLogExplicitLevel |
7353 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7354 "Kext %s - calling kxld_link_file:\n"
7355 " kxld_context: %p\n"
7356 " executable: %p executable_length: %d\n"
7357 " user_data: %p\n"
7358 " kxld_dependencies: %p num_dependencies: %d\n"
7359 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7360 getIdentifierCString(), sKxldContext,
7361 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7362 this, kxlddeps, num_kxlddeps,
7363 kxldHeaderPtr, &kmod_info);
7364 #endif
7365
7366 /* After this call, the linkedExecutable instance variable
7367 * should exist.
7368 */
7369 kxldResult = kxld_link_file(sKxldContext,
7370 (u_char *)theExecutable->getBytesNoCopy(),
7371 theExecutable->getLength(),
7372 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7373 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7374
7375 if (kxldResult != KERN_SUCCESS) {
7376 // xxx - add kxldResult here?
7377 OSKextLog(this,
7378 kOSKextLogErrorLevel |
7379 kOSKextLogLoadFlag,
7380 "Can't load kext %s - link failed.",
7381 getIdentifierCString());
7382 result = kOSKextReturnLinkError;
7383 goto finish;
7384 }
7385
7386 /* We've written data & instructions into kernel memory, so flush the data
7387 * cache and invalidate the instruction cache.
7388 * I/D caches are coherent on x86
7389 */
7390 #if !defined(__i386__) && !defined(__x86_64__)
7391 flush_dcache(kmod_info->address, kmod_info->size, false);
7392 invalidate_icache(kmod_info->address, kmod_info->size, false);
7393 #endif
7394
7395 #else // !CONFIG_KXLD
7396 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7397 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7398 result = kOSKextReturnLinkError;
7399 goto finish;
7400 #endif // CONFIG_KXLD
7401
7402 register_kmod:
7403
7404 if (isInterface()) {
7405 /* Whip up a fake kmod_info entry for the interface kext.
7406 */
7407 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7408 if (!kmod_info) {
7409 result = KERN_MEMORY_ERROR;
7410 goto finish;
7411 }
7412
7413 /* A pseudokext has almost nothing in its kmod_info struct.
7414 */
7415 kmod_info->info_version = KMOD_INFO_VERSION;
7416
7417 /* An interface kext doesn't have a linkedExecutable, so save a
7418 * copy of the UUID out of the original executable via copyUUID()
7419 * while we still have the original executable.
7420 */
7421 interfaceUUID = copyUUID();
7422 }
7423
7424 kmod_info->id = loadTag = sNextLoadTag++;
7425 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7426
7427 /* Stamp the bundle ID and version from the OSKext over anything
7428 * resident inside the kmod_info.
7429 */
7430 string = getIdentifierCString();
7431 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
7432
7433 string = versCString;
7434 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
7435
7436 /* Add the dependencies' kmod_info structs as kmod_references.
7437 */
7438 num_kmod_refs = getNumDependencies();
7439 if (num_kmod_refs) {
7440 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7441 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7442 if (!kmod_info->reference_list) {
7443 result = KERN_MEMORY_ERROR;
7444 goto finish;
7445 }
7446 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7447 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7448 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7449 ref->info = refKext->kmod_info;
7450 ref->info->reference_count++;
7451
7452 if (refIndex + 1 < num_kmod_refs) {
7453 ref->next = kmod_info->reference_list + refIndex + 1;
7454 }
7455 }
7456 }
7457
7458 if (kmod_info->hdr_size > UINT32_MAX) {
7459 OSKextLog(this,
7460 kOSKextLogErrorLevel |
7461 kOSKextLogLoadFlag,
7462 #if __LP64__
7463 "Kext %s header size is too large (%lu > UINT32_MAX).",
7464 #else
7465 "Kext %s header size is too large (%u > UINT32_MAX).",
7466 #endif
7467 kmod_info->name,
7468 kmod_info->hdr_size);
7469 result = KERN_FAILURE;
7470 goto finish;
7471 }
7472
7473 if (kmod_info->size > UINT32_MAX) {
7474 OSKextLog(this,
7475 kOSKextLogErrorLevel |
7476 kOSKextLogLoadFlag,
7477 #if __LP64__
7478 "Kext %s size is too large (%lu > UINT32_MAX).",
7479 #else
7480 "Kext %s size is too large (%u > UINT32_MAX).",
7481 #endif
7482 kmod_info->name,
7483 kmod_info->size);
7484 result = KERN_FAILURE;
7485 goto finish;
7486 }
7487
7488 if (!isInterface() && linkedExecutable) {
7489 OSKextLog(this,
7490 kOSKextLogProgressLevel |
7491 kOSKextLogLoadFlag,
7492 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7493 kmod_info->name,
7494 (unsigned)kmod_info->size / PAGE_SIZE,
7495 (unsigned long)ml_static_unslide(kmod_info->address),
7496 (unsigned)kmod_info->id);
7497 }
7498
7499 /* VM protections and wiring for the Aux KC are done at collection loading time */
7500 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7501 /* if prelinked and primary KC, VM protections are already set */
7502 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
7503 if (result != KERN_SUCCESS) {
7504 goto finish;
7505 }
7506 }
7507
7508 #if KASAN
7509 if (linkedExecutable) {
7510 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7511 linkedExecutable->getLength(), getIdentifierCString());
7512 }
7513 #else
7514 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7515 OSKextLog(this,
7516 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7517 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7518 getIdentifierCString()
7519 );
7520 result = KERN_FAILURE;
7521 goto finish;
7522 }
7523 #endif
7524
7525 result = kOSReturnSuccess;
7526
7527 finish:
7528
7529 #if CONFIG_KXLD
7530 /* Clear up locally allocated dependency info.
7531 */
7532 for (i = 0; i < num_kxlddeps; ++i) {
7533 size_t size;
7534
7535 if (kxlddeps[i].kext_name) {
7536 size = 1 + strlen(kxlddeps[i].kext_name);
7537 kfree_data(kxlddeps[i].kext_name, size);
7538 }
7539 if (kxlddeps[i].interface_name) {
7540 size = 1 + strlen(kxlddeps[i].interface_name);
7541 kfree_data(kxlddeps[i].interface_name, size);
7542 }
7543 }
7544 if (kxlddeps) {
7545 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7546 }
7547 #endif // CONFIG_KXLD
7548
7549 /* We no longer need the unrelocated executable (which the linker
7550 * has altered anyhow).
7551 */
7552 setExecutable(NULL);
7553
7554 if (result != kOSReturnSuccess) {
7555 OSKextLog(this,
7556 kOSKextLogErrorLevel |
7557 kOSKextLogLoadFlag,
7558 "Failed to load executable for kext %s.",
7559 getIdentifierCString());
7560
7561 if (kmod_info && kmod_info->reference_list) {
7562 kfree_type(kmod_reference_t, num_kmod_refs,
7563 kmod_info->reference_list);
7564 }
7565 if (isInterface()) {
7566 kfree_type(kmod_info_t, kmod_info);
7567 kmod_info = NULL;
7568 }
7569 if (kc_type == KCKindUnknown) {
7570 kmod_info = NULL;
7571 if (linkedExecutable) {
7572 linkedExecutable.reset();
7573 }
7574 }
7575 }
7576
7577 return result;
7578 }
7579
7580 /* static */
7581 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)7582 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7583 {
7584 kernel_segment_command_t *linkeditseg = NULL;
7585
7586 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
7587 if (linkeditseg == NULL) {
7588 panic("FileSet booted with no Linkedit segment");
7589 }
7590
7591 #if VM_MAPPED_KEXTS
7592 /* BootKC on x86_64 is not vm mapped */
7593 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7594
7595 OSKextLog(/* kext */ NULL,
7596 kOSKextLogProgressLevel |
7597 kOSKextLogGeneralFlag,
7598 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7599 linkeditseg->vmaddr, linkeditseg->vmsize);
7600 #else
7601 /* BootKC on arm64 is not vm mapped, but is slid */
7602 #if !CONFIG_SPTM
7603 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7604 #else
7605 vm_offset_t linkedit_vmaddr = linkeditseg->vmaddr;
7606 #endif
7607
7608 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7609
7610 OSKextLog(/* kext */ NULL,
7611 kOSKextLogProgressLevel |
7612 kOSKextLogGeneralFlag,
7613 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7614 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7615 #endif /* VM_MAPPED_KEXTS */
7616 }
7617
7618 /*********************************************************************
7619 * The linkedit segment is used by the kext linker for dependency
7620 * resolution, and by dtrace for probe initialization. We can free it
7621 * for non-library kexts, since no kexts depend on non-library kexts
7622 * by definition, once dtrace has been initialized.
7623 *********************************************************************/
7624 void
jettisonLinkeditSegment(void)7625 OSKext::jettisonLinkeditSegment(void)
7626 {
7627 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7628 kernel_segment_command_t * linkedit = NULL;
7629 vm_offset_t start;
7630 vm_size_t linkeditsize, kextsize;
7631 OSSharedPtr<OSData> data;
7632 kc_format format = KCFormatUnknown;
7633
7634 if (isInFileset()) {
7635 return;
7636 }
7637
7638 #if NO_KEXTD
7639 /* We can free symbol tables for all embedded kexts because we don't
7640 * support runtime kext linking.
7641 */
7642 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7643 #else
7644 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7645 #endif
7646 goto finish;
7647 }
7648
7649 /* Find the linkedit segment. If it's not the last segment, then freeing
7650 * it will fragment the kext into multiple VM regions, which OSKext is not
7651 * designed to handle, so we'll have to skip it.
7652 */
7653 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
7654 if (!linkedit) {
7655 goto finish;
7656 }
7657
7658 if (round_page(kmod_info->address + kmod_info->size) !=
7659 round_page(linkedit->vmaddr + linkedit->vmsize)) {
7660 goto finish;
7661 }
7662
7663 /* Create a new OSData for the smaller kext object.
7664 */
7665 linkeditsize = round_page(linkedit->vmsize);
7666 kextsize = kmod_info->size - linkeditsize;
7667 start = linkedit->vmaddr;
7668
7669 if (kextsize > UINT_MAX) {
7670 goto finish;
7671 }
7672 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
7673 if (!data) {
7674 goto finish;
7675 }
7676
7677 /* Fix the kmod info and linkedExecutable.
7678 */
7679 kmod_info->size = kextsize;
7680
7681 /*
7682 * Fileset KCs are mapped as a whole by iBoot.
7683 * Individual kext executables should not be unmapped by xnu
7684 * Doing so may result in panics like rdar://85419651
7685 */
7686 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7687 data->setDeallocFunction(NULL);
7688 } else { // Not from a Fileset KC
7689 #if VM_MAPPED_KEXTS
7690 data->setDeallocFunction(osdata_kext_free);
7691 #else
7692 data->setDeallocFunction(osdata_phys_free);
7693 #endif
7694 }
7695 linkedExecutable->setDeallocFunction(NULL);
7696 linkedExecutable = os::move(data);
7697 flags.jettisonLinkeditSeg = 1;
7698
7699 /* Free the linkedit segment.
7700 */
7701 #if VM_MAPPED_KEXTS
7702 kext_free(start, linkeditsize);
7703 #else
7704 ml_static_mfree(start, linkeditsize);
7705 #endif
7706
7707 finish:
7708 return;
7709 }
7710
7711 /*********************************************************************
7712 * If there are whole pages that are unused betweem the last section
7713 * of the DATA segment and the end of the DATA segment then we can free
7714 * them
7715 *********************************************************************/
7716 void
7717 OSKext::jettisonDATASegmentPadding(void)
7718 {
7719 kernel_mach_header_t * mh;
7720 kernel_segment_command_t * dataSeg;
7721 kernel_section_t * sec, * lastSec;
7722 vm_offset_t dataSegEnd, lastSecEnd;
7723 vm_size_t padSize;
7724
7725 if (flags.builtin) {
7726 return;
7727 }
7728 mh = (kernel_mach_header_t *)kmod_info->address;
7729
7730 if (isInFileset()) {
7731 return;
7732 }
7733
7734 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
7735 if (dataSeg == NULL) {
7736 return;
7737 }
7738
7739 lastSec = NULL;
7740 sec = firstsect(dataSeg);
7741 while (sec != NULL) {
7742 lastSec = sec;
7743 sec = nextsect(dataSeg, sec);
7744 }
7745
7746 if (lastSec == NULL) {
7747 return;
7748 }
7749
7750 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
7751 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
7752 return;
7753 }
7754
7755 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7756 lastSecEnd = round_page(lastSec->addr + lastSec->size);
7757
7758 if (dataSegEnd <= lastSecEnd) {
7759 return;
7760 }
7761
7762 padSize = dataSegEnd - lastSecEnd;
7763
7764 if (padSize >= PAGE_SIZE) {
7765 #if VM_MAPPED_KEXTS
7766 kext_free(lastSecEnd, padSize);
7767 #else
7768 ml_static_mfree(lastSecEnd, padSize);
7769 #endif
7770 }
7771 }
7772
7773 /*********************************************************************
7774 *********************************************************************/
7775 void
7776 OSKext::setLinkedExecutable(OSData * anExecutable)
7777 {
7778 if (linkedExecutable) {
7779 panic("Attempt to set linked executable on kext "
7780 "that already has one (%s).\n",
7781 getIdentifierCString());
7782 }
7783 linkedExecutable.reset(anExecutable, OSRetain);
7784 return;
7785 }
7786
7787 #if CONFIG_DTRACE
7788 /*********************************************************************
7789 * Go through all loaded kexts and tell them to register with dtrace.
7790 * The instance method only registers if necessary.
7791 *********************************************************************/
7792 /* static */
7793 void
7794 OSKext::registerKextsWithDTrace(void)
7795 {
7796 uint32_t count = sLoadedKexts->getCount();
7797 uint32_t i;
7798
7799 IORecursiveLockLock(sKextLock);
7800
7801 for (i = 0; i < count; i++) {
7802 OSKext * thisKext = NULL; // do not release
7803
7804 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7805 if (!thisKext || !thisKext->isExecutable()) {
7806 continue;
7807 }
7808
7809 thisKext->registerWithDTrace();
7810 }
7811
7812 IORecursiveLockUnlock(sKextLock);
7813
7814 return;
7815 }
7816
7817 extern "C" {
7818 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7819 extern int (*dtrace_modunload)(struct kmod_info *);
7820 };
7821
7822 /*********************************************************************
7823 *********************************************************************/
7824 void
7825 OSKext::registerWithDTrace(void)
7826 {
7827 /* Register kext with dtrace. A dtrace_modload failure should not
7828 * prevent a kext from loading, so we ignore the return code.
7829 */
7830 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7831 uint32_t modflag = 0;
7832 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
7833
7834 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7835 if (forceInit == kOSBooleanTrue) {
7836 OSKextLog(this,
7837 kOSKextLogBasicLevel |
7838 kOSKextLogGeneralFlag,
7839 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7840 getIdentifierCString());
7841 forceInit = kOSBooleanFalse;
7842 }
7843 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7844 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7845 }
7846
7847 if (forceInit == kOSBooleanTrue) {
7848 modflag |= KMOD_DTRACE_FORCE_INIT;
7849 }
7850 if (flags.builtin) {
7851 modflag |= KMOD_DTRACE_STATIC_KEXT;
7852 }
7853
7854 (void)(*dtrace_modload)(kmod_info, modflag);
7855 flags.dtraceInitialized = true;
7856 jettisonLinkeditSegment();
7857 }
7858 return;
7859 }
7860 /*********************************************************************
7861 *********************************************************************/
7862 void
7863 OSKext::unregisterWithDTrace(void)
7864 {
7865 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7866 * prevent a kext from loading, so we ignore the return code.
7867 */
7868 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7869 (void)(*dtrace_modunload)(kmod_info);
7870 flags.dtraceInitialized = false;
7871 }
7872 return;
7873 }
7874 #endif /* CONFIG_DTRACE */
7875
7876
7877 /*********************************************************************
7878 * called only by loadExecutable()
7879 *********************************************************************/
7880 #if !VM_MAPPED_KEXTS
7881 #if defined(__arm__) || defined(__arm64__)
7882 static inline kern_return_t
7883 OSKext_protect(
7884 kernel_mach_header_t *kext_mh,
7885 vm_map_t map,
7886 vm_map_offset_t start,
7887 vm_map_size_t size,
7888 vm_prot_t new_prot,
7889 boolean_t set_max,
7890 kc_kind_t kc_type)
7891 {
7892 vm_map_offset_t end = start + size;
7893
7894 #pragma unused(kext_mh,map,kc_type)
7895 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7896 assert(start <= end);
7897 if (start >= end) {
7898 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7899 } else if (set_max) {
7900 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7901 } else {
7902 return ml_static_protect(start, size, new_prot);
7903 }
7904 }
7905
7906 static inline kern_return_t
7907 OSKext_wire(
7908 kernel_mach_header_t *kext_mh,
7909 vm_map_t map,
7910 vm_map_offset_t start,
7911 vm_map_offset_t end,
7912 vm_prot_t access_type,
7913 boolean_t user_wire,
7914 kc_kind_t kc_type)
7915 {
7916 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7917 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7918 }
7919 #else
7920 #error Unrecognized architecture
7921 #endif
7922 #else
7923 static inline kern_return_t
7924 OSKext_protect(
7925 kernel_mach_header_t *kext_mh,
7926 vm_map_t map,
7927 vm_map_offset_t start,
7928 vm_map_size_t size,
7929 vm_prot_t new_prot,
7930 boolean_t set_max,
7931 kc_kind_t kc_type)
7932 {
7933 vm_map_offset_t end = start + size;
7934
7935 if (start == end) { // 10538581
7936 return KERN_SUCCESS;
7937 }
7938 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7939 /*
7940 * XXX: This will probably need to be different for AuxKC and
7941 * pageableKC!
7942 */
7943 return ml_static_protect(start, size, new_prot);
7944 }
7945 return mach_vm_protect(map, start, size, set_max, new_prot);
7946 }
7947
7948 static inline kern_return_t
7949 OSKext_wire(
7950 kernel_mach_header_t *kext_mh,
7951 vm_map_t map,
7952 vm_map_offset_t start,
7953 vm_map_offset_t end,
7954 vm_prot_t access_type,
7955 boolean_t user_wire,
7956 kc_kind_t kc_type)
7957 {
7958 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7959 /* TODO: we may need to hook this for the pageableKC */
7960 return KERN_SUCCESS;
7961 }
7962 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7963 }
7964 #endif
7965
7966 OSReturn
7967 OSKext::setVMAttributes(bool protect, bool wire)
7968 {
7969 vm_map_t kext_map = NULL;
7970 kernel_segment_command_t * seg = NULL;
7971 vm_map_offset_t start_protect = 0;
7972 vm_map_offset_t start_wire = 0;
7973 vm_map_offset_t end_protect = 0;
7974 vm_map_size_t size_protect = 0;
7975 vm_map_offset_t end_wire = 0;
7976 OSReturn result = kOSReturnError;
7977
7978 if (isInterface() || !declaresExecutable() || flags.builtin) {
7979 result = kOSReturnSuccess;
7980 goto finish;
7981 }
7982
7983 /* Get the kext's vm map */
7984 kext_map = kext_get_vm_map(kmod_info);
7985 if (!kext_map) {
7986 result = KERN_MEMORY_ERROR;
7987 goto finish;
7988 }
7989
7990 #if !VM_MAPPED_KEXTS
7991 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7992 /* This is a split kext in a prelinked kernelcache; we'll let the
7993 * platform code take care of protecting it. It is already wired.
7994 */
7995 /* TODO: Should this still allow protections for the first segment
7996 * to go through, in the event that we have a mix of split and
7997 * unsplit kexts?
7998 */
7999 result = KERN_SUCCESS;
8000 goto finish;
8001 }
8002
8003 if (isInFileset() && kc_type != KCKindPageable) {
8004 // kexts in filesets have protections setup as part of collection loading
8005 result = KERN_SUCCESS;
8006 goto finish;
8007 }
8008 #endif
8009
8010 /* Protect the headers as read-only; they do not need to be wired */
8011 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8012 kext_map, kmod_info->address,
8013 kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
8014 : KERN_SUCCESS;
8015 if (result != KERN_SUCCESS) {
8016 goto finish;
8017 }
8018
8019 /* Set the VM protections and wire down each of the segments */
8020 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8021 while (seg) {
8022 #if __arm__
8023 /* We build all ARM kexts, so we can ensure they are aligned */
8024 assert((seg->vmaddr & PAGE_MASK) == 0);
8025 assert((seg->vmsize & PAGE_MASK) == 0);
8026 #endif
8027
8028 /*
8029 * For the non page aligned segments, the range calculation for protection
8030 * and wiring differ as follows:
8031 *
8032 * Protection: The non page aligned data at the start or at the end of the
8033 * segment is excluded from the protection. This exclusion is needed to make
8034 * sure OSKext_protect is not called twice on same page, if the page is shared
8035 * between two segments.
8036 *
8037 * Wiring: The non page aligned data at the start or at the end of the
8038 * segment is included in the wiring range, this inclusion is needed to make sure
8039 * all the data of the segment is wired.
8040 */
8041 start_protect = round_page(seg->vmaddr);
8042 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
8043 size_protect = end_protect - start_protect;
8044
8045 start_wire = trunc_page(seg->vmaddr);
8046 end_wire = round_page(seg->vmaddr + seg->vmsize);
8047
8048 /*
8049 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
8050 * across kexts and data from kexts is not page aligned
8051 */
8052 if (protect && (end_protect > start_protect) &&
8053 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
8054 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
8055 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
8056 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8057 kext_map, start_protect, size_protect, seg->maxprot, TRUE, kc_type);
8058 if (result != KERN_SUCCESS) {
8059 OSKextLog(this,
8060 kOSKextLogErrorLevel |
8061 kOSKextLogLoadFlag,
8062 "Kext %s failed to set maximum VM protections "
8063 "for segment %s - 0x%x.",
8064 getIdentifierCString(), seg->segname, (int)result);
8065 goto finish;
8066 }
8067
8068 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8069 kext_map, start_protect, size_protect, seg->initprot, FALSE, kc_type);
8070 if (result != KERN_SUCCESS) {
8071 OSKextLog(this,
8072 kOSKextLogErrorLevel |
8073 kOSKextLogLoadFlag,
8074 "Kext %s failed to set initial VM protections "
8075 "for segment %s - 0x%x.",
8076 getIdentifierCString(), seg->segname, (int)result);
8077 goto finish;
8078 }
8079 }
8080
8081 if (segmentShouldBeWired(seg) && wire) {
8082 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
8083 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
8084 if (result != KERN_SUCCESS) {
8085 goto finish;
8086 }
8087 }
8088
8089 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8090 }
8091
8092 finish:
8093 return result;
8094 }
8095
8096 /*********************************************************************
8097 *********************************************************************/
8098 boolean_t
8099 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
8100 {
8101 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
8102 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
8103 }
8104
8105 /*********************************************************************
8106 *********************************************************************/
8107 OSReturn
8108 OSKext::validateKextMapping(bool startFlag)
8109 {
8110 OSReturn result = kOSReturnError;
8111 const char * whichOp = startFlag ? "start" : "stop";
8112 kern_return_t kern_result = 0;
8113 vm_map_t kext_map = NULL;
8114 kernel_segment_command_t * seg = NULL;
8115 mach_vm_address_t address = 0;
8116 mach_vm_size_t size = 0;
8117 uint32_t depth = 0;
8118 uint64_t kext_segbase = 0;
8119 uint64_t kext_segsize = 0;
8120 mach_msg_type_number_t count;
8121 vm_region_submap_short_info_data_64_t info;
8122 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
8123
8124 if (flags.builtin) {
8125 return kOSReturnSuccess;
8126 }
8127
8128 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
8129 bzero(&info, sizeof(info));
8130
8131 // xxx - do we need a distinct OSReturn value for these or is "bad data"
8132 // xxx - sufficient?
8133
8134 /* Verify that the kmod_info and start/stop pointers are non-NULL.
8135 */
8136 if (!kmod_info) {
8137 OSKextLog(this,
8138 kOSKextLogErrorLevel |
8139 kOSKextLogLoadFlag,
8140 "Kext %s - NULL kmod_info pointer.",
8141 getIdentifierCString());
8142 result = kOSKextReturnBadData;
8143 goto finish;
8144 }
8145
8146 if (startFlag) {
8147 address = (mach_vm_address_t)kmod_info->start;
8148 } else {
8149 address = (mach_vm_address_t)kmod_info->stop;
8150 }
8151
8152 if (!address) {
8153 OSKextLog(this,
8154 kOSKextLogErrorLevel |
8155 kOSKextLogLoadFlag,
8156 "Kext %s - NULL module %s pointer.",
8157 getIdentifierCString(), whichOp);
8158 result = kOSKextReturnBadData;
8159 goto finish;
8160 }
8161
8162 kext_map = kext_get_vm_map(kmod_info);
8163 depth = (kernel_map == kext_map) ? 1 : 2;
8164 if (isInFileset()) {
8165 #if defined(HAS_APPLE_PAC)
8166 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
8167 #endif /* defined(HAS_APPLE_PAC) */
8168 }
8169
8170 /* Verify that the start/stop function lies within the kext's address range.
8171 */
8172 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
8173 isInFileset()) {
8174 /* This will likely be how we deal with split kexts; walk the segments to
8175 * check that the function lies inside one of the segments of this kext.
8176 */
8177 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8178 seg != NULL;
8179 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
8180 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
8181 kext_segbase = seg->vmaddr;
8182 kext_segsize = seg->vmsize;
8183 break;
8184 }
8185 }
8186
8187 if (!seg) {
8188 OSKextLog(this,
8189 kOSKextLogErrorLevel |
8190 kOSKextLogLoadFlag,
8191 "Kext %s module %s pointer is outside of kext range "
8192 "(%s %p - kext starts at %p).",
8193 getIdentifierCString(),
8194 whichOp,
8195 whichOp,
8196 (void *)(((uintptr_t)address) - kext_slide),
8197 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
8198 result = kOSKextReturnBadData;
8199 goto finish;
8200 }
8201
8202 seg = NULL;
8203 } else {
8204 if (address < kmod_info->address + kmod_info->hdr_size ||
8205 kmod_info->address + kmod_info->size <= address) {
8206 OSKextLog(this,
8207 kOSKextLogErrorLevel |
8208 kOSKextLogLoadFlag,
8209 "Kext %s module %s pointer is outside of kext range "
8210 "(%s %p - kext at %p-%p).",
8211 getIdentifierCString(),
8212 whichOp,
8213 whichOp,
8214 (void *)(((uintptr_t)address) - kext_slide),
8215 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
8216 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
8217 result = kOSKextReturnBadData;
8218 goto finish;
8219 }
8220 }
8221
8222 /* Only do these checks before calling the start function;
8223 * If anything goes wrong with the mapping while the kext is running,
8224 * we'll likely have panicked well before any attempt to stop the kext.
8225 */
8226 if (startFlag) {
8227 if (!isInFileset() || kc_type != KCKindPrimary) {
8228 /*
8229 * Verify that the start/stop function is executable.
8230 */
8231 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
8232 (vm_region_recurse_info_t)&info, &count);
8233 if (kern_result != KERN_SUCCESS) {
8234 OSKextLog(this,
8235 kOSKextLogErrorLevel |
8236 kOSKextLogLoadFlag,
8237 "Kext %s - bad %s pointer %p.",
8238 getIdentifierCString(),
8239 whichOp, (void *)ml_static_unslide(address));
8240 result = kOSKextReturnBadData;
8241 goto finish;
8242 }
8243 } else {
8244 /*
8245 * Since kexts loaded from the primary KC are held in memory
8246 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8247 * discover that memory's protection flags. Instead, we need to
8248 * get that information from the kernel pmap itself. Above, we
8249 * (potentially) saved the size of the segment in which the address
8250 * in question was located. If we have a non-zero size, verify
8251 * that all pages in the (address, address + kext_segsize) range
8252 * are marked executable. If we somehow did not record the size
8253 * (or the base) just verify the single page that includes the address.
8254 */
8255 if (kext_segbase == 0 || kext_segsize == 0) {
8256 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8257 kext_segsize = PAGE_SIZE;
8258 }
8259 }
8260
8261 #if VM_MAPPED_KEXTS
8262 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8263 ((isInFileset() && kc_type == KCKindPrimary) &&
8264 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8265 OSKextLog(this,
8266 kOSKextLogErrorLevel |
8267 kOSKextLogLoadFlag,
8268 "Kext %s - memory region containing module %s function "
8269 "is not executable.",
8270 getIdentifierCString(), whichOp);
8271 result = kOSKextReturnBadData;
8272 goto finish;
8273 }
8274 #endif
8275
8276 /* Verify that the kext's segments are backed by physical memory.
8277 */
8278 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8279 while (seg) {
8280 if (!verifySegmentMapping(seg)) {
8281 result = kOSKextReturnBadData;
8282 goto finish;
8283 }
8284
8285 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8286 }
8287 }
8288
8289 result = kOSReturnSuccess;
8290 finish:
8291 return result;
8292 }
8293
8294 /*********************************************************************
8295 *********************************************************************/
8296 boolean_t
8297 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8298 {
8299 mach_vm_address_t address = 0;
8300
8301 if (seg->vmsize > UINT32_MAX) {
8302 return false;
8303 }
8304
8305 if (!segmentShouldBeWired(seg)) {
8306 return true;
8307 }
8308
8309 for (address = seg->vmaddr;
8310 address < round_page(seg->vmaddr + seg->vmsize);
8311 address += PAGE_SIZE) {
8312 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
8313 OSKextLog(this,
8314 kOSKextLogErrorLevel |
8315 kOSKextLogLoadFlag,
8316 "Kext %s - page %p is not backed by physical memory.",
8317 getIdentifierCString(),
8318 (void *)address);
8319 return false;
8320 }
8321 }
8322
8323 return true;
8324 }
8325
8326 /*********************************************************************
8327 *********************************************************************/
8328 static void
8329 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8330 {
8331 uint64_t stamp = 0;
8332 firehose_tracepoint_id_u trace_id;
8333 struct firehose_trace_uuid_info_s uuid_info_s;
8334 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8335 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8336 OSSharedPtr<OSData> uuid_data;
8337
8338 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
8339 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8340
8341 uuid_data = aKext->copyTextUUID();
8342 if (uuid_data) {
8343 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
8344 }
8345
8346 uuid_info->ftui_size = size;
8347 if (aKext->isDriverKit()) {
8348 uuid_info->ftui_address = address;
8349 } else {
8350 uuid_info->ftui_address = ml_static_unslide(address);
8351 }
8352 os_log_encoded_metadata(trace_id, stamp, uuid_info, uuid_info_len);
8353 return;
8354 }
8355
8356 void
8357 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8358 {
8359 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
8360 }
8361
8362 /*********************************************************************
8363 *********************************************************************/
8364 OSReturn
8365 OSKext::start(bool startDependenciesFlag)
8366 {
8367 OSReturn result = kOSReturnError;
8368 kern_return_t (* startfunc)(kmod_info_t *, void *);
8369 unsigned int i, count;
8370 void * kmodStartData = NULL;
8371
8372 if (isStarted() || isInterface() || isKernelComponent()) {
8373 result = kOSReturnSuccess;
8374 goto finish;
8375 }
8376
8377 if (!isLoaded()) {
8378 OSKextLog(this,
8379 kOSKextLogErrorLevel |
8380 kOSKextLogLoadFlag,
8381 "Attempt to start nonloaded kext %s.",
8382 getIdentifierCString());
8383 result = kOSKextReturnInvalidArgument;
8384 goto finish;
8385 }
8386
8387 if (!sLoadEnabled) {
8388 OSKextLog(this,
8389 kOSKextLogErrorLevel |
8390 kOSKextLogLoadFlag,
8391 "Kext loading is disabled (attempt to start kext %s).",
8392 getIdentifierCString());
8393 result = kOSKextReturnDisabled;
8394 goto finish;
8395 }
8396
8397 result = validateKextMapping(/* start? */ true);
8398 if (result != kOSReturnSuccess) {
8399 goto finish;
8400 }
8401
8402 startfunc = kmod_info->start;
8403
8404 count = getNumDependencies();
8405 for (i = 0; i < count; i++) {
8406 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8407 if (dependency == NULL) {
8408 OSKextLog(this,
8409 kOSKextLogErrorLevel |
8410 kOSKextLogLoadFlag,
8411 "Kext %s start - internal error, dependency disappeared.",
8412 getIdentifierCString());
8413 goto finish;
8414 }
8415 if (!dependency->isStarted()) {
8416 if (startDependenciesFlag) {
8417 OSReturn dependencyResult =
8418 dependency->start(startDependenciesFlag);
8419 if (dependencyResult != KERN_SUCCESS) {
8420 OSKextLog(this,
8421 kOSKextLogErrorLevel |
8422 kOSKextLogLoadFlag,
8423 "Kext %s start - dependency %s failed to start (error 0x%x).",
8424 getIdentifierCString(),
8425 dependency->getIdentifierCString(),
8426 dependencyResult);
8427 goto finish;
8428 }
8429 } else {
8430 OSKextLog(this,
8431 kOSKextLogErrorLevel |
8432 kOSKextLogLoadFlag,
8433 "Not starting %s - dependency %s not started yet.",
8434 getIdentifierCString(),
8435 dependency->getIdentifierCString());
8436 result = kOSKextReturnStartStopError; // xxx - make new return?
8437 goto finish;
8438 }
8439 }
8440 }
8441
8442 OSKextLog(this,
8443 kOSKextLogDetailLevel |
8444 kOSKextLogLoadFlag,
8445 "Kext %s calling module start function.",
8446 getIdentifierCString());
8447
8448 flags.starting = 1;
8449
8450 // Drop a log message so logd can grab the needed information to decode this kext
8451 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
8452 result = OSRuntimeInitializeCPP(this);
8453 if (result == KERN_SUCCESS) {
8454 result = startfunc(kmod_info, kmodStartData);
8455 }
8456
8457 flags.starting = 0;
8458
8459 /* On success overlap the setting of started/starting. On failure just
8460 * clear starting.
8461 */
8462 if (result == KERN_SUCCESS) {
8463 flags.started = 1;
8464
8465 // xxx - log start error from kernel?
8466 OSKextLog(this,
8467 kOSKextLogProgressLevel |
8468 kOSKextLogLoadFlag,
8469 "Kext %s is now started.",
8470 getIdentifierCString());
8471 } else {
8472 invokeOrCancelRequestCallbacks(
8473 /* result not actually used */ kOSKextReturnStartStopError,
8474 /* invokeFlag */ false);
8475 OSKextLog(this,
8476 kOSKextLogWarningLevel |
8477 kOSKextLogLoadFlag,
8478 "Kext %s did not start (return code 0x%x).",
8479 getIdentifierCString(), result);
8480 }
8481
8482 finish:
8483 return result;
8484 }
8485
8486 /*********************************************************************
8487 *********************************************************************/
8488 /* static */
8489 bool
8490 OSKext::canUnloadKextWithIdentifier(
8491 OSString * kextIdentifier,
8492 bool checkClassesFlag)
8493 {
8494 bool result = false;
8495 OSKext * aKext = NULL; // do not release
8496
8497 IORecursiveLockLock(sKextLock);
8498
8499 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8500
8501 if (!aKext) {
8502 goto finish; // can't unload what's not loaded
8503 }
8504
8505 if (aKext->isLoaded()) {
8506 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8507 goto finish;
8508 }
8509 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8510 goto finish;
8511 }
8512 }
8513
8514 result = true;
8515
8516 finish:
8517 IORecursiveLockUnlock(sKextLock);
8518 return result;
8519 }
8520
8521 /*********************************************************************
8522 *********************************************************************/
8523 OSReturn
8524 OSKext::stop(void)
8525 {
8526 OSReturn result = kOSReturnError;
8527 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8528
8529 if (!isStarted() || isInterface()) {
8530 result = kOSReturnSuccess;
8531 goto finish;
8532 }
8533
8534 if (!isLoaded()) {
8535 OSKextLog(this,
8536 kOSKextLogErrorLevel |
8537 kOSKextLogLoadFlag,
8538 "Attempt to stop nonloaded kext %s.",
8539 getIdentifierCString());
8540 result = kOSKextReturnInvalidArgument;
8541 goto finish;
8542 }
8543
8544 /* Refuse to stop if we have clients or instances. It is up to
8545 * the caller to make sure those aren't true.
8546 */
8547 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8548 OSKextLog(this,
8549 kOSKextLogErrorLevel |
8550 kOSKextLogLoadFlag,
8551 "Kext %s - C++ instances; can't stop.",
8552 getIdentifierCString());
8553 result = kOSKextReturnInUse;
8554 goto finish;
8555 }
8556
8557 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8558 OSKextLog(this,
8559 kOSKextLogErrorLevel |
8560 kOSKextLogLoadFlag,
8561 "Kext %s - has references (linkage or tracking object); "
8562 "can't stop.",
8563 getIdentifierCString());
8564 result = kOSKextReturnInUse;
8565 goto finish;
8566 }
8567
8568 /* Note: If validateKextMapping fails on the stop & unload path,
8569 * we are in serious trouble and a kernel panic is likely whether
8570 * we stop & unload the kext or not.
8571 */
8572 result = validateKextMapping(/* start? */ false);
8573 if (result != kOSReturnSuccess) {
8574 goto finish;
8575 }
8576
8577 stopfunc = kmod_info->stop;
8578 if (stopfunc) {
8579 OSKextLog(this,
8580 kOSKextLogDetailLevel |
8581 kOSKextLogLoadFlag,
8582 "Kext %s calling module stop function.",
8583 getIdentifierCString());
8584
8585 flags.stopping = 1;
8586
8587 result = stopfunc(kmod_info, /* userData */ NULL);
8588 if (result == KERN_SUCCESS) {
8589 result = OSRuntimeFinalizeCPP(this);
8590 }
8591
8592 flags.stopping = 0;
8593
8594 if (result == KERN_SUCCESS) {
8595 flags.started = 0;
8596
8597 OSKextLog(this,
8598 kOSKextLogDetailLevel |
8599 kOSKextLogLoadFlag,
8600 "Kext %s is now stopped and ready to unload.",
8601 getIdentifierCString());
8602 } else {
8603 OSKextLog(this,
8604 kOSKextLogErrorLevel |
8605 kOSKextLogLoadFlag,
8606 "Kext %s did not stop (return code 0x%x).",
8607 getIdentifierCString(), result);
8608 result = kOSKextReturnStartStopError;
8609 }
8610 }
8611
8612 finish:
8613 // Drop a log message so logd can update this kext's metadata
8614 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
8615 return result;
8616 }
8617
8618 /*********************************************************************
8619 *********************************************************************/
8620 OSReturn
8621 OSKext::unload(void)
8622 {
8623 OSReturn result = kOSReturnError;
8624 unsigned int index;
8625 uint32_t num_kmod_refs = 0;
8626 OSKextAccount * freeAccount;
8627 bool in_fileset = false;
8628
8629 if (!sUnloadEnabled) {
8630 OSKextLog(this,
8631 kOSKextLogErrorLevel |
8632 kOSKextLogLoadFlag,
8633 "Kext unloading is disabled (%s).",
8634 this->getIdentifierCString());
8635
8636 result = kOSKextReturnDisabled;
8637 goto finish;
8638 }
8639
8640 // cache this result so we don't need to access the kmod_info after
8641 // it's been potentially free'd
8642 in_fileset = isInFileset();
8643
8644 /* Refuse to unload if we have clients or instances. It is up to
8645 * the caller to make sure those aren't true.
8646 */
8647 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8648 // xxx - Don't log under errors? this is more of an info thing
8649 OSKextLog(this,
8650 kOSKextLogErrorLevel |
8651 kOSKextLogKextBookkeepingFlag,
8652 "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8653 getIdentifierCString(), getRetainCount());
8654 result = kOSKextReturnInUse;
8655 goto finish;
8656 }
8657
8658 if (isDriverKit()) {
8659 index = sLoadedDriverKitKexts->getNextIndexOfObject(this, 0);
8660 if (index != (unsigned int)-1) {
8661 sLoadedDriverKitKexts->removeObject(index);
8662 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
8663 loadTag = 0;
8664 }
8665 }
8666
8667 if (!isLoaded()) {
8668 result = kOSReturnSuccess;
8669 goto finish;
8670 }
8671
8672 if (isKernelComponent()) {
8673 result = kOSKextReturnInvalidArgument;
8674 goto finish;
8675 }
8676
8677 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
8678 OSKextLog(this,
8679 kOSKextLogErrorLevel |
8680 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8681 "Can't unload kext %s; classes have instances:",
8682 getIdentifierCString());
8683 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8684 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8685 result = kOSKextReturnInUse;
8686 goto finish;
8687 }
8688
8689 /* Note that the kext is unloading before running any code that
8690 * might be in the kext (request callbacks, module stop function).
8691 * We will deny certain requests made against a kext in the process
8692 * of unloading.
8693 */
8694 flags.unloading = 1;
8695
8696 /* Update the string describing the last kext to unload in case we panic.
8697 */
8698 savePanicString(/* isLoading */ false);
8699
8700 if (isStarted()) {
8701 result = stop();
8702 if (result != KERN_SUCCESS) {
8703 OSKextLog(this,
8704 kOSKextLogErrorLevel |
8705 kOSKextLogLoadFlag,
8706 "Kext %s can't unload - module stop returned 0x%x.",
8707 getIdentifierCString(), (unsigned)result);
8708 result = kOSKextReturnStartStopError;
8709 goto finish;
8710 }
8711 }
8712
8713 OSKextLog(this,
8714 kOSKextLogProgressLevel |
8715 kOSKextLogLoadFlag,
8716 "Kext %s unloading.",
8717 getIdentifierCString());
8718
8719 {
8720 struct list_head *p;
8721 struct list_head *prev;
8722 struct list_head *next;
8723 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8724 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8725 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
8726 prev = p->prev;
8727 next = p->next;
8728 prev->next = next;
8729 next->prev = prev;
8730 p->prev = p;
8731 p->next = p;
8732 IORecursiveLockWakeup(sKextLock, s, false);
8733 }
8734 }
8735
8736
8737 /* Even if we don't call the stop function, we want to be sure we
8738 * have no OSMetaClass references before unloading the kext executable
8739 * from memory. OSMetaClasses may have pointers into the kext executable
8740 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8741 */
8742 if (metaClasses) {
8743 metaClasses->flushCollection();
8744 }
8745 (void) OSRuntimeFinalizeCPP(this);
8746
8747 /* Remove the kext from the list of loaded kexts, patch the gap
8748 * in the kmod_info_t linked list, and reset "kmod" to point to the
8749 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8750 */
8751 index = sLoadedKexts->getNextIndexOfObject(this, 0);
8752 if (index != (unsigned int)-1) {
8753 sLoadedKexts->removeObject(index);
8754
8755 OSKext * nextKext = OSDynamicCast(OSKext,
8756 sLoadedKexts->getObject(index));
8757
8758 if (nextKext) {
8759 if (index > 0) {
8760 OSKext * gapKext = OSDynamicCast(OSKext,
8761 sLoadedKexts->getObject(index - 1));
8762
8763 nextKext->kmod_info->next = gapKext->kmod_info;
8764 } else { /* index == 0 */
8765 nextKext->kmod_info->next = NULL;
8766 }
8767 }
8768
8769 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8770 if (lastKext && !lastKext->isKernel()) {
8771 kmod = lastKext->kmod_info;
8772 } else {
8773 kmod = NULL; // clear the global kmod variable
8774 }
8775 }
8776
8777 /* Clear out the kmod references that we're keeping for compatibility
8778 * with current panic backtrace code & kgmacros.
8779 * xxx - will want to update those bits sometime and remove this.
8780 */
8781 num_kmod_refs = getNumDependencies();
8782 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8783 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8784 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8785 ref->info->reference_count--;
8786 }
8787 kfree_type(kmod_reference_t, num_kmod_refs,
8788 kmod_info->reference_list);
8789 }
8790
8791 #if CONFIG_DTRACE
8792 unregisterWithDTrace();
8793 #endif /* CONFIG_DTRACE */
8794
8795 notifyKextUnloadObservers(this);
8796
8797 freeAccount = NULL;
8798 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
8799 account->kext = NULL;
8800 if (account->site.tag) {
8801 account->site.flags |= VM_TAG_UNLOAD;
8802 } else {
8803 freeAccount = account;
8804 }
8805
8806 #if DEVELOPMENT || DEBUG
8807 assertf(account->task_refgrp.grp_count == 0,
8808 "unloading a kext with active task references");
8809 #endif /* DEVELOPMENT || DEBUG */
8810
8811 lck_ticket_unlock(sKextAccountsLock);
8812 if (freeAccount) {
8813 IOFreeType(freeAccount, OSKextAccount);
8814 }
8815
8816 /* Unwire and free the linked executable.
8817 */
8818 if (linkedExecutable) {
8819 #if KASAN
8820 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8821 #endif
8822
8823 #if VM_MAPPED_KEXTS
8824 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8825 kernel_segment_command_t *seg = NULL;
8826 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8827
8828 if (!kext_map) {
8829 OSKextLog(this,
8830 kOSKextLogErrorLevel |
8831 kOSKextLogLoadFlag,
8832 "Failed to free kext %s; couldn't find the kext map.",
8833 getIdentifierCString());
8834 result = kOSKextReturnInternalError;
8835 goto finish;
8836 }
8837
8838 OSKextLog(this,
8839 kOSKextLogProgressLevel |
8840 kOSKextLogLoadFlag,
8841 "Kext %s unwiring and unmapping linked executable.",
8842 getIdentifierCString());
8843
8844 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8845 while (seg) {
8846 if (segmentShouldBeWired(seg)) {
8847 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8848 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8849
8850 result = vm_map_unwire(kext_map, start_wire,
8851 end_wire, FALSE);
8852 if (result != KERN_SUCCESS) {
8853 OSKextLog(this,
8854 kOSKextLogErrorLevel |
8855 kOSKextLogLoadFlag,
8856 "Failed to unwire kext %s.",
8857 getIdentifierCString());
8858 result = kOSKextReturnInternalError;
8859 goto finish;
8860 }
8861 }
8862
8863 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8864 }
8865 #if defined(__x86_64__) || defined(__i386__)
8866 if (in_fileset && flags.resetSegmentsFromVnode) {
8867 IORecursiveLockLock(sKextLock);
8868 resetKCFileSetSegments();
8869 IORecursiveLockUnlock(sKextLock);
8870 }
8871 #endif // (__x86_64__) || defined(__i386__)
8872 }
8873 #endif /* VM_MAPPED_KEXTS */
8874 if (flags.resetSegmentsFromImmutableCopy) {
8875 result = resetMutableSegments();
8876 if (result != kOSReturnSuccess) {
8877 OSKextLog(this,
8878 kOSKextLogErrorLevel |
8879 kOSKextLogLoadFlag,
8880 "Failed to reset kext %s.",
8881 getIdentifierCString());
8882 result = kOSKextReturnInternalError;
8883 goto finish;
8884 }
8885 }
8886 if (kc_type == KCKindUnknown) {
8887 linkedExecutable.reset();
8888 }
8889 }
8890
8891 /* An interface kext has a fake kmod_info that was allocated,
8892 * so we have to free it.
8893 */
8894 if (isInterface()) {
8895 kfree_type(kmod_info_t, kmod_info);
8896 kmod_info = NULL;
8897 }
8898
8899 if (!in_fileset) {
8900 kmod_info = NULL;
8901 }
8902
8903 flags.loaded = false;
8904 flushDependencies();
8905
8906 /* save a copy of the bundle ID for us to check when deciding to
8907 * rebuild the kernel cache file. If a kext was already in the kernel
8908 * cache and unloaded then later loaded we do not need to rebuild the
8909 * kernel cache. 9055303
8910 */
8911 if (isPrelinked()) {
8912 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
8913 IORecursiveLockLock(sKextLock);
8914 if (sUnloadedPrelinkedKexts) {
8915 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8916 }
8917 IORecursiveLockUnlock(sKextLock);
8918 }
8919 }
8920
8921 OSKextLog(this,
8922 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8923 "Kext %s unloaded.", getIdentifierCString());
8924
8925 queueKextNotification(kKextRequestPredicateUnloadNotification,
8926 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
8927
8928 finish:
8929 OSKext::saveLoadedKextPanicList();
8930 OSKext::updateLoadedKextSummaries();
8931
8932 flags.unloading = 0;
8933 return result;
8934 }
8935
8936 /*********************************************************************
8937 * Assumes sKextLock is held.
8938 *********************************************************************/
8939 /* static */
8940 OSReturn
8941 OSKext::queueKextNotification(
8942 const char * notificationName,
8943 OSString * kextIdentifier,
8944 OSData * dextUniqueIdentifier)
8945 {
8946 OSReturn result = kOSReturnError;
8947 OSSharedPtr<OSDictionary> loadRequest;
8948
8949 if (!kextIdentifier) {
8950 result = kOSKextReturnInvalidArgument;
8951 goto finish;
8952 }
8953
8954 /* Create a new request unless one is already sitting
8955 * in sKernelRequests for this bundle identifier
8956 */
8957 result = _OSKextCreateRequest(notificationName, loadRequest);
8958 if (result != kOSReturnSuccess) {
8959 goto finish;
8960 }
8961 if (!_OSKextSetRequestArgument(loadRequest.get(),
8962 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8963 result = kOSKextReturnNoMemory;
8964 goto finish;
8965 }
8966 if (NULL != dextUniqueIdentifier) {
8967 if (!_OSKextSetRequestArgument(loadRequest.get(),
8968 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
8969 result = kOSKextReturnNoMemory;
8970 goto finish;
8971 }
8972 }
8973 if (!sKernelRequests->setObject(loadRequest.get())) {
8974 result = kOSKextReturnNoMemory;
8975 goto finish;
8976 }
8977
8978 /* We might want to only queue the notification if the IOKit daemon is active,
8979 * but that wouldn't work for embedded. Note that we don't care if
8980 * the ping immediately succeeds here so don't do anything with the
8981 * result of this call.
8982 */
8983 OSKext::pingIOKitDaemon();
8984
8985 result = kOSReturnSuccess;
8986
8987 finish:
8988 return result;
8989 }
8990
8991
8992 #if CONFIG_KXLD
8993 /*********************************************************************
8994 *********************************************************************/
8995 static void
8996 _OSKextConsiderDestroyingLinkContext(
8997 __unused thread_call_param_t p0,
8998 __unused thread_call_param_t p1)
8999 {
9000 /* Take multiple locks in the correct order.
9001 */
9002 IORecursiveLockLock(sKextLock);
9003 IORecursiveLockLock(sKextInnerLock);
9004
9005 /* The first time we destroy the kxldContext is in the first
9006 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
9007 * before calling this function. Thereafter any call to this function
9008 * will actually destroy the context.
9009 */
9010 if (sConsiderUnloadsCalled && sKxldContext) {
9011 kxld_destroy_context(sKxldContext);
9012 sKxldContext = NULL;
9013 }
9014
9015 /* Free the thread_call that was allocated to execute this function.
9016 */
9017 if (sDestroyLinkContextThread) {
9018 if (!thread_call_free(sDestroyLinkContextThread)) {
9019 OSKextLog(/* kext */ NULL,
9020 kOSKextLogErrorLevel |
9021 kOSKextLogGeneralFlag,
9022 "thread_call_free() failed for kext link context.");
9023 }
9024 sDestroyLinkContextThread = NULL;
9025 }
9026
9027 IORecursiveLockUnlock(sKextInnerLock);
9028 IORecursiveLockUnlock(sKextLock);
9029
9030 return;
9031 }
9032
9033 /*********************************************************************
9034 * Destroying the kxldContext requires checking variables under both
9035 * sKextInnerLock and sKextLock, so we do it on a separate thread
9036 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
9037 * call relationship.
9038 *
9039 * This function must be invoked with sKextInnerLock held.
9040 * Do not call any function that takes sKextLock here!
9041 *********************************************************************/
9042 /* static */
9043 void
9044 OSKext::considerDestroyingLinkContext(void)
9045 {
9046 IORecursiveLockLock(sKextInnerLock);
9047
9048 /* If we have already queued a thread to destroy the link context,
9049 * don't bother resetting; that thread will take care of it.
9050 */
9051 if (sDestroyLinkContextThread) {
9052 goto finish;
9053 }
9054
9055 /* The function to be invoked in the thread will deallocate
9056 * this thread_call, so don't share it around.
9057 */
9058 sDestroyLinkContextThread = thread_call_allocate(
9059 &_OSKextConsiderDestroyingLinkContext, NULL);
9060 if (!sDestroyLinkContextThread) {
9061 OSKextLog(/* kext */ NULL,
9062 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
9063 "Can't create thread to destroy kext link context.");
9064 goto finish;
9065 }
9066
9067 thread_call_enter(sDestroyLinkContextThread);
9068
9069 finish:
9070 IORecursiveLockUnlock(sKextInnerLock);
9071 return;
9072 }
9073
9074 #else // !CONFIG_KXLD
9075
9076 /* static */
9077 void
9078 OSKext::considerDestroyingLinkContext(void)
9079 {
9080 return;
9081 }
9082
9083 #endif // CONFIG_KXLD
9084
9085 #if PRAGMA_MARK
9086 #pragma mark Autounload
9087 #endif
9088 /*********************************************************************
9089 * This is a static method because the kext will be deallocated if it
9090 * does unload!
9091 *********************************************************************/
9092 /* static */
9093 OSReturn
9094 OSKext::autounloadKext(OSKext * aKext)
9095 {
9096 OSReturn result = kOSKextReturnInUse;
9097
9098 #if NO_KEXTD
9099 /*
9100 * Do not unload prelinked kexts on platforms that do not have an
9101 * IOKit daemon as there is no way to reload the kext or restart
9102 * matching.
9103 */
9104 if (aKext->isPrelinked()) {
9105 goto finish;
9106 }
9107 #endif /* defined(__x86_64__) */
9108
9109 /* Check for external references to this kext (usu. dependents),
9110 * instances of defined classes (or classes derived from them),
9111 * outstanding requests.
9112 */
9113 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
9114 !aKext->flags.autounloadEnabled ||
9115 aKext->isKernelComponent()) {
9116 goto finish;
9117 }
9118
9119 /* Skip a delay-autounload kext, once.
9120 */
9121 if (aKext->flags.delayAutounload) {
9122 OSKextLog(aKext,
9123 kOSKextLogProgressLevel |
9124 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
9125 "Kext %s has delayed autounload set; skipping and clearing flag.",
9126 aKext->getIdentifierCString());
9127 aKext->flags.delayAutounload = 0;
9128 goto finish;
9129 }
9130
9131 if (aKext->hasOSMetaClassInstances() ||
9132 aKext->countRequestCallbacks()) {
9133 goto finish;
9134 }
9135
9136 result = OSKext::removeKext(aKext);
9137
9138 finish:
9139 return result;
9140 }
9141
9142 /*********************************************************************
9143 *********************************************************************/
9144 void
9145 _OSKextConsiderUnloads(
9146 __unused thread_call_param_t p0,
9147 __unused thread_call_param_t p1)
9148 {
9149 bool didUnload = false;
9150 unsigned int count, i;
9151
9152 /* Take multiple locks in the correct order
9153 * (note also sKextSummaries lock further down).
9154 */
9155 IORecursiveLockLock(sKextLock);
9156 IORecursiveLockLock(sKextInnerLock);
9157
9158 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
9159
9160 /* If the system is powering down, don't try to unload anything.
9161 */
9162 if (sSystemSleep) {
9163 goto finish;
9164 }
9165
9166 OSKextLog(/* kext */ NULL,
9167 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
9168 "Checking for unused kexts to autounload.");
9169
9170 /*****
9171 * Remove any request callbacks marked as stale,
9172 * and mark as stale any currently in flight.
9173 */
9174 count = sRequestCallbackRecords->getCount();
9175 if (count) {
9176 i = count - 1;
9177 do {
9178 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
9179 sRequestCallbackRecords->getObject(i));
9180 if (callbackRecord) {
9181 OSBoolean * stale = OSDynamicCast(OSBoolean,
9182 callbackRecord->getObject(kKextRequestStaleKey));
9183
9184 if (stale == kOSBooleanTrue) {
9185 OSKext::invokeRequestCallback(callbackRecord,
9186 kOSKextReturnTimeout);
9187 } else {
9188 callbackRecord->setObject(kKextRequestStaleKey,
9189 kOSBooleanTrue);
9190 }
9191 }
9192 } while (i--);
9193 }
9194
9195 /*****
9196 * Make multiple passes through the array of loaded kexts until
9197 * we don't unload any. This handles unwinding of dependency
9198 * chains. We have to go *backwards* through the array because
9199 * kexts are removed from it when unloaded, and we cannot make
9200 * a copy or we'll mess up the retain counts we rely on to
9201 * check whether a kext will unload. If only we could have
9202 * nonretaining collections like CF has....
9203 */
9204 do {
9205 didUnload = false;
9206
9207 count = sLoadedKexts->getCount();
9208 if (count) {
9209 i = count - 1;
9210 do {
9211 OSKext * thisKext = OSDynamicCast(OSKext,
9212 sLoadedKexts->getObject(i));
9213 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
9214 } while (i--);
9215 }
9216 } while (didUnload);
9217
9218 finish:
9219 sConsiderUnloadsPending = false;
9220 sConsiderUnloadsExecuted = true;
9221
9222 (void) OSKext::considerRebuildOfPrelinkedKernel();
9223
9224 IORecursiveLockUnlock(sKextInnerLock);
9225 IORecursiveLockUnlock(sKextLock);
9226
9227 return;
9228 }
9229
9230 /*********************************************************************
9231 * Do not call any function that takes sKextLock here!
9232 *********************************************************************/
9233 void
9234 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
9235 {
9236 AbsoluteTime when;
9237
9238 IORecursiveLockLock(sKextInnerLock);
9239
9240 if (!sUnloadCallout) {
9241 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
9242 }
9243
9244 /* we only reset delay value for unloading if we already have something
9245 * pending. rescheduleOnlyFlag should not start the count down.
9246 */
9247 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9248 goto finish;
9249 }
9250
9251 thread_call_cancel(sUnloadCallout);
9252 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9253 #if !NO_KEXTD
9254 && sIOKitDaemonActive
9255 #endif
9256 ) {
9257 clock_interval_to_deadline(sConsiderUnloadDelay,
9258 1000 * 1000 * 1000, &when);
9259
9260 OSKextLog(/* kext */ NULL,
9261 kOSKextLogProgressLevel |
9262 kOSKextLogLoadFlag,
9263 "%scheduling %sscan for unused kexts in %lu seconds.",
9264 sConsiderUnloadsPending ? "Res" : "S",
9265 sConsiderUnloadsCalled ? "" : "initial ",
9266 (unsigned long)sConsiderUnloadDelay);
9267
9268 sConsiderUnloadsPending = true;
9269 thread_call_enter_delayed(sUnloadCallout, when);
9270 }
9271
9272 finish:
9273 /* The kxld context should be reused throughout boot. We mark the end of
9274 * period as the first time considerUnloads() is called, and we destroy
9275 * the first kxld context in that function. Afterwards, it will be
9276 * destroyed in flushNonloadedKexts.
9277 */
9278 if (!sConsiderUnloadsCalled) {
9279 sConsiderUnloadsCalled = true;
9280 OSKext::considerDestroyingLinkContext();
9281 }
9282
9283 IORecursiveLockUnlock(sKextInnerLock);
9284 return;
9285 }
9286
9287 /*********************************************************************
9288 * Do not call any function that takes sKextLock here!
9289 *********************************************************************/
9290 extern "C" {
9291 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9292 IOReturn
9293 OSKextSystemSleepOrWake(UInt32 messageType)
9294 {
9295 IORecursiveLockLock(sKextInnerLock);
9296
9297 /* If the system is going to sleep, cancel the reaper thread timer,
9298 * and note that we're in a sleep state in case it just fired but hasn't
9299 * taken the lock yet. If we are coming back from sleep, just
9300 * clear the sleep flag; IOService's normal operation will cause
9301 * unloads to be considered soon enough.
9302 */
9303 if (messageType == kIOMessageSystemWillSleep) {
9304 if (sUnloadCallout) {
9305 thread_call_cancel(sUnloadCallout);
9306 }
9307 sSystemSleep = true;
9308 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9309 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9310 sSystemSleep = false;
9311 clock_get_uptime(&sLastWakeTime);
9312 }
9313 IORecursiveLockUnlock(sKextInnerLock);
9314
9315 return kIOReturnSuccess;
9316 }
9317 };
9318
9319
9320 #if PRAGMA_MARK
9321 #pragma mark Prelinked Kernel
9322 #endif
9323
9324 #ifdef CONFIG_KXLD
9325 /*********************************************************************
9326 * Do not access sConsiderUnloads... variables other than
9327 * sConsiderUnloadsExecuted in this function. They are guarded by a
9328 * different lock.
9329 *********************************************************************/
9330 /* static */
9331 void
9332 OSKext::considerRebuildOfPrelinkedKernel(void)
9333 {
9334 static bool requestedPrelink = false;
9335 OSReturn checkResult = kOSReturnError;
9336 OSSharedPtr<OSDictionary> prelinkRequest;
9337 OSSharedPtr<OSCollectionIterator> kextIterator;
9338 const OSSymbol * thisID = NULL; // do not release
9339 bool doRebuild = false;
9340 AbsoluteTime my_abstime;
9341 UInt64 my_ns;
9342 SInt32 delta_secs;
9343
9344 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9345 if (requestedPrelink || !sPrelinkBoot) {
9346 return;
9347 }
9348
9349 /* no direct return from this point */
9350 IORecursiveLockLock(sKextLock);
9351
9352 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9353 * and any new startup kexts loaded.
9354 */
9355 if (!sConsiderUnloadsExecuted ||
9356 !sDeferredLoadSucceeded) {
9357 goto finish;
9358 }
9359
9360 /* we really only care about boot / system start up related kexts so bail
9361 * if we're here after REBUILD_MAX_TIME.
9362 */
9363 if (!_OSKextInPrelinkRebuildWindow()) {
9364 OSKextLog(/* kext */ NULL,
9365 kOSKextLogArchiveFlag,
9366 "%s prebuild rebuild has expired",
9367 __FUNCTION__);
9368 requestedPrelink = true;
9369 goto finish;
9370 }
9371
9372 /* we do not want to trigger a rebuild if we get here too close to waking
9373 * up. (see radar 10233768)
9374 */
9375 IORecursiveLockLock(sKextInnerLock);
9376
9377 clock_get_uptime(&my_abstime);
9378 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9379 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9380 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9381 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9382 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9383 }
9384 IORecursiveLockUnlock(sKextInnerLock);
9385
9386 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9387 /* too close to time of last wake from sleep */
9388 goto finish;
9389 }
9390 requestedPrelink = true;
9391
9392 /* Now it's time to see if we have a reason to rebuild. We may have done
9393 * some loads and unloads but the kernel cache didn't actually change.
9394 * We will rebuild if any kext is not marked prelinked AND is not in our
9395 * list of prelinked kexts that got unloaded. (see radar 9055303)
9396 */
9397 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9398 if (!kextIterator) {
9399 goto finish;
9400 }
9401
9402 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9403 OSKext * thisKext; // do not release
9404
9405 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9406 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9407 continue;
9408 }
9409
9410 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9411 continue;
9412 }
9413 /* kext is loaded and was not in current kernel cache so let's rebuild
9414 */
9415 doRebuild = true;
9416 OSKextLog(/* kext */ NULL,
9417 kOSKextLogArchiveFlag,
9418 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9419 thisKext->bundleID->getCStringNoCopy());
9420 break;
9421 }
9422 sUnloadedPrelinkedKexts->flushCollection();
9423
9424 if (!doRebuild) {
9425 goto finish;
9426 }
9427
9428 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9429 prelinkRequest);
9430 if (checkResult != kOSReturnSuccess) {
9431 goto finish;
9432 }
9433
9434 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9435 goto finish;
9436 }
9437
9438 OSKext::pingIOKitDaemon();
9439
9440 finish:
9441 IORecursiveLockUnlock(sKextLock);
9442
9443 return;
9444 }
9445
9446 #else /* !CONFIG_KXLD */
9447
9448 void
9449 OSKext::considerRebuildOfPrelinkedKernel(void)
9450 {
9451 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9452 return;
9453 }
9454
9455 #endif /* CONFIG_KXLD */
9456
9457 #if PRAGMA_MARK
9458 #pragma mark Dependencies
9459 #endif
9460 /*********************************************************************
9461 *********************************************************************/
9462 bool
9463 OSKext::resolveDependencies(
9464 OSArray * loopStack)
9465 {
9466 bool result = false;
9467 OSSharedPtr<OSArray> localLoopStack;
9468 bool addedToLoopStack = false;
9469 OSDictionary * libraries = NULL; // do not release
9470 OSSharedPtr<OSCollectionIterator> libraryIterator;
9471 OSString * libraryID = NULL; // do not release
9472 OSKext * libraryKext = NULL; // do not release
9473 bool hasRawKernelDependency = false;
9474 bool hasKernelDependency = false;
9475 bool hasKPIDependency = false;
9476 bool hasPrivateKPIDependency = false;
9477 unsigned int count;
9478
9479 #if CONFIG_KXLD
9480 OSString * infoString = NULL; // do not release
9481 OSString * readableString = NULL; // do not release
9482 #endif // CONFIG_KXLD
9483
9484 /* A kernel component will automatically have this flag set,
9485 * and a loaded kext should also have it set (as should all its
9486 * loaded dependencies).
9487 */
9488 if (flags.hasAllDependencies) {
9489 result = true;
9490 goto finish;
9491 }
9492
9493 /* Check for loops in the dependency graph.
9494 */
9495 if (loopStack) {
9496 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
9497 OSKextLog(this,
9498 kOSKextLogErrorLevel |
9499 kOSKextLogDependenciesFlag,
9500 "Kext %s has a dependency loop; can't resolve dependencies.",
9501 getIdentifierCString());
9502 goto finish;
9503 }
9504 } else {
9505 OSKextLog(this,
9506 kOSKextLogStepLevel |
9507 kOSKextLogDependenciesFlag,
9508 "Kext %s resolving dependencies.",
9509 getIdentifierCString());
9510
9511 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
9512 if (!localLoopStack) {
9513 OSKextLog(this,
9514 kOSKextLogErrorLevel |
9515 kOSKextLogDependenciesFlag,
9516 "Kext %s can't create bookkeeping stack to resolve dependencies.",
9517 getIdentifierCString());
9518 goto finish;
9519 }
9520 loopStack = localLoopStack.get();
9521 }
9522 if (!loopStack->setObject(this)) {
9523 OSKextLog(this,
9524 kOSKextLogErrorLevel |
9525 kOSKextLogDependenciesFlag,
9526 "Kext %s - internal error resolving dependencies.",
9527 getIdentifierCString());
9528 goto finish;
9529 }
9530 addedToLoopStack = true;
9531
9532 /* Purge any existing kexts in the dependency list and start over.
9533 */
9534 flushDependencies();
9535 if (dependencies) {
9536 OSKextLog(this,
9537 kOSKextLogErrorLevel |
9538 kOSKextLogDependenciesFlag,
9539 "Kext %s - internal error resolving dependencies.",
9540 getIdentifierCString());
9541 }
9542
9543 libraries = OSDynamicCast(OSDictionary,
9544 getPropertyForHostArch(kOSBundleLibrariesKey));
9545 if (libraries == NULL || libraries->getCount() == 0) {
9546 OSKextLog(this,
9547 kOSKextLogErrorLevel |
9548 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9549 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9550 getIdentifierCString(), kOSBundleLibrariesKey);
9551 goto finish;
9552 }
9553
9554 /* Make a new array to hold the dependencies (flush freed the old one).
9555 */
9556 dependencies = OSArray::withCapacity(libraries->getCount());
9557 if (!dependencies) {
9558 OSKextLog(this,
9559 kOSKextLogErrorLevel |
9560 kOSKextLogDependenciesFlag,
9561 "Kext %s - can't allocate dependencies array.",
9562 getIdentifierCString());
9563 goto finish;
9564 }
9565
9566 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9567 // xxx - compat: if none were declared.
9568
9569 libraryIterator = OSCollectionIterator::withCollection(libraries);
9570 if (!libraryIterator) {
9571 OSKextLog(this,
9572 kOSKextLogErrorLevel |
9573 kOSKextLogDependenciesFlag,
9574 "Kext %s - can't allocate dependencies iterator.",
9575 getIdentifierCString());
9576 goto finish;
9577 }
9578
9579 while ((libraryID = OSDynamicCast(OSString,
9580 libraryIterator->getNextObject()))) {
9581 const char * library_id = libraryID->getCStringNoCopy();
9582
9583 OSString * libraryVersion = OSDynamicCast(OSString,
9584 libraries->getObject(libraryID));
9585 if (libraryVersion == NULL) {
9586 OSKextLog(this,
9587 kOSKextLogErrorLevel |
9588 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9589 "Kext %s - illegal type in OSBundleLibraries.",
9590 getIdentifierCString());
9591 goto finish;
9592 }
9593
9594 OSKextVersion libraryVers =
9595 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
9596 if (libraryVers == -1) {
9597 OSKextLog(this,
9598 kOSKextLogErrorLevel |
9599 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9600 "Kext %s - invalid library version %s.",
9601 getIdentifierCString(),
9602 libraryVersion->getCStringNoCopy());
9603 goto finish;
9604 }
9605
9606 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9607 if (libraryKext == NULL) {
9608 OSKextLog(this,
9609 kOSKextLogErrorLevel |
9610 kOSKextLogDependenciesFlag,
9611 "Kext %s - library kext %s not found.",
9612 getIdentifierCString(), library_id);
9613 goto finish;
9614 }
9615
9616 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
9617 OSKextLog(this,
9618 kOSKextLogErrorLevel |
9619 kOSKextLogDependenciesFlag,
9620 "Kext %s - library kext %s not compatible "
9621 "with requested version %s.",
9622 getIdentifierCString(), library_id,
9623 libraryVersion->getCStringNoCopy());
9624 goto finish;
9625 }
9626
9627 /* If a nonprelinked library somehow got into the mix for a
9628 * prelinked kext, at any point in the chain, we must fail
9629 * because the prelinked relocs for the library will be all wrong.
9630 */
9631 if (this->isPrelinked() &&
9632 libraryKext->declaresExecutable() &&
9633 !libraryKext->isPrelinked()) {
9634 OSKextLog(this,
9635 kOSKextLogErrorLevel |
9636 kOSKextLogDependenciesFlag,
9637 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9638 getIdentifierCString(), library_id,
9639 libraryVersion->getCStringNoCopy());
9640 goto finish;
9641 }
9642
9643 if (!libraryKext->resolveDependencies(loopStack)) {
9644 goto finish;
9645 }
9646
9647 /* Add the library directly only if it has an executable to link.
9648 * Otherwise it's just used to collect other dependencies, so put
9649 * *its* dependencies on the list for this kext.
9650 */
9651 // xxx - We are losing info here; would like to make fake entries or
9652 // xxx - keep these in the dependency graph for loaded kexts.
9653 // xxx - I really want to make kernel components not a special case!
9654 if (libraryKext->declaresExecutable() ||
9655 libraryKext->isInterface()) {
9656 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
9657 dependencies->setObject(libraryKext);
9658
9659 OSKextLog(this,
9660 kOSKextLogDetailLevel |
9661 kOSKextLogDependenciesFlag,
9662 "Kext %s added dependency %s.",
9663 getIdentifierCString(),
9664 libraryKext->getIdentifierCString());
9665 }
9666 } else {
9667 int numLibDependencies = libraryKext->getNumDependencies();
9668 OSArray * libraryDependencies = libraryKext->getDependencies();
9669 int index;
9670
9671 if (numLibDependencies) {
9672 // xxx - this msg level should be 1 lower than the per-kext one
9673 OSKextLog(this,
9674 kOSKextLogDetailLevel |
9675 kOSKextLogDependenciesFlag,
9676 "Kext %s pulling %d dependencies from codeless library %s.",
9677 getIdentifierCString(),
9678 numLibDependencies,
9679 libraryKext->getIdentifierCString());
9680 }
9681 for (index = 0; index < numLibDependencies; index++) {
9682 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9683 libraryDependencies->getObject(index));
9684 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
9685 dependencies->setObject(thisLibDependency);
9686 OSKextLog(this,
9687 kOSKextLogDetailLevel |
9688 kOSKextLogDependenciesFlag,
9689 "Kext %s added dependency %s from codeless library %s.",
9690 getIdentifierCString(),
9691 thisLibDependency->getIdentifierCString(),
9692 libraryKext->getIdentifierCString());
9693 }
9694 }
9695 }
9696
9697 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
9698 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
9699 hasRawKernelDependency = true;
9700 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9701 hasKernelDependency = true;
9702 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9703 hasKPIDependency = true;
9704 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
9705 hasPrivateKPIDependency = true;
9706 }
9707 }
9708 }
9709
9710 if (hasRawKernelDependency) {
9711 OSKextLog(this,
9712 kOSKextLogErrorLevel |
9713 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9714 "Error - kext %s declares a dependency on %s, which is not permitted.",
9715 getIdentifierCString(), KERNEL_LIB);
9716 goto finish;
9717 }
9718 #if __LP64__
9719 if (hasKernelDependency) {
9720 OSKextLog(this,
9721 kOSKextLogErrorLevel |
9722 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9723 "Error - kext %s declares %s dependencies. "
9724 "Only %s* dependencies are supported for 64-bit kexts.",
9725 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9726 goto finish;
9727 }
9728 if (!hasKPIDependency) {
9729 OSKextLog(this,
9730 kOSKextLogWarningLevel |
9731 kOSKextLogDependenciesFlag,
9732 "Warning - kext %s declares no %s* dependencies. "
9733 "If it uses any KPIs, the link may fail with undefined symbols.",
9734 getIdentifierCString(), KPI_LIB_PREFIX);
9735 }
9736 #else /* __LP64__ */
9737 // xxx - will change to flatly disallow "kernel" dependencies at some point
9738 // xxx - is it invalid to do both "com.apple.kernel" and any
9739 // xxx - "com.apple.kernel.*"?
9740
9741 if (hasKernelDependency && hasKPIDependency) {
9742 OSKextLog(this,
9743 kOSKextLogWarningLevel |
9744 kOSKextLogDependenciesFlag,
9745 "Warning - kext %s has immediate dependencies on both "
9746 "%s* and %s* components; use only one style.",
9747 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9748 }
9749
9750 if (!hasKernelDependency && !hasKPIDependency) {
9751 // xxx - do we want to use validation flag for these too?
9752 OSKextLog(this,
9753 kOSKextLogWarningLevel |
9754 kOSKextLogDependenciesFlag,
9755 "Warning - %s declares no kernel dependencies; using %s.",
9756 getIdentifierCString(), KERNEL6_LIB);
9757 OSKext * kernelKext = OSDynamicCast(OSKext,
9758 sKextsByID->getObject(KERNEL6_LIB));
9759 if (kernelKext) {
9760 dependencies->setObject(kernelKext);
9761 } else {
9762 OSKextLog(this,
9763 kOSKextLogErrorLevel |
9764 kOSKextLogDependenciesFlag,
9765 "Error - Library %s not found for %s.",
9766 KERNEL6_LIB, getIdentifierCString());
9767 }
9768 }
9769
9770 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9771 * its indirect dependencies to simulate old-style linking. XXX - Should
9772 * check for duplicates.
9773 */
9774 if (!hasKPIDependency) {
9775 unsigned int i;
9776
9777 flags.hasBleedthrough = true;
9778
9779 count = getNumDependencies();
9780
9781 /* We add to the dependencies array in this loop, but do not iterate
9782 * past its original count.
9783 */
9784 for (i = 0; i < count; i++) {
9785 OSKext * dependencyKext = OSDynamicCast(OSKext,
9786 dependencies->getObject(i));
9787 dependencyKext->addBleedthroughDependencies(dependencies.get());
9788 }
9789 }
9790 #endif /* __LP64__ */
9791
9792 #if CONFIG_KXLD
9793 /*
9794 * If we're not dynamically linking kexts, then we don't need to check
9795 * copyright strings. The linker in user space has already done this.
9796 */
9797 if (hasPrivateKPIDependency) {
9798 bool hasApplePrefix = false;
9799 bool infoCopyrightIsValid = false;
9800 bool readableCopyrightIsValid = false;
9801
9802 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9803 APPLE_KEXT_PREFIX);
9804
9805 infoString = OSDynamicCast(OSString,
9806 getPropertyForHostArch("CFBundleGetInfoString"));
9807 if (infoString) {
9808 infoCopyrightIsValid =
9809 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9810 }
9811
9812 readableString = OSDynamicCast(OSString,
9813 getPropertyForHostArch("NSHumanReadableCopyright"));
9814 if (readableString) {
9815 readableCopyrightIsValid =
9816 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9817 }
9818
9819 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9820 OSKextLog(this,
9821 kOSKextLogErrorLevel |
9822 kOSKextLogDependenciesFlag,
9823 "Error - kext %s declares a dependency on %s. "
9824 "Only Apple kexts may declare a dependency on %s.",
9825 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9826 goto finish;
9827 }
9828 }
9829 #endif // CONFIG_KXLD
9830
9831 result = true;
9832 flags.hasAllDependencies = 1;
9833
9834 finish:
9835
9836 if (addedToLoopStack) {
9837 count = loopStack->getCount();
9838 if (count > 0 && (this == loopStack->getObject(count - 1))) {
9839 loopStack->removeObject(count - 1);
9840 } else {
9841 OSKextLog(this,
9842 kOSKextLogErrorLevel |
9843 kOSKextLogDependenciesFlag,
9844 "Kext %s - internal error resolving dependencies.",
9845 getIdentifierCString());
9846 }
9847 }
9848
9849 if (result && localLoopStack) {
9850 OSKextLog(this,
9851 kOSKextLogStepLevel |
9852 kOSKextLogDependenciesFlag,
9853 "Kext %s successfully resolved dependencies.",
9854 getIdentifierCString());
9855 }
9856
9857 return result;
9858 }
9859
9860 /*********************************************************************
9861 *********************************************************************/
9862 bool
9863 OSKext::addBleedthroughDependencies(OSArray * anArray)
9864 {
9865 bool result = false;
9866 unsigned int dependencyIndex, dependencyCount;
9867
9868 dependencyCount = getNumDependencies();
9869
9870 for (dependencyIndex = 0;
9871 dependencyIndex < dependencyCount;
9872 dependencyIndex++) {
9873 OSKext * dependency = OSDynamicCast(OSKext,
9874 dependencies->getObject(dependencyIndex));
9875 if (!dependency) {
9876 OSKextLog(this,
9877 kOSKextLogErrorLevel |
9878 kOSKextLogDependenciesFlag,
9879 "Kext %s - internal error propagating compatibility dependencies.",
9880 getIdentifierCString());
9881 goto finish;
9882 }
9883 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
9884 anArray->setObject(dependency);
9885 }
9886 dependency->addBleedthroughDependencies(anArray);
9887 }
9888
9889 result = true;
9890
9891 finish:
9892 return result;
9893 }
9894
9895 /*********************************************************************
9896 *********************************************************************/
9897 bool
9898 OSKext::flushDependencies(bool forceFlag)
9899 {
9900 bool result = false;
9901
9902 /* Only clear the dependencies if the kext isn't loaded;
9903 * we need the info for loaded kexts to track references.
9904 */
9905 if (!isLoaded() || forceFlag) {
9906 if (dependencies) {
9907 // xxx - check level
9908 OSKextLog(this,
9909 kOSKextLogProgressLevel |
9910 kOSKextLogDependenciesFlag,
9911 "Kext %s flushing dependencies.",
9912 getIdentifierCString());
9913 dependencies.reset();
9914 }
9915 if (!isKernelComponent()) {
9916 flags.hasAllDependencies = 0;
9917 }
9918 result = true;
9919 }
9920
9921 return result;
9922 }
9923
9924 /*********************************************************************
9925 *********************************************************************/
9926 uint32_t
9927 OSKext::getNumDependencies(void)
9928 {
9929 if (!dependencies) {
9930 return 0;
9931 }
9932 return dependencies->getCount();
9933 }
9934
9935 /*********************************************************************
9936 *********************************************************************/
9937 OSArray *
9938 OSKext::getDependencies(void)
9939 {
9940 return dependencies.get();
9941 }
9942
9943 bool
9944 OSKext::hasDependency(const OSSymbol * depID)
9945 {
9946 bool result __block;
9947
9948 if (depID == getIdentifier()) {
9949 return true;
9950 }
9951 if (!dependencies) {
9952 return false;
9953 }
9954 result = false;
9955 dependencies->iterateObjects(^bool (OSObject * obj) {
9956 OSKext * kext;
9957 kext = OSDynamicCast(OSKext, obj);
9958 if (!kext) {
9959 return false;
9960 }
9961 result = (depID == kext->getIdentifier());
9962 return result;
9963 });
9964 return result;
9965 }
9966
9967 #if PRAGMA_MARK
9968 #pragma mark OSMetaClass Support
9969 #endif
9970 /*********************************************************************
9971 *********************************************************************/
9972 OSReturn
9973 OSKext::addClass(
9974 OSMetaClass * aClass,
9975 uint32_t numClasses)
9976 {
9977 OSReturn result = kOSMetaClassNoInsKModSet;
9978
9979 if (!metaClasses) {
9980 metaClasses = OSSet::withCapacity(numClasses);
9981 if (!metaClasses) {
9982 goto finish;
9983 }
9984 }
9985
9986 if (metaClasses->containsObject(aClass)) {
9987 OSKextLog(this,
9988 kOSKextLogWarningLevel |
9989 kOSKextLogLoadFlag,
9990 "Notice - kext %s has already registered class %s.",
9991 getIdentifierCString(),
9992 aClass->getClassName());
9993 result = kOSReturnSuccess;
9994 goto finish;
9995 }
9996
9997 if (!metaClasses->setObject(aClass)) {
9998 goto finish;
9999 } else {
10000 OSKextLog(this,
10001 kOSKextLogDetailLevel |
10002 kOSKextLogLoadFlag,
10003 "Kext %s registered class %s.",
10004 getIdentifierCString(),
10005 aClass->getClassName());
10006 }
10007
10008 if (!flags.autounloadEnabled) {
10009 const OSMetaClass * metaScan = NULL; // do not release
10010
10011 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
10012 if (metaScan == OSTypeID(IOService)) {
10013 OSKextLog(this,
10014 kOSKextLogProgressLevel |
10015 kOSKextLogLoadFlag,
10016 "Kext %s has IOService subclass %s; enabling autounload.",
10017 getIdentifierCString(),
10018 aClass->getClassName());
10019
10020 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
10021 break;
10022 }
10023 }
10024 }
10025
10026 notifyAddClassObservers(this, aClass, flags);
10027
10028 result = kOSReturnSuccess;
10029
10030 finish:
10031 if (result != kOSReturnSuccess) {
10032 OSKextLog(this,
10033 kOSKextLogErrorLevel |
10034 kOSKextLogLoadFlag,
10035 "Kext %s failed to register class %s.",
10036 getIdentifierCString(),
10037 aClass->getClassName());
10038 }
10039
10040 return result;
10041 }
10042
10043 /*********************************************************************
10044 *********************************************************************/
10045 OSReturn
10046 OSKext::removeClass(
10047 OSMetaClass * aClass)
10048 {
10049 OSReturn result = kOSMetaClassNoKModSet;
10050
10051 if (!metaClasses) {
10052 goto finish;
10053 }
10054
10055 if (!metaClasses->containsObject(aClass)) {
10056 OSKextLog(this,
10057 kOSKextLogWarningLevel |
10058 kOSKextLogLoadFlag,
10059 "Notice - kext %s asked to unregister unknown class %s.",
10060 getIdentifierCString(),
10061 aClass->getClassName());
10062 result = kOSReturnSuccess;
10063 goto finish;
10064 }
10065
10066 OSKextLog(this,
10067 kOSKextLogDetailLevel |
10068 kOSKextLogLoadFlag,
10069 "Kext %s unregistering class %s.",
10070 getIdentifierCString(),
10071 aClass->getClassName());
10072
10073 metaClasses->removeObject(aClass);
10074
10075 notifyRemoveClassObservers(this, aClass, flags);
10076
10077 result = kOSReturnSuccess;
10078
10079 finish:
10080 if (result != kOSReturnSuccess) {
10081 OSKextLog(this,
10082 kOSKextLogErrorLevel |
10083 kOSKextLogLoadFlag,
10084 "Failed to unregister kext %s class %s.",
10085 getIdentifierCString(),
10086 aClass->getClassName());
10087 }
10088 return result;
10089 }
10090
10091 /*********************************************************************
10092 *********************************************************************/
10093 OSSet *
10094 OSKext::getMetaClasses(void)
10095 {
10096 return metaClasses.get();
10097 }
10098
10099 /*********************************************************************
10100 *********************************************************************/
10101 bool
10102 OSKext::hasOSMetaClassInstances(void)
10103 {
10104 bool result = false;
10105 OSSharedPtr<OSCollectionIterator> classIterator;
10106 OSMetaClass * checkClass = NULL; // do not release
10107
10108 if (!metaClasses) {
10109 goto finish;
10110 }
10111
10112 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10113 if (!classIterator) {
10114 // xxx - log alloc failure?
10115 goto finish;
10116 }
10117 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10118 if (checkClass->getInstanceCount()) {
10119 result = true;
10120 goto finish;
10121 }
10122 }
10123
10124 finish:
10125 return result;
10126 }
10127
10128 /*********************************************************************
10129 *********************************************************************/
10130 /* static */
10131 void
10132 OSKext::reportOSMetaClassInstances(
10133 const char * kextIdentifier,
10134 OSKextLogSpec msgLogSpec)
10135 {
10136 OSSharedPtr<OSKext> theKext;
10137
10138 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
10139 if (!theKext) {
10140 goto finish;
10141 }
10142
10143 theKext->reportOSMetaClassInstances(msgLogSpec);
10144 finish:
10145 return;
10146 }
10147
10148 /*********************************************************************
10149 *********************************************************************/
10150 void
10151 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
10152 {
10153 OSSharedPtr<OSCollectionIterator> classIterator;
10154 OSMetaClass * checkClass = NULL; // do not release
10155
10156 if (!metaClasses) {
10157 goto finish;
10158 }
10159
10160 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10161 if (!classIterator) {
10162 goto finish;
10163 }
10164 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10165 if (checkClass->getInstanceCount()) {
10166 OSKextLog(this,
10167 msgLogSpec,
10168 " Kext %s class %s has %d instance%s.",
10169 getIdentifierCString(),
10170 checkClass->getClassName(),
10171 checkClass->getInstanceCount(),
10172 checkClass->getInstanceCount() == 1 ? "" : "s");
10173 }
10174 }
10175
10176 finish:
10177 return;
10178 }
10179
10180 #if PRAGMA_MARK
10181 #pragma mark User-Space Requests
10182 #endif
10183
10184 static kern_return_t
10185 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
10186 {
10187 OSReturn result = kOSReturnSuccess;
10188 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
10189 OSDictionary * request = NULL; //do not release
10190 IOUserServerCheckInToken * token = NULL; //do not release
10191 OSString * requestPredicate = NULL; //do not release
10192 OSSharedPtr<OSNumber> portNameNumber;
10193 mach_port_name_t portName = 0;
10194 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
10195 if (!request) {
10196 OSKextLog(/* kext */ NULL,
10197 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10198 "Elements of request should be of type OSDictionary");
10199 result = kOSKextReturnInternalError;
10200 goto finish;
10201 }
10202 requestPredicate = _OSKextGetRequestPredicate(request);
10203 if (!requestPredicate) {
10204 OSKextLog(/* kext */ NULL,
10205 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10206 "Failed to get request predicate");
10207 result = kOSKextReturnInternalError;
10208 goto finish;
10209 }
10210 // is this a dext launch?
10211 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
10212 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
10213 if (!token) {
10214 OSKextLog(/* kext */ NULL,
10215 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10216 "Could not find a IOUserServerCheckInToken in daemon launch request.");
10217 result = kOSKextReturnInternalError;
10218 goto finish;
10219 }
10220 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
10221 if (portName == 0 || portName == MACH_PORT_DEAD) {
10222 OSKextLog(/* kext */ NULL,
10223 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10224 "Could not create send right for object.");
10225 result = kOSKextReturnInternalError;
10226 goto finish;
10227 }
10228 // Store the mach port name as a OSNumber
10229 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
10230 if (!portNameNumber) {
10231 OSKextLog(/* kext */ NULL,
10232 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10233 "Could not create OSNumber object.");
10234 result = kOSKextReturnNoMemory;
10235 goto finish;
10236 }
10237 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
10238 OSKextLog(/* kext */ NULL,
10239 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10240 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
10241 result = kOSKextReturnNoMemory;
10242 goto finish;
10243 }
10244 }
10245 finish:
10246 if (result != kOSReturnSuccess) {
10247 break;
10248 }
10249 }
10250 return result;
10251 }
10252
10253 bool
10254 OSKext::iokitDaemonActive()
10255 {
10256 bool result;
10257 IORecursiveLockLock(sKextLock);
10258 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10259 IORecursiveLockUnlock(sKextLock);
10260 return result;
10261 }
10262
10263 /*********************************************************************
10264 * XXX - this function is a big ugly mess
10265 *********************************************************************/
10266 /* static */
10267 OSReturn
10268 OSKext::handleRequest(
10269 host_priv_t hostPriv,
10270 OSKextLogSpec clientLogFilter,
10271 char * requestBuffer,
10272 uint32_t requestLength,
10273 char ** responseOut,
10274 uint32_t * responseLengthOut,
10275 char ** logInfoOut,
10276 uint32_t * logInfoLengthOut)
10277 {
10278 OSReturn result = kOSReturnError;
10279 kern_return_t kmem_result = KERN_FAILURE;
10280
10281 char * response = NULL; // returned by reference
10282 uint32_t responseLength = 0;
10283
10284 bool taskCanManageAllKCs = false;
10285 bool taskOnlyManagesBootKC = false;
10286
10287 OSSharedPtr<OSObject> parsedXML;
10288 OSDictionary * requestDict = NULL; // do not release
10289 OSSharedPtr<OSString> errorString;
10290
10291 OSSharedPtr<OSObject> responseObject;
10292
10293 OSSharedPtr<OSSerialize> serializer;
10294
10295 OSSharedPtr<OSArray> logInfoArray;
10296
10297 OSString * predicate = NULL; // do not release
10298 OSString * kextIdentifier = NULL; // do not release
10299 OSArray * kextIdentifiers = NULL; // do not release
10300 OSKext * theKext = NULL; // do not release
10301 OSBoolean * boolArg = NULL; // do not release
10302
10303
10304 IORecursiveLockLock(sKextLock);
10305
10306 if (responseOut) {
10307 *responseOut = NULL;
10308 *responseLengthOut = 0;
10309 }
10310 if (logInfoOut) {
10311 *logInfoOut = NULL;
10312 *logInfoLengthOut = 0;
10313 }
10314
10315 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
10316
10317 /* XML must be nul-terminated.
10318 */
10319 if (requestBuffer[requestLength - 1] != '\0') {
10320 OSKextLog(/* kext */ NULL,
10321 kOSKextLogErrorLevel |
10322 kOSKextLogIPCFlag,
10323 "Invalid request from user space (not nul-terminated).");
10324 result = kOSKextReturnBadData;
10325 goto finish;
10326 }
10327 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
10328 if (parsedXML) {
10329 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10330 }
10331 if (!requestDict) {
10332 const char * errorCString = "(unknown error)";
10333
10334 if (errorString && errorString->getCStringNoCopy()) {
10335 errorCString = errorString->getCStringNoCopy();
10336 } else if (parsedXML) {
10337 errorCString = "not a dictionary";
10338 }
10339 OSKextLog(/* kext */ NULL,
10340 kOSKextLogErrorLevel |
10341 kOSKextLogIPCFlag,
10342 "Error unserializing request from user space: %s.",
10343 errorCString);
10344 result = kOSKextReturnSerialization;
10345 goto finish;
10346 }
10347
10348 predicate = _OSKextGetRequestPredicate(requestDict);
10349 if (!predicate) {
10350 OSKextLog(/* kext */ NULL,
10351 kOSKextLogErrorLevel |
10352 kOSKextLogIPCFlag,
10353 "Recieved kext request from user space with no predicate.");
10354 result = kOSKextReturnInvalidArgument;
10355 goto finish;
10356 }
10357 OSKextLog(/* kext */ NULL,
10358 kOSKextLogDebugLevel |
10359 kOSKextLogIPCFlag,
10360 "Received '%s' request from user space.",
10361 predicate->getCStringNoCopy());
10362
10363 /*
10364 * All management of file sets requires an entitlement
10365 */
10366 result = kOSKextReturnNotPrivileged;
10367 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10368 predicate->isEqualTo(kKextRequestPredicateStart) ||
10369 predicate->isEqualTo(kKextRequestPredicateStop) ||
10370 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10371 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10372 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10373 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10374 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10375 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10376 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10377 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10378 if (!iokitDaemonAvailable()) {
10379 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10380 }
10381 if (hostPriv == HOST_PRIV_NULL) {
10382 OSKextLog(/* kext */ NULL,
10383 kOSKextLogErrorLevel |
10384 kOSKextLogIPCFlag,
10385 "Access Failure - must be root user.");
10386 goto finish;
10387 }
10388 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10389 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10390
10391 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10392 OSKextLog(/* kext */ NULL,
10393 kOSKextLogErrorLevel |
10394 kOSKextLogIPCFlag,
10395 "Access Failure - client not entitled to manage file sets.");
10396 goto finish;
10397 }
10398
10399 /*
10400 * The OnlyBootKC entitlement restricts the
10401 * collection-management entitlement to only managing kexts in
10402 * the BootKC. All other predicates that alter global state or
10403 * add new KCs are disallowed.
10404 */
10405 if (taskOnlyManagesBootKC &&
10406 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10407 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10408 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10409 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10410 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10411 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10412 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10413 OSKextLog(/* kext */ NULL,
10414 kOSKextLogErrorLevel |
10415 kOSKextLogIPCFlag,
10416 "Access Failure - client not entitled to manage non-primary KCs");
10417 goto finish;
10418 }
10419
10420 /*
10421 * If we get here, then the process either has the full KC
10422 * management entitlement, or it has the BootKC-only
10423 * entitlement and the request is about the BootKC.
10424 */
10425 }
10426
10427 /* Get common args in anticipation of use.
10428 */
10429 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10430 requestDict, kKextRequestArgumentBundleIdentifierKey));
10431 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10432 requestDict, kKextRequestArgumentBundleIdentifierKey));
10433 if (kextIdentifier) {
10434 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10435 }
10436 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10437 requestDict, kKextRequestArgumentValueKey));
10438
10439 if (taskOnlyManagesBootKC &&
10440 theKext &&
10441 theKext->isInFileset() &&
10442 theKext->kc_type != KCKindPrimary) {
10443 OSKextLog(/* kext */ NULL,
10444 kOSKextLogErrorLevel |
10445 kOSKextLogIPCFlag,
10446 "Access Failure - client not entitled to manage kext in non-primary KC");
10447 result = kOSKextReturnNotPrivileged;
10448 goto finish;
10449 }
10450 result = kOSKextReturnInvalidArgument;
10451
10452 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10453 if (!kextIdentifier) {
10454 OSKextLog(/* kext */ NULL,
10455 kOSKextLogErrorLevel |
10456 kOSKextLogIPCFlag,
10457 "Invalid arguments to kext start request.");
10458 } else if (!theKext) {
10459 OSKextLog(/* kext */ NULL,
10460 kOSKextLogErrorLevel |
10461 kOSKextLogIPCFlag,
10462 "Kext %s not found for start request.",
10463 kextIdentifier->getCStringNoCopy());
10464 result = kOSKextReturnNotFound;
10465 } else {
10466 result = theKext->start();
10467 }
10468 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10469 if (!kextIdentifier) {
10470 OSKextLog(/* kext */ NULL,
10471 kOSKextLogErrorLevel |
10472 kOSKextLogIPCFlag,
10473 "Invalid arguments to kext stop request.");
10474 } else if (!theKext) {
10475 OSKextLog(/* kext */ NULL,
10476 kOSKextLogErrorLevel |
10477 kOSKextLogIPCFlag,
10478 "Kext %s not found for stop request.",
10479 kextIdentifier->getCStringNoCopy());
10480 result = kOSKextReturnNotFound;
10481 } else {
10482 result = theKext->stop();
10483 }
10484 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10485 result = OSKext::setMissingAuxKCBundles(requestDict);
10486 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10487 if (!kextIdentifier) {
10488 OSKextLog(/* kext */ NULL,
10489 kOSKextLogErrorLevel |
10490 kOSKextLogIPCFlag,
10491 "Invalid arguments to AuxKC Bundle Available request.");
10492 } else {
10493 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10494 }
10495 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10496 if (!kextIdentifier) {
10497 OSKextLog(/* kext */ NULL,
10498 kOSKextLogErrorLevel |
10499 kOSKextLogIPCFlag,
10500 "Invalid arguments to kext load from KC request.");
10501 } else if (!theKext) {
10502 OSKextLog(/* kext */ NULL,
10503 kOSKextLogErrorLevel |
10504 kOSKextLogIPCFlag,
10505 "Kext %s not found for load from KC request.",
10506 kextIdentifier->getCStringNoCopy());
10507 result = kOSKextReturnNotFound;
10508 } else if (!theKext->isInFileset()) {
10509 OSKextLog(/* kext */ NULL,
10510 kOSKextLogErrorLevel |
10511 kOSKextLogIPCFlag,
10512 "Kext %s does not exist in a KC: refusing to load.",
10513 kextIdentifier->getCStringNoCopy());
10514 result = kOSKextReturnNotLoadable;
10515 } else {
10516 result = OSKext::loadKextFromKC(theKext, requestDict);
10517 }
10518 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10519 if (!kextIdentifier) {
10520 OSKextLog(/* kext */ NULL,
10521 kOSKextLogErrorLevel |
10522 kOSKextLogIPCFlag,
10523 "Invalid arguments to codeless kext load interface (missing identifier).");
10524 } else {
10525 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10526 }
10527 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10528 if (!kextIdentifier) {
10529 OSKextLog(/* kext */ NULL,
10530 kOSKextLogErrorLevel |
10531 kOSKextLogIPCFlag,
10532 "Invalid arguments to kext unload request.");
10533 } else if (!theKext) {
10534 OSKextLog(/* kext */ NULL,
10535 kOSKextLogErrorLevel |
10536 kOSKextLogIPCFlag,
10537 "Kext %s not found for unload request.",
10538 kextIdentifier->getCStringNoCopy());
10539 result = kOSKextReturnNotFound;
10540 } else {
10541 if (theKext->isDriverKit()) {
10542 result = OSKext::removeDext(theKext);
10543 } else {
10544 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10545 _OSKextGetRequestArgument(requestDict,
10546 kKextRequestArgumentTerminateIOServicesKey));
10547 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
10548 }
10549 }
10550 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10551 result = OSKext::dispatchResource(requestDict);
10552 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10553 OSNumber *lookupNum = NULL;
10554 lookupNum = OSDynamicCast(OSNumber,
10555 _OSKextGetRequestArgument(requestDict,
10556 kKextRequestArgumentLookupAddressKey));
10557
10558 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
10559 if (responseObject) {
10560 result = kOSReturnSuccess;
10561 } else {
10562 goto finish;
10563 }
10564 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10565 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10566 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10567 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10568 OSBoolean * delayAutounloadBool = NULL;
10569 OSObject * infoKeysRaw = NULL;
10570 OSArray * infoKeys = NULL;
10571 uint32_t infoKeysCount = 0;
10572
10573 delayAutounloadBool = OSDynamicCast(OSBoolean,
10574 _OSKextGetRequestArgument(requestDict,
10575 kKextRequestArgumentDelayAutounloadKey));
10576
10577 /* If asked to delay autounload, reset the timer if it's currently set.
10578 * (That is, don't schedule an unload if one isn't already pending.
10579 */
10580 if (delayAutounloadBool == kOSBooleanTrue) {
10581 OSKext::considerUnloads(/* rescheduleOnly? */ true);
10582 }
10583
10584 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10585 kKextRequestArgumentInfoKeysKey);
10586 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10587 if (infoKeysRaw && !infoKeys) {
10588 OSKextLog(/* kext */ NULL,
10589 kOSKextLogErrorLevel |
10590 kOSKextLogIPCFlag,
10591 "Invalid arguments to kext info request.");
10592 goto finish;
10593 }
10594
10595 if (infoKeys) {
10596 infoKeysCount = infoKeys->getCount();
10597 for (uint32_t i = 0; i < infoKeysCount; i++) {
10598 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10599 OSKextLog(/* kext */ NULL,
10600 kOSKextLogErrorLevel |
10601 kOSKextLogIPCFlag,
10602 "Invalid arguments to kext info request.");
10603 goto finish;
10604 }
10605 }
10606 }
10607
10608 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10609 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
10610 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10611 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
10612 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10613 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10614 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10615 responseObject = OSKext::copyDextsInfo(kextIdentifiers, infoKeys);
10616 }
10617
10618 if (!responseObject) {
10619 result = kOSKextReturnInternalError;
10620 } else {
10621 OSKextLog(/* kext */ NULL,
10622 kOSKextLogDebugLevel |
10623 kOSKextLogIPCFlag,
10624 "Returning loaded kext info.");
10625 result = kOSReturnSuccess;
10626 }
10627 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10628 /* Hand the current sKernelRequests array to the caller
10629 * (who must release it), and make a new one.
10630 */
10631 responseObject = os::move(sKernelRequests);
10632 sKernelRequests = OSArray::withCapacity(0);
10633 sPostedKextLoadIdentifiers->flushCollection();
10634 OSKextLog(/* kext */ NULL,
10635 kOSKextLogDebugLevel |
10636 kOSKextLogIPCFlag,
10637 "Returning kernel requests.");
10638 result = kOSReturnSuccess;
10639 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10640 /* Return the set of all requested bundle identifiers */
10641 responseObject = sAllKextLoadIdentifiers;
10642 OSKextLog(/* kext */ NULL,
10643 kOSKextLogDebugLevel |
10644 kOSKextLogIPCFlag,
10645 "Returning load requests.");
10646 result = kOSReturnSuccess;
10647 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10648 printf("KextLog: Loading FileSet KC(s)\n");
10649 result = OSKext::loadFileSetKexts(requestDict);
10650 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10651 bool active = iokitDaemonActive();
10652 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10653 if (sOSKextWasResetAfterUserspaceReboot) {
10654 printf("KextLog: was reset after userspace reboot\n");
10655 }
10656 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10657 } else {
10658 OSKextLog(/* kext */ NULL,
10659 kOSKextLogDebugLevel |
10660 kOSKextLogIPCFlag,
10661 "Received '%s' invalid request from user space.",
10662 predicate->getCStringNoCopy());
10663 goto finish;
10664 }
10665
10666 /**********
10667 * Now we have handle the request, or not. Gather up the response & logging
10668 * info to ship to user space.
10669 *********/
10670
10671 /* Note: Nothing in OSKext is supposed to retain requestDict,
10672 * but you never know....
10673 */
10674 if (requestDict->getRetainCount() > 1) {
10675 OSKextLog(/* kext */ NULL,
10676 kOSKextLogWarningLevel |
10677 kOSKextLogIPCFlag,
10678 "Request from user space still retained by a kext; "
10679 "probable memory leak.");
10680 }
10681
10682 if (responseOut && responseObject) {
10683 serializer = OSSerialize::withCapacity(0);
10684 if (!serializer) {
10685 result = kOSKextReturnNoMemory;
10686 goto finish;
10687 }
10688 /*
10689 * Before serializing the kernel requests, patch the dext launch requests so
10690 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10691 * IOUserServerCheckInToken kernel object.
10692 */
10693 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10694 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10695 task_t calling_task = current_task();
10696 if (!requests) {
10697 OSKextLog(/* kext */ NULL,
10698 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10699 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10700 result = kOSKextReturnInternalError;
10701 goto finish;
10702 }
10703 result = patchDextLaunchRequests(calling_task, requests);
10704 if (result != kOSReturnSuccess) {
10705 OSKextLog(/* kext */ NULL,
10706 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10707 "Failed to patch dext launch requests.");
10708 goto finish;
10709 }
10710 }
10711
10712 if (!responseObject->serialize(serializer.get())) {
10713 OSKextLog(/* kext */ NULL,
10714 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10715 "Failed to serialize response to request from user space.");
10716 result = kOSKextReturnSerialization;
10717 goto finish;
10718 }
10719
10720 response = (char *)serializer->text();
10721 responseLength = serializer->getLength();
10722 }
10723
10724 if (responseOut && response) {
10725 char * buffer;
10726
10727 /* This kmem_alloc sets the return value of the function.
10728 */
10729 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
10730 round_page(responseLength), KMA_DATA, VM_KERN_MEMORY_OSKEXT);
10731 if (kmem_result != KERN_SUCCESS) {
10732 OSKextLog(/* kext */ NULL,
10733 kOSKextLogErrorLevel |
10734 kOSKextLogIPCFlag,
10735 "Failed to copy response to request from user space.");
10736 result = kmem_result;
10737 goto finish;
10738 } else {
10739 /* 11981737 - clear uninitialized data in last page */
10740 bzero((void *)(buffer + responseLength),
10741 (round_page(responseLength) - responseLength));
10742 memcpy(buffer, response, responseLength);
10743 *responseOut = buffer;
10744 *responseLengthOut = responseLength;
10745 }
10746 }
10747
10748 finish:
10749
10750 /* Gather up the collected log messages for user space. Any messages
10751 * messages past this call will not make it up as log messages but
10752 * will be in the system log. Note that we ignore the return of the
10753 * serialize; it has no bearing on the operation at hand even if we
10754 * fail to get the log messages.
10755 */
10756 logInfoArray = OSKext::clearUserSpaceLogFilter();
10757
10758 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10759 (void)OSKext::serializeLogInfo(logInfoArray.get(),
10760 logInfoOut, logInfoLengthOut);
10761 }
10762
10763 IORecursiveLockUnlock(sKextLock);
10764
10765 return result;
10766 }
10767
10768 #if PRAGMA_MARK
10769 #pragma mark Linked Kext Collection Support
10770 #endif
10771
10772 static int
10773 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10774 {
10775 for (int i = 0; i < segCount; i++) {
10776 vm_offset_t segStart = segAddrs[i];
10777 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10778
10779 if (theAddr >= segStart && theAddr < segEnd) {
10780 return i;
10781 }
10782 }
10783 return -1;
10784 }
10785
10786 static void
10787 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
10788 kernel_segment_command_t *kextTextSeg,
10789 OSData *kaslrOffsets)
10790 {
10791 static const char *plk_segNames[] = {
10792 "__TEXT",
10793 "__TEXT_EXEC",
10794 "__DATA",
10795 "__DATA_CONST",
10796 "__LINKEDIT",
10797 "__PRELINK_TEXT",
10798 "__PLK_TEXT_EXEC",
10799 "__PRELINK_DATA",
10800 "__PLK_DATA_CONST",
10801 "__PLK_LLVM_COV",
10802 "__PLK_LINKEDIT",
10803 "__PRELINK_INFO"
10804 };
10805 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10806
10807 unsigned long plk_segSizes[num_plk_seg];
10808 vm_offset_t plk_segAddrs[num_plk_seg];
10809
10810 for (size_t i = 0; i < num_plk_seg; i++) {
10811 plk_segSizes[i] = 0;
10812 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10813 }
10814
10815 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10816
10817 int slidKextAddrCount = 0;
10818 int badSlideAddr = 0;
10819 int badSlideTarget = 0;
10820
10821 struct kaslrPackedOffsets {
10822 uint32_t count; /* number of offsets */
10823 uint32_t offsetsArray[]; /* offsets to slide */
10824 };
10825 const struct kaslrPackedOffsets *myOffsets = NULL;
10826 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10827
10828 for (uint32_t j = 0; j < myOffsets->count; j++) {
10829 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10830 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10831 int slideAddrSegIndex = -1;
10832 int addrToSlideSegIndex = -1;
10833
10834 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10835 if (slideAddrSegIndex >= 0) {
10836 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10837 if (addrToSlideSegIndex < 0) {
10838 badSlideTarget++;
10839 continue;
10840 }
10841 } else {
10842 badSlideAddr++;
10843 continue;
10844 }
10845
10846 slidKextAddrCount++;
10847 *slideAddr = ml_static_slide(*slideAddr);
10848 } // for ...
10849 }
10850
10851
10852
10853 /********************************************************************
10854 * addKextsFromKextCollection
10855 *
10856 * Input: MachO header of kext collection. The MachO is assumed to
10857 * have a section named 'info_seg_name,info_sect_name' that
10858 * contains a serialized XML info dictionary. This dictionary
10859 * contains a UUID, possibly a set of relocations (for older
10860 * kxld-built binaries), and an array of kext personalities.
10861 *
10862 ********************************************************************/
10863 bool
10864 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10865 OSDictionary *infoDict, const char *text_seg_name,
10866 OSData **kcUUID, kc_kind_t type)
10867 {
10868 bool result = false;
10869
10870 OSArray *kextArray = NULL; // do not release
10871 OSData *infoDictKCUUID = NULL; // do not release
10872 OSData *kaslrOffsets = NULL; // do not release
10873
10874 IORegistryEntry *registryRoot = NULL; // do not release
10875 OSSharedPtr<OSNumber> kcKextCount;
10876
10877 /* extract the KC UUID from the dictionary */
10878 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10879 if (infoDictKCUUID) {
10880 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10881 panic("kcUUID length is %d, expected %lu",
10882 infoDictKCUUID->getLength(), sizeof(uuid_t));
10883 }
10884 }
10885
10886 /* locate the array of kext dictionaries */
10887 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10888 if (!kextArray) {
10889 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10890 "The given KC has no kext info dictionaries");
10891 goto finish;
10892 }
10893
10894 /*
10895 * old-style KASLR offsets may be present in the info dictionary. If
10896 * we find them, use them and eventually slide them.
10897 */
10898 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10899
10900 /*
10901 * Before processing any kexts, locate the special kext bundle which
10902 * contains a list of kexts that we are to prevent from loading.
10903 */
10904 createExcludeListFromPrelinkInfo(kextArray);
10905
10906 /*
10907 * Create OSKext objects for each kext we find in the array of kext
10908 * info plist dictionaries.
10909 */
10910 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10911 OSDictionary *kextDict = NULL;
10912 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10913 if (!kextDict) {
10914 OSKextLog(/* kext */ NULL,
10915 kOSKextLogErrorLevel |
10916 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10917 "Kext info dictionary for kext #%d isn't a dictionary?", i);
10918 continue;
10919 }
10920
10921 /*
10922 * Create the kext for the entry, then release it, because the
10923 * kext system keeps a reference around until the kext is
10924 * explicitly removed. Any creation/registration failures are
10925 * already logged for us.
10926 */
10927 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
10928 }
10929
10930 /*
10931 * slide old-style kxld relocations
10932 * NOTE: this is still used on embedded KCs built with kcgen
10933 * TODO: Remove this once we use the new kext linker everywhere!
10934 */
10935 if (kaslrOffsets && vm_kernel_slide > 0) {
10936 kernel_segment_command_t *text_segment = NULL;
10937 text_segment = getsegbynamefromheader(mh, text_seg_name);
10938 if (!text_segment) {
10939 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10940 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10941 goto finish;
10942 }
10943
10944 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
10945 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10946 setAllVMAttributes();
10947 }
10948
10949 /* Store the number of prelinked kexts in the registry so we can tell
10950 * when the system has been started from a prelinked kernel.
10951 */
10952 registryRoot = IORegistryEntry::getRegistryRoot();
10953 assert(registryRoot);
10954
10955 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10956 assert(kcKextCount);
10957 if (kcKextCount) {
10958 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10959 OSNumber *num;
10960 num = OSDynamicCast(OSNumber, prop.get());
10961 if (num) {
10962 kcKextCount->addValue(num->unsigned64BitValue());
10963 }
10964 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10965 }
10966
10967 OSKextLog(/* kext */ NULL,
10968 kOSKextLogProgressLevel |
10969 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10970 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10971 "%u prelinked kexts", infoDict->getCount());
10972
10973
10974 if (kcUUID && infoDictKCUUID) {
10975 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10976 }
10977
10978 result = true;
10979
10980 finish:
10981 return result;
10982 }
10983
10984 bool
10985 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10986 OSDictionary *infoDict, const char *text_seg_name,
10987 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10988 {
10989 OSData *result = NULL;
10990 bool success = addKextsFromKextCollection(mh,
10991 infoDict,
10992 text_seg_name,
10993 &result,
10994 type);
10995 if (success) {
10996 kcUUID.reset(result, OSNoRetain);
10997 }
10998 return success;
10999 }
11000
11001 static OSSharedPtr<OSObject> deferredAuxKCXML;
11002 bool
11003 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
11004 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
11005 {
11006 if (type != KCKindAuxiliary) {
11007 return false;
11008 }
11009
11010 kernel_mach_header_t *_mh;
11011 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
11012 if (!_mh || _mh != mh) {
11013 return false;
11014 }
11015
11016 if (deferredAuxKCXML) {
11017 /* only allow this to be called once */
11018 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11019 "An Aux KC has already been registered for deferred processing.");
11020 return false;
11021 }
11022
11023 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11024 if (!infoDict) {
11025 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11026 "The Aux KC has info dictionary");
11027 return false;
11028 }
11029
11030 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
11031 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
11032 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11033 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
11034 return false;
11035 }
11036
11037 /*
11038 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
11039 * sysctl can return the UUID to user space which will check this
11040 * value for errors.
11041 */
11042 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
11043 kcUUID->getLength());
11044 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
11045 auxkc_uuid_valid = TRUE;
11046
11047 deferredAuxKCXML = parsedXML;
11048
11049 return true;
11050 }
11051
11052 OSSharedPtr<OSObject>
11053 OSKext::consumeDeferredKextCollection(kc_kind_t type)
11054 {
11055 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
11056 return NULL;
11057 }
11058
11059 return os::move(deferredAuxKCXML);
11060 }
11061
11062 #if PRAGMA_MARK
11063 #pragma mark Profile-Guided-Optimization Support
11064 #endif
11065
11066 // #include <InstrProfiling.h>
11067 extern "C" {
11068 uint64_t __llvm_profile_get_size_for_buffer_internal(
11069 const char *DataBegin,
11070 const char *DataEnd,
11071 const char *CountersBegin,
11072 const char *CountersEnd,
11073 const char *BitmapBegin,
11074 const char *BitmapEnd,
11075 const char *NamesBegin,
11076 const char *NamesEnd,
11077 const char *VTableBegin,
11078 const char *VTableEnd,
11079 const char *VNamesBegin,
11080 const char *VNamesEnd);
11081 int __llvm_profile_write_buffer_internal(
11082 char *Buffer,
11083 const char *DataBegin,
11084 const char *DataEnd,
11085 const char *CountersBegin,
11086 const char *CountersEnd,
11087 const char *BitmapBegin,
11088 const char *BitmapEnd,
11089 const char *NamesBegin,
11090 const char *NamesEnd);
11091 }
11092
11093 static
11094 void
11095 OSKextPgoMetadataPut(char *pBuffer,
11096 size_t *position,
11097 size_t bufferSize,
11098 uint32_t *num_pairs,
11099 const char *key,
11100 const char *value)
11101 {
11102 size_t strlen_key = strlen(key);
11103 size_t strlen_value = strlen(value);
11104 size_t len = strlen(key) + 1 + strlen(value) + 1;
11105 char *pos = pBuffer + *position;
11106 *position += len;
11107 if (pBuffer && bufferSize && *position <= bufferSize) {
11108 memcpy(pos, key, strlen_key); pos += strlen_key;
11109 *(pos++) = '=';
11110 memcpy(pos, value, strlen_value); pos += strlen_value;
11111 *(pos++) = 0;
11112 if (num_pairs) {
11113 (*num_pairs)++;
11114 }
11115 }
11116 }
11117
11118
11119 static
11120 void
11121 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
11122 {
11123 *position += strlen(key) + 1 + value_max + 1;
11124 }
11125
11126
11127 static
11128 void
11129 OSKextPgoMetadataPutAll(OSKext *kext,
11130 uuid_t instance_uuid,
11131 char *pBuffer,
11132 size_t *position,
11133 size_t bufferSize,
11134 uint32_t *num_pairs)
11135 {
11136 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
11137 //log_10 2^16 ≈ 4.82
11138 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
11139 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
11140
11141 if (!pBuffer) {
11142 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
11143 OSKextPgoMetadataPutMax(position, "UUID", 36);
11144 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
11145 } else {
11146 uuid_string_t instance_uuid_string;
11147 uuid_unparse(instance_uuid, instance_uuid_string);
11148 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11149 "INSTANCE", instance_uuid_string);
11150
11151 OSSharedPtr<OSData> uuid_data;
11152 uuid_t uuid;
11153 uuid_string_t uuid_string;
11154 uuid_data = kext->copyUUID();
11155 if (uuid_data) {
11156 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
11157 uuid_unparse(uuid, uuid_string);
11158 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11159 "UUID", uuid_string);
11160 }
11161
11162 clock_sec_t secs;
11163 clock_usec_t usecs;
11164 clock_get_calendar_microtime(&secs, &usecs);
11165 assert(usecs < 1000000);
11166 char timestamp[max_timestamp_string_size + 1];
11167 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
11168 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
11169 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11170 "TIMESTAMP", timestamp);
11171 }
11172
11173 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11174 "NAME", kext->getIdentifierCString());
11175
11176 char versionCString[kOSKextVersionMaxLength];
11177 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
11178 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11179 "VERSION", versionCString);
11180 }
11181
11182 static
11183 size_t
11184 OSKextPgoMetadataSize(OSKext *kext)
11185 {
11186 size_t position = 0;
11187 uuid_t fakeuuid = {};
11188 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
11189 return position;
11190 }
11191
11192 int
11193 OSKextGrabPgoDataLocked(OSKext *kext,
11194 bool metadata,
11195 uuid_t instance_uuid,
11196 uint64_t *pSize,
11197 char *pBuffer,
11198 uint64_t bufferSize)
11199 {
11200 int err = 0;
11201
11202 kernel_section_t *sect_prf_data = NULL;
11203 kernel_section_t *sect_prf_name = NULL;
11204 kernel_section_t *sect_prf_cnts = NULL;
11205 uint64_t size;
11206 size_t metadata_size = 0;
11207 size_t offset_to_pairs = 0;
11208
11209 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
11210 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
11211 if (!sect_prf_name) {
11212 // kextcache sometimes truncates the section name to 15 chars
11213 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
11214 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
11215 }
11216 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11217
11218 // Ignore some sections used by optional PGO variants.
11219 const char *unused_section = NULL;
11220
11221 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
11222 err = ENOTSUP;
11223 goto out;
11224 }
11225
11226 size = __llvm_profile_get_size_for_buffer_internal(
11227 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11228 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11229 unused_section /* bits */, unused_section /* bits end */,
11230 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size,
11231 unused_section /* vtab */, unused_section /* vtab end */,
11232 unused_section /* vnam */, unused_section /* vnam end */);
11233
11234 if (metadata) {
11235 metadata_size = OSKextPgoMetadataSize(kext);
11236 size += metadata_size;
11237 size += sizeof(pgo_metadata_footer);
11238 }
11239
11240
11241 if (pSize) {
11242 *pSize = size;
11243 }
11244
11245 if (pBuffer && bufferSize) {
11246 if (bufferSize < size) {
11247 err = ERANGE;
11248 goto out;
11249 }
11250
11251 err = __llvm_profile_write_buffer_internal(
11252 pBuffer,
11253 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11254 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11255 unused_section /* bits */, unused_section /* bits end */,
11256 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11257
11258 if (err) {
11259 err = EIO;
11260 goto out;
11261 }
11262
11263 if (metadata) {
11264 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11265 if (offset_to_pairs > UINT32_MAX) {
11266 err = E2BIG;
11267 goto out;
11268 }
11269
11270 char *end_of_buffer = pBuffer + size;
11271 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11272 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11273
11274 size_t metadata_position = 0;
11275 uint32_t num_pairs = 0;
11276 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
11277 while (metadata_position < metadata_size) {
11278 metadata_buffer[metadata_position++] = 0;
11279 }
11280
11281 struct pgo_metadata_footer footer;
11282 footer.magic = htonl(0x6d657461);
11283 footer.number_of_pairs = htonl( num_pairs );
11284 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11285 memcpy(footerp, &footer, sizeof(footer));
11286 }
11287 }
11288
11289 out:
11290 return err;
11291 }
11292
11293
11294 int
11295 OSKextGrabPgoData(uuid_t uuid,
11296 uint64_t *pSize,
11297 char *pBuffer,
11298 uint64_t bufferSize,
11299 int wait_for_unload,
11300 int metadata)
11301 {
11302 int err = 0;
11303 OSSharedPtr<OSKext> kext;
11304
11305
11306 IORecursiveLockLock(sKextLock);
11307
11308 kext = OSKext::lookupKextWithUUID(uuid);
11309 if (!kext) {
11310 err = ENOENT;
11311 goto out;
11312 }
11313
11314 if (wait_for_unload) {
11315 OSKextGrabPgoStruct s;
11316
11317 s.metadata = metadata;
11318 s.pSize = pSize;
11319 s.pBuffer = pBuffer;
11320 s.bufferSize = bufferSize;
11321 s.err = EINTR;
11322
11323 struct list_head *prev = &kext->pendingPgoHead;
11324 struct list_head *next = kext->pendingPgoHead.next;
11325
11326 s.list_head.prev = prev;
11327 s.list_head.next = next;
11328
11329 prev->next = &s.list_head;
11330 next->prev = &s.list_head;
11331
11332 kext.reset();
11333
11334 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
11335
11336 prev = s.list_head.prev;
11337 next = s.list_head.next;
11338
11339 prev->next = next;
11340 next->prev = prev;
11341
11342 err = s.err;
11343 } else {
11344 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
11345 }
11346
11347 out:
11348
11349 IORecursiveLockUnlock(sKextLock);
11350
11351 return err;
11352 }
11353
11354 void
11355 OSKextResetPgoCountersLock()
11356 {
11357 IORecursiveLockLock(sKextLock);
11358 }
11359
11360 void
11361 OSKextResetPgoCountersUnlock()
11362 {
11363 IORecursiveLockUnlock(sKextLock);
11364 }
11365
11366
11367 extern unsigned int not_in_kdp;
11368
11369 void
11370 OSKextResetPgoCounters()
11371 {
11372 assert(!not_in_kdp);
11373 uint32_t count = sLoadedKexts->getCount();
11374 for (uint32_t i = 0; i < count; i++) {
11375 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11376 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11377 if (!sect_prf_cnts) {
11378 continue;
11379 }
11380 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
11381 }
11382 }
11383
11384 OSSharedPtr<OSDictionary>
11385 OSKext::copyLoadedKextInfoByUUID(
11386 OSArray * kextIdentifiers,
11387 OSArray * infoKeys)
11388 {
11389 OSSharedPtr<OSDictionary> result;
11390 OSSharedPtr<OSDictionary> kextInfo;
11391 uint32_t max_count, i, j;
11392 uint32_t idCount = 0;
11393 uint32_t idIndex = 0;
11394 IORecursiveLockLock(sKextLock);
11395 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11396 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11397
11398 #if CONFIG_MACF
11399 /* Is the calling process allowed to query kext info? */
11400 if (current_task() != kernel_task) {
11401 int macCheckResult = 0;
11402 kauth_cred_t cred = NULL;
11403
11404 cred = kauth_cred_get_with_ref();
11405 macCheckResult = mac_kext_check_query(cred);
11406 kauth_cred_unref(&cred);
11407
11408 if (macCheckResult != 0) {
11409 OSKextLog(/* kext */ NULL,
11410 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11411 "Failed to query kext info (MAC policy error 0x%x).",
11412 macCheckResult);
11413 goto finish;
11414 }
11415 }
11416 #endif
11417
11418 /* Empty list of UUIDs is equivalent to no list (get all).
11419 */
11420 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11421 kextIdentifiers = NULL;
11422 } else if (kextIdentifiers) {
11423 idCount = kextIdentifiers->getCount();
11424 }
11425
11426 /* Same for keys.
11427 */
11428 if (infoKeys && !infoKeys->getCount()) {
11429 infoKeys = NULL;
11430 }
11431
11432 max_count = count[0] + count[1];
11433 result = OSDictionary::withCapacity(max_count);
11434 if (!result) {
11435 goto finish;
11436 }
11437
11438 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11439 for (i = 0; i < count[j]; i++) {
11440 OSKext *thisKext = NULL; // do not release
11441 Boolean includeThis = true;
11442 uuid_t thisKextUUID;
11443 uuid_t thisKextTextUUID;
11444 OSSharedPtr<OSData> uuid_data;
11445 uuid_string_t uuid_key;
11446
11447 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11448 if (!thisKext) {
11449 continue;
11450 }
11451
11452 uuid_data = thisKext->copyUUID();
11453 if (!uuid_data) {
11454 continue;
11455 }
11456
11457 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
11458
11459 uuid_unparse(thisKextUUID, uuid_key);
11460
11461 uuid_data = thisKext->copyTextUUID();
11462 if (!uuid_data) {
11463 continue;
11464 }
11465 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
11466
11467 /* Skip current kext if we have a list of UUIDs and
11468 * it isn't in the list.
11469 */
11470 if (kextIdentifiers) {
11471 includeThis = false;
11472
11473 for (idIndex = 0; idIndex < idCount; idIndex++) {
11474 const OSString* wantedUUID = OSDynamicCast(OSString,
11475 kextIdentifiers->getObject(idIndex));
11476
11477 uuid_t uuid;
11478 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
11479
11480 if ((0 == uuid_compare(uuid, thisKextUUID))
11481 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
11482 includeThis = true;
11483 /* Only need to find the first kext if multiple match,
11484 * ie. asking for the kernel uuid does not need to find
11485 * interface kexts or builtin static kexts.
11486 */
11487 kextIdentifiers->removeObject(idIndex);
11488 uuid_unparse(uuid, uuid_key);
11489 break;
11490 }
11491 }
11492 }
11493
11494 if (!includeThis) {
11495 continue;
11496 }
11497
11498 kextInfo = thisKext->copyInfo(infoKeys);
11499 if (kextInfo) {
11500 result->setObject(uuid_key, kextInfo.get());
11501 }
11502
11503 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11504 goto finish;
11505 }
11506 }
11507 }
11508
11509 finish:
11510 IORecursiveLockUnlock(sKextLock);
11511
11512 return result;
11513 }
11514
11515 /*********************************************************************
11516 *********************************************************************/
11517 /* static */
11518 OSSharedPtr<OSDictionary>
11519 OSKext::copyKextCollectionInfo(
11520 OSDictionary *requestDict,
11521 OSArray *infoKeys)
11522 {
11523 OSSharedPtr<OSDictionary> result;
11524 OSString *collectionType = NULL;
11525 OSObject *rawLoadedState = NULL;
11526 OSString *loadedState = NULL;
11527
11528 kc_kind_t kc_request_kind = KCKindUnknown;
11529 bool onlyLoaded = false;
11530 bool onlyUnloaded = false;
11531
11532 #if CONFIG_MACF
11533 /* Is the calling process allowed to query kext info? */
11534 if (current_task() != kernel_task) {
11535 int macCheckResult = 0;
11536 kauth_cred_t cred = NULL;
11537
11538 cred = kauth_cred_get_with_ref();
11539 macCheckResult = mac_kext_check_query(cred);
11540 kauth_cred_unref(&cred);
11541
11542 if (macCheckResult != 0) {
11543 OSKextLog(/* kext */ NULL,
11544 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11545 "Failed to query kext info (MAC policy error 0x%x).",
11546 macCheckResult);
11547 goto finish;
11548 }
11549 }
11550 #endif
11551
11552 if (infoKeys && !infoKeys->getCount()) {
11553 infoKeys = NULL;
11554 }
11555
11556 collectionType = OSDynamicCast(OSString,
11557 _OSKextGetRequestArgument(requestDict,
11558 kKextRequestArgumentCollectionTypeKey));
11559 if (!collectionType) {
11560 OSKextLog(/* kext */ NULL,
11561 kOSKextLogErrorLevel |
11562 kOSKextLogIPCFlag,
11563 "Invalid '%s' argument to kext collection info request.",
11564 kKextRequestArgumentCollectionTypeKey);
11565 goto finish;
11566 }
11567 if (collectionType->isEqualTo(kKCTypePrimary)) {
11568 kc_request_kind = KCKindPrimary;
11569 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11570 kc_request_kind = KCKindPageable;
11571 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11572 kc_request_kind = KCKindAuxiliary;
11573 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11574 kc_request_kind = KCKindNone;
11575 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11576 OSKextLog(/* kext */ NULL,
11577 kOSKextLogErrorLevel |
11578 kOSKextLogIPCFlag,
11579 "Invalid '%s' argument value '%s' to kext collection info request.",
11580 kKextRequestArgumentCollectionTypeKey,
11581 collectionType->getCStringNoCopy());
11582 goto finish;
11583 }
11584
11585 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11586 kKextRequestArgumentLoadedStateKey);
11587 if (rawLoadedState) {
11588 loadedState = OSDynamicCast(OSString, rawLoadedState);
11589 if (!loadedState) {
11590 OSKextLog(/* kext */ NULL,
11591 kOSKextLogErrorLevel |
11592 kOSKextLogIPCFlag,
11593 "Invalid '%s' argument to kext collection info request.",
11594 kKextRequestArgumentLoadedStateKey);
11595 goto finish;
11596 }
11597 }
11598 if (loadedState) {
11599 if (loadedState->isEqualTo("Loaded")) {
11600 onlyLoaded = true;
11601 } else if (loadedState->isEqualTo("Unloaded")) {
11602 onlyUnloaded = true;
11603 } else if (!loadedState->isEqualTo("Any")) {
11604 OSKextLog(/* kext */ NULL,
11605 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11606 "Invalid '%s' argument value '%s' for '%s' collection info",
11607 kKextRequestArgumentLoadedStateKey,
11608 loadedState->getCStringNoCopy(),
11609 collectionType->getCStringNoCopy());
11610 goto finish;
11611 }
11612 }
11613
11614 result = OSDictionary::withCapacity(sKextsByID->getCount());
11615 if (!result) {
11616 goto finish;
11617 }
11618
11619 IORecursiveLockLock(sKextLock);
11620 { // start block scope
11621 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11622 {
11623 OSKext *thisKext = NULL; // do not release
11624 OSSharedPtr<OSDictionary> kextInfo;
11625
11626 (void)thisKextID;
11627
11628 thisKext = OSDynamicCast(OSKext, obj);
11629 if (!thisKext) {
11630 return false;
11631 }
11632
11633 /*
11634 * skip the kext if it came from the wrong collection type
11635 * (and the caller requested a specific type)
11636 */
11637 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11638 return false;
11639 }
11640
11641 /*
11642 * respect the caller's desire to find only loaded or
11643 * unloaded kexts
11644 */
11645 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11646 return false;
11647 }
11648 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11649 return false;
11650 }
11651
11652 kextInfo = thisKext->copyInfo(infoKeys);
11653 if (kextInfo) {
11654 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11655 }
11656 return false;
11657 });
11658 } // end block scope
11659 IORecursiveLockUnlock(sKextLock);
11660
11661 finish:
11662 return result;
11663 }
11664
11665 /* static */
11666 OSSharedPtr<OSArray>
11667 OSKext::copyDextsInfo(
11668 OSArray *kextIdentifiers,
11669 OSArray *infoKeys)
11670 {
11671 OSSharedPtr<OSArray> result = NULL;
11672 uint32_t idCount = 0;
11673 bool getActive = false;
11674 bool getLoaded = false;
11675 bool getUnloaded = false;
11676 bool getPendingUpgrade = false;
11677 unsigned int avgDextCount = 0;
11678
11679 #if CONFIG_MACF
11680 /* Is the calling process allowed to query dext info? */
11681 if (current_task() != kernel_task) {
11682 int macCheckResult = 0;
11683 kauth_cred_t cred = NULL;
11684
11685 cred = kauth_cred_get_with_ref();
11686 macCheckResult = mac_kext_check_query(cred);
11687 kauth_cred_unref(&cred);
11688
11689 if (macCheckResult != 0) {
11690 OSKextLog(/* kext */ NULL,
11691 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11692 "Failed to query kext info (MAC policy error 0x%x).",
11693 macCheckResult);
11694 goto finish;
11695 }
11696 }
11697 #endif
11698 /*
11699 * No infoKeys means return everything we
11700 * know about the dexts.
11701 */
11702 if (infoKeys && !infoKeys->getCount()) {
11703 infoKeys = NULL;
11704 }
11705
11706 /*
11707 * Empty list of bundle ids is equivalent to
11708 * no list (get all).
11709 */
11710 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11711 kextIdentifiers = NULL;
11712 } else if (kextIdentifiers) {
11713 idCount = kextIdentifiers->getCount();
11714 }
11715
11716 /*
11717 * Caller can specify which state of dexts to query.
11718 */
11719 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveKey)) {
11720 getActive = true;
11721 }
11722 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11723 getLoaded = true;
11724 }
11725 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11726 getUnloaded = true;
11727 }
11728 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11729 getPendingUpgrade = true;
11730 }
11731
11732 /*
11733 * By default we are going to return all active and pendingUpgrade dexts
11734 * only.
11735 */
11736 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11737 getActive = true;
11738 getPendingUpgrade = true;
11739 }
11740
11741 /*
11742 * We return a dictionary of dexts
11743 * for every group requested.
11744 */
11745 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11746 result = OSArray::withCapacity(avgDextCount);
11747 if (!result) {
11748 goto finish;
11749 }
11750
11751 IORecursiveLockLock(sKextLock);
11752 { // start block scope
11753 if (getActive || getLoaded || getUnloaded) {
11754 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11755 {
11756 OSKext *thisKext = NULL; // do not release
11757 OSSharedPtr<OSDictionary> kextInfo;
11758 Boolean includeThis = true;
11759 (void)thisKextID;
11760
11761 thisKext = OSDynamicCast(OSKext, obj);
11762 if (!thisKext || !thisKext->isDriverKit()) {
11763 return false;
11764 }
11765
11766 /*
11767 * Skip current dext if we have a list of bundle IDs and
11768 * it isn't in the list.
11769 */
11770 if (kextIdentifiers) {
11771 includeThis = false;
11772
11773 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11774 const OSString * thisRequestID = OSDynamicCast(OSString,
11775 kextIdentifiers->getObject(idIndex));
11776 if (thisKextID->isEqualTo(thisRequestID)) {
11777 includeThis = true;
11778 break;
11779 }
11780 }
11781 }
11782
11783 if (!includeThis) {
11784 return false;
11785 }
11786
11787 OSSharedPtr<OSString> state;
11788 if (sLoadedDriverKitKexts->getNextIndexOfObject(thisKext, 0) == -1U) {
11789 if (!(getActive || getUnloaded)) {
11790 return false;
11791 }
11792 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11793 } else {
11794 if (!(getActive || getLoaded)) {
11795 return false;
11796 }
11797 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11798 }
11799
11800 kextInfo = thisKext->copyInfo(infoKeys);
11801 if (kextInfo) {
11802 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11803 result->setObject(kextInfo.get());
11804 }
11805
11806 return false;
11807 });
11808 }
11809
11810 if (getPendingUpgrade) {
11811 sDriverKitToUpgradeByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11812 {
11813 OSKext *thisKext = NULL; // do not release
11814 OSSharedPtr<OSDictionary> kextInfo;
11815 Boolean includeThis = true;
11816 (void)thisKextID;
11817
11818 thisKext = OSDynamicCast(OSKext, obj);
11819 if (!thisKext) {
11820 return false;
11821 }
11822 __assert_only bool isDext = thisKext->isDriverKit();
11823 assert(isDext == true);
11824
11825 /*
11826 * Skip current dext if we have a list of bundle IDs and
11827 * it isn't in the list.
11828 */
11829 if (kextIdentifiers) {
11830 includeThis = false;
11831
11832 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11833 const OSString * thisRequestID = OSDynamicCast(OSString,
11834 kextIdentifiers->getObject(idIndex));
11835 if (thisKextID->isEqualTo(thisRequestID)) {
11836 includeThis = true;
11837 break;
11838 }
11839 }
11840 }
11841
11842 if (!includeThis) {
11843 return false;
11844 }
11845
11846 kextInfo = thisKext->copyInfo(infoKeys);
11847 if (kextInfo) {
11848 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11849 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11850 result->setObject(kextInfo.get());
11851 }
11852 return false;
11853 });
11854 }
11855 } // end block scope
11856 IORecursiveLockUnlock(sKextLock);
11857 finish:
11858 return result;
11859 }
11860
11861 /*********************************************************************
11862 *********************************************************************/
11863 /* static */
11864 OSSharedPtr<OSDictionary>
11865 OSKext::copyLoadedKextInfo(
11866 OSArray * kextIdentifiers,
11867 OSArray * infoKeys)
11868 {
11869 OSSharedPtr<OSDictionary> result;
11870 uint32_t idCount = 0;
11871 bool onlyLoaded;
11872
11873 IORecursiveLockLock(sKextLock);
11874
11875 #if CONFIG_MACF
11876 /* Is the calling process allowed to query kext info? */
11877 if (current_task() != kernel_task) {
11878 int macCheckResult = 0;
11879 kauth_cred_t cred = NULL;
11880
11881 cred = kauth_cred_get_with_ref();
11882 macCheckResult = mac_kext_check_query(cred);
11883 kauth_cred_unref(&cred);
11884
11885 if (macCheckResult != 0) {
11886 OSKextLog(/* kext */ NULL,
11887 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11888 "Failed to query kext info (MAC policy error 0x%x).",
11889 macCheckResult);
11890 goto finish;
11891 }
11892 }
11893 #endif
11894
11895 /* Empty list of bundle ids is equivalent to no list (get all).
11896 */
11897 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11898 kextIdentifiers = NULL;
11899 } else if (kextIdentifiers) {
11900 idCount = kextIdentifiers->getCount();
11901 }
11902
11903 /* Same for keys.
11904 */
11905 if (infoKeys && !infoKeys->getCount()) {
11906 infoKeys = NULL;
11907 }
11908
11909 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
11910
11911 result = OSDictionary::withCapacity(128);
11912 if (!result) {
11913 goto finish;
11914 }
11915
11916 #if 0
11917 OSKextLog(/* kext */ NULL,
11918 kOSKextLogErrorLevel |
11919 kOSKextLogGeneralFlag,
11920 "kaslr: vm_kernel_slide 0x%lx \n",
11921 vm_kernel_slide);
11922 OSKextLog(/* kext */ NULL,
11923 kOSKextLogErrorLevel |
11924 kOSKextLogGeneralFlag,
11925 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11926 vm_kernel_stext, vm_kernel_etext);
11927 OSKextLog(/* kext */ NULL,
11928 kOSKextLogErrorLevel |
11929 kOSKextLogGeneralFlag,
11930 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11931 vm_kernel_base, vm_kernel_top);
11932 OSKextLog(/* kext */ NULL,
11933 kOSKextLogErrorLevel |
11934 kOSKextLogGeneralFlag,
11935 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11936 vm_kext_base, vm_kext_top);
11937 OSKextLog(/* kext */ NULL,
11938 kOSKextLogErrorLevel |
11939 kOSKextLogGeneralFlag,
11940 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11941 vm_prelink_stext, vm_prelink_etext);
11942 OSKextLog(/* kext */ NULL,
11943 kOSKextLogErrorLevel |
11944 kOSKextLogGeneralFlag,
11945 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11946 vm_prelink_sinfo, vm_prelink_einfo);
11947 OSKextLog(/* kext */ NULL,
11948 kOSKextLogErrorLevel |
11949 kOSKextLogGeneralFlag,
11950 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11951 vm_slinkedit, vm_elinkedit);
11952 #endif
11953 { // start block scope
11954 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
11955 {
11956 OSKext * thisKext = NULL; // do not release
11957 Boolean includeThis = true;
11958 OSSharedPtr<OSDictionary> kextInfo;
11959
11960 thisKext = OSDynamicCast(OSKext, obj);
11961 if (!thisKext) {
11962 return false;
11963 }
11964
11965 /* Skip current kext if not yet started and caller didn't request all.
11966 */
11967 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11968 return false;
11969 }
11970
11971 /* Skip current kext if we have a list of bundle IDs and
11972 * it isn't in the list.
11973 */
11974 if (kextIdentifiers) {
11975 includeThis = false;
11976
11977 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11978 const OSString * thisRequestID = OSDynamicCast(OSString,
11979 kextIdentifiers->getObject(idIndex));
11980 if (thisKextID->isEqualTo(thisRequestID)) {
11981 includeThis = true;
11982 break;
11983 }
11984 }
11985 }
11986
11987 if (!includeThis) {
11988 return false;
11989 }
11990
11991 kextInfo = thisKext->copyInfo(infoKeys);
11992 if (kextInfo) {
11993 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11994 }
11995 return false;
11996 });
11997 } // end block scope
11998
11999 finish:
12000 IORecursiveLockUnlock(sKextLock);
12001
12002 return result;
12003 }
12004
12005 /*********************************************************************
12006 * Any info that needs to do allocations must goto finish on alloc
12007 * failure. Info that is just a lookup should just not set the object
12008 * if the info does not exist.
12009 *********************************************************************/
12010 #define _OSKextLoadInfoDictCapacity (12)
12011
12012 OSSharedPtr<OSDictionary>
12013 OSKext::copyInfo(OSArray * infoKeys)
12014 {
12015 OSSharedPtr<OSDictionary> result;
12016 bool success = false;
12017 OSSharedPtr<OSData> headerData;
12018 OSSharedPtr<OSData> logData;
12019 OSSharedPtr<OSNumber> cpuTypeNumber;
12020 OSSharedPtr<OSNumber> cpuSubtypeNumber;
12021 OSString * versionString = NULL; // do not release
12022 OSString * bundleType = NULL; // do not release
12023 uint32_t executablePathCStringSize = 0;
12024 char * executablePathCString = NULL; // must kfree
12025 OSSharedPtr<OSString> executablePathString;
12026 OSSharedPtr<OSData> uuid;
12027 OSSharedPtr<OSArray> dependencyLoadTags;
12028 OSSharedPtr<OSCollectionIterator> metaClassIterator;
12029 OSSharedPtr<OSArray> metaClassInfo;
12030 OSSharedPtr<OSDictionary> metaClassDict;
12031 OSMetaClass * thisMetaClass = NULL; // do not release
12032 OSSharedPtr<OSString> metaClassName;
12033 OSSharedPtr<OSString> superclassName;
12034 kc_format_t kcformat;
12035 uint32_t count, i;
12036
12037 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
12038 if (!result) {
12039 goto finish;
12040 }
12041
12042
12043 /* Empty keys means no keys, but NULL is quicker to check.
12044 */
12045 if (infoKeys && !infoKeys->getCount()) {
12046 infoKeys = NULL;
12047 }
12048
12049 if (!PE_get_primary_kc_format(&kcformat)) {
12050 goto finish;
12051 }
12052
12053 /* Headers, CPU type, and CPU subtype.
12054 */
12055 if (!infoKeys ||
12056 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
12057 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
12058 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
12059 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12060 if (linkedExecutable && !isInterface()) {
12061 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
12062 linkedExecutable->getBytesNoCopy();
12063
12064 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
12065 // do not return macho header info on shipping embedded - 19095897
12066 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
12067 kernel_mach_header_t * temp_kext_mach_hdr;
12068 struct load_command * lcp;
12069
12070 headerData = OSData::withBytes(kext_mach_hdr,
12071 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
12072 if (!headerData) {
12073 goto finish;
12074 }
12075
12076 // unslide any vmaddrs we return to userspace - 10726716
12077 temp_kext_mach_hdr = (kernel_mach_header_t *)
12078 headerData->getBytesNoCopy();
12079 if (temp_kext_mach_hdr == NULL) {
12080 goto finish;
12081 }
12082
12083 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
12084 for (i = 0; (i < temp_kext_mach_hdr->ncmds) && !flags.unslidMachO; i++) {
12085 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12086 kernel_segment_command_t * segp;
12087 kernel_section_t * secp;
12088
12089 segp = (kernel_segment_command_t *) lcp;
12090 // 10543468 - if we jettisoned __LINKEDIT clear size info
12091 if (flags.jettisonLinkeditSeg) {
12092 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
12093 segp->vmsize = 0;
12094 segp->fileoff = 0;
12095 segp->filesize = 0;
12096 }
12097 }
12098
12099 #if __arm__ || __arm64__
12100 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
12101 // and unslide them to avoid vm assertion failures / kernel logging breakage.
12102 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
12103 segp->vmaddr = gVirtBase;
12104 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
12105 secp->size = 0; // paranoia :)
12106 secp->addr = gVirtBase;
12107 }
12108 }
12109 #endif
12110
12111 #if 0
12112 OSKextLog(/* kext */ NULL,
12113 kOSKextLogErrorLevel |
12114 kOSKextLogGeneralFlag,
12115 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
12116 __FUNCTION__, segp->segname, segp->vmaddr,
12117 VM_KERNEL_UNSLIDE(segp->vmaddr),
12118 segp->vmsize, segp->nsects);
12119 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
12120 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
12121 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
12122 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
12123 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
12124 OSKextLog(/* kext */ NULL,
12125 kOSKextLogErrorLevel |
12126 kOSKextLogGeneralFlag,
12127 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
12128 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
12129 }
12130 #endif
12131 segp->vmaddr = ml_static_unslide(segp->vmaddr);
12132
12133 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
12134 secp->addr = ml_static_unslide(secp->addr);
12135 }
12136 }
12137 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
12138 }
12139 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
12140 }
12141 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
12142
12143 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12144 osLogDataHeaderRef *header;
12145 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12146
12147 void *os_log_data = NULL;
12148 void *cstring_data = NULL;
12149 void *asan_cstring_data = NULL;
12150 unsigned long os_log_size = 0;
12151 unsigned long cstring_size = 0;
12152 unsigned long asan_cstring_size = 0;
12153 uint32_t os_log_offset = 0;
12154 uint32_t cstring_offset = 0;
12155 uint32_t asan_cstring_offset = 0;
12156 bool res;
12157
12158 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
12159 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
12160 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
12161
12162 /*
12163 * If the addresses in the Mach-O header are unslid, manually
12164 * slide them to allow for dereferencing.
12165 */
12166 if (flags.unslidMachO) {
12167 os_log_data = (os_log_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)os_log_data) : nullptr;
12168 cstring_data = (cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)cstring_data) : nullptr;
12169 asan_cstring_data = (asan_cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)asan_cstring_data) : nullptr;
12170 }
12171
12172 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
12173 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
12174 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
12175
12176 header = (osLogDataHeaderRef *) headerBytes;
12177 header->version = OS_LOG_HDR_VERSION;
12178 header->sect_count = NUM_OS_LOG_SECTIONS;
12179 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
12180 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
12181 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
12182 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
12183 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
12184 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
12185
12186
12187 logData = OSData::withValue(*header);
12188 if (!logData) {
12189 goto finish;
12190 }
12191 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12192 if (!res) {
12193 goto finish;
12194 }
12195 if (os_log_data) {
12196 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
12197 if (!res) {
12198 goto finish;
12199 }
12200 }
12201 if (cstring_data) {
12202 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
12203 if (!res) {
12204 goto finish;
12205 }
12206 }
12207 if (asan_cstring_data) {
12208 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
12209 if (!res) {
12210 goto finish;
12211 }
12212 }
12213 result->setObject(kOSBundleLogStringsKey, logData.get());
12214 }
12215
12216 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
12217 cpuTypeNumber = OSNumber::withNumber(
12218 (uint64_t) kext_mach_hdr->cputype,
12219 8 * sizeof(kext_mach_hdr->cputype));
12220 if (!cpuTypeNumber) {
12221 goto finish;
12222 }
12223 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
12224 }
12225
12226 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12227 cpuSubtypeNumber = OSNumber::withNumber(
12228 (uint64_t) kext_mach_hdr->cpusubtype,
12229 8 * sizeof(kext_mach_hdr->cpusubtype));
12230 if (!cpuSubtypeNumber) {
12231 goto finish;
12232 }
12233 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
12234 }
12235 } else {
12236 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12237 osLogDataHeaderRef *header;
12238 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12239 bool res;
12240
12241 header = (osLogDataHeaderRef *) headerBytes;
12242 header->version = OS_LOG_HDR_VERSION;
12243 header->sect_count = NUM_OS_LOG_SECTIONS;
12244 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
12245 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
12246 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
12247 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12248 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
12249 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12250
12251 logData = OSData::withValue(*header);
12252 if (!logData) {
12253 goto finish;
12254 }
12255 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12256 if (!res) {
12257 goto finish;
12258 }
12259 result->setObject(kOSBundleLogStringsKey, logData.get());
12260 }
12261 }
12262 }
12263
12264 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
12265 */
12266 result->setObject(kCFBundleIdentifierKey, bundleID.get());
12267
12268 /* kOSBundleDextUniqueIdentifierKey if present.
12269 */
12270 if (isDriverKit() && dextUniqueID != NULL) {
12271 result->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID.get());
12272 }
12273
12274 /* CFBundlePackageType
12275 */
12276 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12277 if (bundleType) {
12278 result->setObject(kCFBundlePackageTypeKey, bundleType);
12279 }
12280
12281 /* CFBundleVersion.
12282 */
12283 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
12284 versionString = OSDynamicCast(OSString,
12285 getPropertyForHostArch(kCFBundleVersionKey));
12286 if (versionString) {
12287 result->setObject(kCFBundleVersionKey, versionString);
12288 }
12289 }
12290
12291 /* OSBundleCompatibleVersion.
12292 */
12293 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
12294 versionString = OSDynamicCast(OSString,
12295 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12296 if (versionString) {
12297 result->setObject(kOSBundleCompatibleVersionKey, versionString);
12298 }
12299 }
12300
12301 /* Path.
12302 */
12303 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
12304 if (path) {
12305 result->setObject(kOSBundlePathKey, path.get());
12306 }
12307 }
12308
12309
12310 /* OSBundleExecutablePath.
12311 */
12312 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
12313 if (path && executableRelPath) {
12314 uint32_t pathLength = path->getLength(); // gets incremented below
12315
12316 // +1 for slash, +1 for \0
12317 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12318
12319 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12320 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12321 if (!executablePathCString) {
12322 goto finish;
12323 }
12324 strlcpy(executablePathCString, path->getCStringNoCopy(),
12325 executablePathCStringSize);
12326 executablePathCString[pathLength++] = '/';
12327 executablePathCString[pathLength++] = '\0';
12328 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
12329 executablePathCStringSize);
12330
12331 executablePathString = OSString::withCString(executablePathCString);
12332
12333 if (!executablePathString) {
12334 goto finish;
12335 }
12336
12337 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12338 } else if (flags.builtin) {
12339 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
12340 } else if (isDriverKit()) {
12341 if (path) {
12342 // +1 for slash, +1 for \0
12343 uint32_t pathLength = path->getLength();
12344 executablePathCStringSize = pathLength + 2;
12345
12346 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12347 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12348 if (!executablePathCString) {
12349 goto finish;
12350 }
12351 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
12352 executablePathCString[pathLength++] = '/';
12353 executablePathCString[pathLength++] = '\0';
12354
12355 executablePathString = OSString::withCString(executablePathCString);
12356
12357 if (!executablePathString) {
12358 goto finish;
12359 }
12360
12361 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12362 }
12363 }
12364 }
12365
12366 /* UUID, if the kext has one.
12367 */
12368 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
12369 uuid = copyUUID();
12370 if (uuid) {
12371 result->setObject(kOSBundleUUIDKey, uuid.get());
12372 }
12373 }
12374 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
12375 uuid = copyTextUUID();
12376 if (uuid) {
12377 result->setObject(kOSBundleTextUUIDKey, uuid.get());
12378 }
12379 }
12380
12381 /*
12382 * Info.plist digest
12383 */
12384 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
12385 OSData *digest;
12386 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12387 if (digest) {
12388 result->setObject(kOSKextInfoPlistDigestKey, digest);
12389 }
12390 }
12391
12392 /*
12393 * Collection type
12394 */
12395 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
12396 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
12397 }
12398
12399 /*
12400 * Collection availability
12401 */
12402 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
12403 result->setObject(kOSKextAuxKCAvailabilityKey,
12404 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12405 }
12406
12407 /*
12408 * Allows user load
12409 */
12410 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
12411 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12412 if (allowUserLoad) {
12413 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
12414 }
12415 }
12416
12417 /*
12418 * Bundle Dependencies (OSBundleLibraries)
12419 */
12420 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
12421 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12422 if (libraries) {
12423 result->setObject(kOSBundleLibrariesKey, libraries);
12424 }
12425 }
12426
12427 /*****
12428 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12429 */
12430 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
12431 result->setObject(kOSKernelResourceKey,
12432 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12433 }
12434
12435 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
12436 result->setObject(kOSBundleIsInterfaceKey,
12437 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12438 }
12439
12440 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
12441 result->setObject(kOSBundlePrelinkedKey,
12442 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12443 }
12444
12445 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
12446 result->setObject(kOSBundleStartedKey,
12447 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12448 }
12449
12450 /* LoadTag (Index).
12451 */
12452 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
12453 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
12454 /* numBits */ 8 * sizeof(loadTag));
12455 if (!scratchNumber) {
12456 goto finish;
12457 }
12458 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
12459 }
12460
12461 /* LoadAddress, LoadSize.
12462 */
12463 if (!infoKeys ||
12464 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
12465 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
12466 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
12467 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
12468 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12469 bool is_dext = isDriverKit();
12470 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12471 /* These go to userspace via serialization, so we don't want any doubts
12472 * about their size.
12473 */
12474 uint64_t loadAddress = 0;
12475 uint32_t loadSize = 0;
12476 uint32_t wiredSize = 0;
12477 uint64_t execLoadAddress = 0;
12478 uint32_t execLoadSize = 0;
12479
12480 /* Interfaces always report 0 load address & size.
12481 * Just the way they roll.
12482 *
12483 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12484 * xxx - shouldn't have one!
12485 */
12486
12487 if (flags.builtin || linkedExecutable) {
12488 kernel_mach_header_t *mh = NULL;
12489 kernel_segment_command_t *seg = NULL;
12490
12491 if (flags.builtin) {
12492 loadAddress = kmod_info->address;
12493 loadSize = (uint32_t)kmod_info->size;
12494 } else {
12495 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12496 loadSize = linkedExecutable->getLength();
12497 }
12498 mh = (kernel_mach_header_t *)loadAddress;
12499 loadAddress = ml_static_unslide(loadAddress);
12500
12501 /* Walk through the kext, looking for the first executable
12502 * segment in case we were asked for its size/address.
12503 */
12504 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
12505 if (seg->initprot & VM_PROT_EXECUTE) {
12506 execLoadAddress = (flags.unslidMachO) ? seg->vmaddr : ml_static_unslide(seg->vmaddr);
12507 execLoadSize = (uint32_t)seg->vmsize;
12508 break;
12509 }
12510 }
12511
12512 /* If we have a kmod_info struct, calculated the wired size
12513 * from that. Otherwise it's the full load size.
12514 */
12515 if (kmod_info) {
12516 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12517 } else {
12518 wiredSize = loadSize;
12519 }
12520 } else if (is_dext) {
12521 /*
12522 * DriverKit userspace executables do not have a kernel linkedExecutable,
12523 * so we "fake" their address range with the LoadTag.
12524 */
12525 if (loadTag) {
12526 loadAddress = execLoadAddress = loadTag;
12527 loadSize = execLoadSize = 1;
12528 }
12529 }
12530
12531 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
12532 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12533 (unsigned long long)(loadAddress),
12534 /* numBits */ 8 * sizeof(loadAddress));
12535 if (!scratchNumber) {
12536 goto finish;
12537 }
12538 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
12539 }
12540 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12541 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
12542 && loadAddress && loadSize) {
12543 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
12544 if (!baseAddress) {
12545 goto finish;
12546 }
12547
12548 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12549 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
12550 /* numBits */ 8 * sizeof(loadAddress));
12551 if (!scratchNumber) {
12552 goto finish;
12553 }
12554 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
12555 }
12556 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
12557 && (this == sKernelKext) && gBuiltinKmodsCount) {
12558 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
12559 }
12560 }
12561
12562 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
12563 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12564 (unsigned long long)(execLoadAddress),
12565 /* numBits */ 8 * sizeof(execLoadAddress));
12566 if (!scratchNumber) {
12567 goto finish;
12568 }
12569 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
12570 }
12571 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
12572 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12573 (unsigned long long)(loadSize),
12574 /* numBits */ 8 * sizeof(loadSize));
12575 if (!scratchNumber) {
12576 goto finish;
12577 }
12578 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
12579 }
12580 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
12581 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12582 (unsigned long long)(execLoadSize),
12583 /* numBits */ 8 * sizeof(execLoadSize));
12584 if (!scratchNumber) {
12585 goto finish;
12586 }
12587 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
12588 }
12589 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12590 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12591 (unsigned long long)(wiredSize),
12592 /* numBits */ 8 * sizeof(wiredSize));
12593 if (!scratchNumber) {
12594 goto finish;
12595 }
12596 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
12597 }
12598 }
12599 }
12600
12601 /* OSBundleDependencies. In descending order for
12602 * easy compatibility with kextstat(8).
12603 */
12604 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
12605 if ((count = getNumDependencies())) {
12606 dependencyLoadTags = OSArray::withCapacity(count);
12607 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
12608
12609 i = count - 1;
12610 do {
12611 OSKext * dependency = OSDynamicCast(OSKext,
12612 dependencies->getObject(i));
12613
12614 if (!dependency) {
12615 continue;
12616 }
12617 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12618 (unsigned long long)dependency->getLoadTag(),
12619 /* numBits*/ 8 * sizeof(loadTag));
12620 if (!scratchNumber) {
12621 goto finish;
12622 }
12623 dependencyLoadTags->setObject(scratchNumber.get());
12624 } while (i--);
12625 }
12626 }
12627
12628 /* OSBundleMetaClasses.
12629 */
12630 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
12631 if (metaClasses && metaClasses->getCount()) {
12632 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
12633 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
12634 if (!metaClassIterator || !metaClassInfo) {
12635 goto finish;
12636 }
12637 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
12638
12639 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12640 metaClassIterator->getNextObject()))) {
12641 metaClassDict = OSDictionary::withCapacity(3);
12642 if (!metaClassDict) {
12643 goto finish;
12644 }
12645
12646 metaClassName = OSString::withCString(thisMetaClass->getClassName());
12647 if (thisMetaClass->getSuperClass()) {
12648 superclassName = OSString::withCString(
12649 thisMetaClass->getSuperClass()->getClassName());
12650 }
12651 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
12652 8 * sizeof(unsigned int));
12653
12654 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12655 * of course.
12656 */
12657 if (!metaClassDict || !metaClassName || !scratchNumber) {
12658 goto finish;
12659 }
12660
12661 metaClassInfo->setObject(metaClassDict.get());
12662 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
12663 if (superclassName) {
12664 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
12665 }
12666 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
12667 }
12668 }
12669 }
12670
12671 /* OSBundleRetainCount.
12672 */
12673 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
12674 {
12675 int kextRetainCount = getRetainCount() - 1;
12676 if (isLoaded()) {
12677 kextRetainCount--;
12678 }
12679 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12680 (int)kextRetainCount,
12681 /* numBits*/ 8 * sizeof(int));
12682 if (scratchNumber) {
12683 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
12684 }
12685 }
12686 }
12687
12688 success = true;
12689
12690 finish:
12691 if (executablePathCString) {
12692 kfree_data(executablePathCString, executablePathCStringSize);
12693 }
12694 if (!success) {
12695 result.reset();
12696 }
12697 return result;
12698 }
12699
12700 /*********************************************************************
12701 *********************************************************************/
12702 /* static */
12703 bool
12704 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12705 {
12706 bool ok;
12707 OSSharedPtr<OSKext> kext;
12708
12709 IORecursiveLockLock(sKextLock);
12710 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12711 IORecursiveLockUnlock(sKextLock);
12712
12713 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12714 return false;
12715 }
12716 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
12717 kext->path->getCStringNoCopy(),
12718 kext->userExecutableRelPath->getCStringNoCopy());
12719 ok = true;
12720
12721 return ok;
12722 }
12723
12724 /*********************************************************************
12725 *********************************************************************/
12726 /* static */
12727 OSReturn
12728 OSKext::requestResource(
12729 const char * kextIdentifierCString,
12730 const char * resourceNameCString,
12731 OSKextRequestResourceCallback callback,
12732 void * context,
12733 OSKextRequestTag * requestTagOut)
12734 {
12735 OSReturn result = kOSReturnError;
12736 OSSharedPtr<OSKext> callbackKext; // looked up
12737
12738 OSKextRequestTag requestTag = -1;
12739 OSSharedPtr<OSNumber> requestTagNum;
12740 OSSharedPtr<OSDictionary> requestDict;
12741 OSSharedPtr<OSString> kextIdentifier;
12742 OSSharedPtr<OSString> resourceName;
12743
12744 OSSharedPtr<OSDictionary> callbackRecord;
12745 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12746
12747 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12748
12749 IORecursiveLockLock(sKextLock);
12750
12751 if (requestTagOut) {
12752 *requestTagOut = kOSKextRequestTagInvalid;
12753 }
12754
12755 /* If requests to user space are disabled, don't go any further */
12756 if (!sKernelRequestsEnabled) {
12757 OSKextLog(/* kext */ NULL,
12758 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12759 "Can't request resource %s for %s - requests to user space are disabled.",
12760 resourceNameCString,
12761 kextIdentifierCString);
12762 result = kOSKextReturnDisabled;
12763 goto finish;
12764 }
12765
12766 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12767 result = kOSKextReturnInvalidArgument;
12768 goto finish;
12769 }
12770
12771 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12772 if (!callbackKext) {
12773 OSKextLog(/* kext */ NULL,
12774 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12775 "Resource request has bad callback address.");
12776 result = kOSKextReturnInvalidArgument;
12777 goto finish;
12778 }
12779 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12780 OSKextLog(/* kext */ NULL,
12781 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12782 "Resource request callback is in a kext that is not started.");
12783 result = kOSKextReturnInvalidArgument;
12784 goto finish;
12785 }
12786
12787 /* Do not allow any new requests to be made on a kext that is unloading.
12788 */
12789 if (callbackKext->flags.stopping) {
12790 result = kOSKextReturnStopping;
12791 goto finish;
12792 }
12793
12794 /* If we're wrapped the next available request tag around to the negative
12795 * numbers, we can't service any more requests.
12796 */
12797 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12798 OSKextLog(/* kext */ NULL,
12799 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12800 "No more request tags available; restart required.");
12801 result = kOSKextReturnNoResources;
12802 goto finish;
12803 }
12804 requestTag = sNextRequestTag++;
12805
12806 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12807 requestDict);
12808 if (result != kOSReturnSuccess) {
12809 goto finish;
12810 }
12811
12812 kextIdentifier = OSString::withCString(kextIdentifierCString);
12813 resourceName = OSString::withCString(resourceNameCString);
12814 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12815 8 * sizeof(requestTag));
12816 if (!kextIdentifier ||
12817 !resourceName ||
12818 !requestTagNum ||
12819 !_OSKextSetRequestArgument(requestDict.get(),
12820 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
12821 !_OSKextSetRequestArgument(requestDict.get(),
12822 kKextRequestArgumentNameKey, resourceName.get()) ||
12823 !_OSKextSetRequestArgument(requestDict.get(),
12824 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
12825 result = kOSKextReturnNoMemory;
12826 goto finish;
12827 }
12828
12829 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
12830 if (!callbackRecord) {
12831 result = kOSKextReturnNoMemory;
12832 goto finish;
12833 }
12834 // we validate callback address at call time
12835 callbackWrapper = OSValueObjectWithValue(callback);
12836 if (context) {
12837 contextWrapper = OSValueObjectWithValue(context);
12838 }
12839 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12840 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
12841 result = kOSKextReturnNoMemory;
12842 goto finish;
12843 }
12844
12845 if (context) {
12846 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12847 kKextRequestArgumentContextKey, contextWrapper.get())) {
12848 result = kOSKextReturnNoMemory;
12849 goto finish;
12850 }
12851 }
12852
12853 /* Only post the requests after all the other potential failure points
12854 * have been passed.
12855 */
12856 if (!sKernelRequests->setObject(requestDict.get()) ||
12857 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12858 result = kOSKextReturnNoMemory;
12859 goto finish;
12860 }
12861
12862 OSKext::pingIOKitDaemon();
12863
12864 result = kOSReturnSuccess;
12865 if (requestTagOut) {
12866 *requestTagOut = requestTag;
12867 }
12868
12869 finish:
12870
12871 /* If we didn't succeed, yank the request & callback
12872 * from their holding arrays.
12873 */
12874 if (result != kOSReturnSuccess) {
12875 unsigned int index;
12876
12877 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
12878 if (index != (unsigned int)-1) {
12879 sKernelRequests->removeObject(index);
12880 }
12881 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
12882 if (index != (unsigned int)-1) {
12883 sRequestCallbackRecords->removeObject(index);
12884 }
12885 }
12886
12887 OSKext::considerUnloads(/* rescheduleOnly? */ true);
12888
12889 IORecursiveLockUnlock(sKextLock);
12890
12891 return result;
12892 }
12893
12894 OSReturn
12895 OSKext::requestDaemonLaunch(
12896 OSString *kextIdentifier,
12897 OSString *serverName,
12898 OSNumber *serverTag,
12899 OSBoolean *reslide,
12900 IOUserServerCheckInToken * checkInToken,
12901 OSData *serverDUI)
12902 {
12903 OSReturn result = kOSReturnError;
12904 OSSharedPtr<OSDictionary> requestDict;
12905 unsigned int size = 0;
12906 const char *dextUniqueIDCString = NULL;
12907
12908 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12909 return kOSKextReturnInvalidArgument;
12910 }
12911 if (!iokitDaemonAvailable()) {
12912 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
12913 }
12914
12915 if (serverDUI != NULL) {
12916 dextUniqueIDCString = getDextUniqueIDCString(serverDUI, &size);
12917 }
12918
12919 IORecursiveLockLock(sKextLock);
12920
12921 OSKextLog(/* kext */ NULL,
12922 kOSKextLogDebugLevel |
12923 kOSKextLogGeneralFlag,
12924 "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12925 kextIdentifier->getCStringNoCopy(),
12926 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12927 serverName->getCStringNoCopy(),
12928 serverTag->unsigned64BitValue(),
12929 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12930 );
12931
12932 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
12933 if (result != kOSReturnSuccess) {
12934 goto finish;
12935 }
12936
12937 if (!_OSKextSetRequestArgument(requestDict.get(),
12938 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12939 !_OSKextSetRequestArgument(requestDict.get(),
12940 kKextRequestArgumentDriverExtensionServerName, serverName) ||
12941 !_OSKextSetRequestArgument(requestDict.get(),
12942 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
12943 !_OSKextSetRequestArgument(requestDict.get(),
12944 kKextRequestArgumentDriverExtensionReslideSharedCache, reslide) ||
12945 !_OSKextSetRequestArgument(requestDict.get(),
12946 kKextRequestArgumentCheckInToken, checkInToken)) {
12947 result = kOSKextReturnNoMemory;
12948 goto finish;
12949 }
12950
12951 if (serverDUI) {
12952 if (!_OSKextSetRequestArgument(requestDict.get(),
12953 kOSBundleDextUniqueIdentifierKey, serverDUI)) {
12954 result = kOSKextReturnNoMemory;
12955 goto finish;
12956 }
12957 }
12958
12959 /* Only post the requests after all the other potential failure points
12960 * have been passed.
12961 */
12962 if (!sKernelRequests->setObject(requestDict.get())) {
12963 result = kOSKextReturnNoMemory;
12964 goto finish;
12965 }
12966 result = OSKext::pingIOKitDaemon();
12967 if (result != kOSReturnSuccess) {
12968 goto finish;
12969 }
12970
12971 result = kOSReturnSuccess;
12972 finish:
12973 IORecursiveLockUnlock(sKextLock);
12974 if (dextUniqueIDCString) {
12975 kfree_data(dextUniqueIDCString, size);
12976 }
12977 return result;
12978 }
12979
12980 OSReturn
12981 OSKext::notifyDextUpgrade(
12982 OSString *kextIdentifier,
12983 OSData *dextUniqueIdentifier)
12984 {
12985 OSReturn result = kOSReturnError;
12986 OSSharedPtr<OSDictionary> requestDict;
12987 unsigned int size = 0;
12988 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueIdentifier, &size);
12989 assert(dextUniqueIDCString != NULL);
12990
12991 IORecursiveLockLock(sKextLock);
12992
12993 OSKextLog(NULL,
12994 kOSKextLogDebugLevel |
12995 kOSKextLogGeneralFlag,
12996 "Notifying of dext upgrade for %s with UniqueID %s",
12997 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
12998
12999 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestDict);
13000 if (result != kOSReturnSuccess) {
13001 goto finish;
13002 }
13003
13004 if (!_OSKextSetRequestArgument(requestDict.get(),
13005 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
13006 !_OSKextSetRequestArgument(requestDict.get(),
13007 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
13008 result = kOSKextReturnNoMemory;
13009 goto finish;
13010 }
13011
13012 /* Only post the requests after all the other potential failure points
13013 * have been passed.
13014 */
13015 if (!sKernelRequests->setObject(requestDict.get())) {
13016 result = kOSKextReturnNoMemory;
13017 goto finish;
13018 }
13019 OSKext::pingIOKitDaemon();
13020
13021 result = kOSReturnSuccess;
13022 finish:
13023 IORecursiveLockUnlock(sKextLock);
13024
13025 if (dextUniqueIDCString != NULL) {
13026 kfree_data(dextUniqueIDCString, size);
13027 }
13028 return result;
13029 }
13030
13031 /*********************************************************************
13032 * Assumes sKextLock is held.
13033 *********************************************************************/
13034 /* static */
13035 OSReturn
13036 OSKext::dequeueCallbackForRequestTag(
13037 OSKextRequestTag requestTag,
13038 OSSharedPtr<OSDictionary> &callbackRecordOut)
13039 {
13040 OSDictionary * callbackRecordOutRaw = NULL;
13041 OSReturn result;
13042
13043 result = dequeueCallbackForRequestTag(requestTag,
13044 &callbackRecordOutRaw);
13045
13046 if (kOSReturnSuccess == result) {
13047 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
13048 }
13049
13050 return result;
13051 }
13052 OSReturn
13053 OSKext::dequeueCallbackForRequestTag(
13054 OSKextRequestTag requestTag,
13055 OSDictionary ** callbackRecordOut)
13056 {
13057 OSReturn result = kOSReturnError;
13058 OSSharedPtr<OSNumber> requestTagNum;
13059
13060 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
13061 8 * sizeof(requestTag));
13062 if (!requestTagNum) {
13063 goto finish;
13064 }
13065
13066 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
13067 callbackRecordOut);
13068
13069 finish:
13070 return result;
13071 }
13072
13073 /*********************************************************************
13074 * Assumes sKextLock is held.
13075 *********************************************************************/
13076 /* static */
13077 OSReturn
13078 OSKext::dequeueCallbackForRequestTag(
13079 OSNumber * requestTagNum,
13080 OSSharedPtr<OSDictionary> &callbackRecordOut)
13081 {
13082 OSDictionary * callbackRecordOutRaw = NULL;
13083 OSReturn result;
13084
13085 result = dequeueCallbackForRequestTag(requestTagNum,
13086 &callbackRecordOutRaw);
13087
13088 if (kOSReturnSuccess == result) {
13089 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
13090 }
13091
13092 return result;
13093 }
13094 OSReturn
13095 OSKext::dequeueCallbackForRequestTag(
13096 OSNumber * requestTagNum,
13097 OSDictionary ** callbackRecordOut)
13098 {
13099 OSReturn result = kOSKextReturnInvalidArgument;
13100 OSDictionary * callbackRecord = NULL; // retain if matched!
13101 OSNumber * callbackTagNum = NULL; // do not release
13102 unsigned int count, i;
13103
13104 result = kOSReturnError;
13105 count = sRequestCallbackRecords->getCount();
13106 for (i = 0; i < count; i++) {
13107 callbackRecord = OSDynamicCast(OSDictionary,
13108 sRequestCallbackRecords->getObject(i));
13109 if (!callbackRecord) {
13110 goto finish;
13111 }
13112
13113 /* If we don't find a tag, we basically have a leak here. Maybe
13114 * we should just remove it.
13115 */
13116 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
13117 callbackRecord, kKextRequestArgumentRequestTagKey));
13118 if (!callbackTagNum) {
13119 goto finish;
13120 }
13121
13122 /* We could be even more paranoid and check that all the incoming
13123 * args match what's in the callback record.
13124 */
13125 if (callbackTagNum->isEqualTo(requestTagNum)) {
13126 if (callbackRecordOut) {
13127 *callbackRecordOut = callbackRecord;
13128 callbackRecord->retain();
13129 }
13130 sRequestCallbackRecords->removeObject(i);
13131 result = kOSReturnSuccess;
13132 goto finish;
13133 }
13134 }
13135 result = kOSKextReturnNotFound;
13136
13137 finish:
13138 return result;
13139 }
13140
13141
13142 /*********************************************************************
13143 * Busy timeout triage
13144 *********************************************************************/
13145 /* static */
13146 bool
13147 OSKext::pendingIOKitDaemonRequests(void)
13148 {
13149 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
13150 }
13151
13152 /*********************************************************************
13153 * Acquires and releases sKextLock
13154 *
13155 * This function is designed to be called by kernelmanagerd and driverkitd
13156 * and it gathers all codeless kext and dext personalities, and then attempts
13157 * to map a System (pageable) KC and an Auxiliary (aux) KC.
13158 *
13159 * The pageable and aux KC can be loaded only once at boot time.
13160 * Even if the pageable or aux KC fail to load - this function will
13161 * not allow a new pageable or aux KC to be installed by subsequent calls.
13162 * This is done to avoid security issues where userspace has been compromised
13163 * or the pageable kc has been tampered with and the attacker
13164 * attempts to re-load a malicious variant.
13165 * However dexts can be dynamically loaded, so this function can be used
13166 * to request the installation of a new set of dexts even after boot time.
13167 *
13168 *
13169 *
13170 * Return: if a KC fails to load the return value will contain:
13171 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
13172 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
13173 * Similarly, if the aux kc load fails, the return value will
13174 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
13175 * compose with each other and with kOSKextReturnKCLoadFailure.
13176 *********************************************************************/
13177 /* static */
13178 OSReturn
13179 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
13180 {
13181 static bool daemon_ready = false;
13182
13183 OSReturn ret = kOSKextReturnInvalidArgument;
13184 OSReturn kcerr = 0;
13185 bool start_matching = false;
13186
13187 bool allow_fileset_load = !daemon_ready;
13188 #if !(defined(__x86_64__) || defined(__i386__))
13189 /* never allow KCs full of kexts on non-x86 machines */
13190 allow_fileset_load = false;
13191 #endif
13192
13193 /*
13194 * Change with 70582300
13195 */
13196 #if 0 || !defined(VM_MAPPED_KEXTS)
13197 /*
13198 * On platforms that don't support the SystemKC or a file-backed
13199 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
13200 * needs to be queried before we load any codeless kexts or release
13201 * any 3rd party kexts to run. On platforms that support a file-backed
13202 * AuxKC, this process is done via the kext audit mechanism.
13203 */
13204
13205 printf("KextLog: waiting for kext receipt to be queried.\n");
13206 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
13207 IOSleep(30);
13208 }
13209 #endif /* !VM_MAPPED_KEXTS */
13210
13211 /*
13212 * Get the args from the request. Right now we need the file
13213 * name for the pageable and the aux kext collection file sets.
13214 */
13215 OSDictionary * requestArgs = NULL; // do not release
13216 OSString * pageable_filepath = NULL; // do not release
13217 OSString * aux_filepath = NULL; // do not release
13218 OSArray * codeless_kexts = NULL; // do not release
13219
13220 kernel_mach_header_t *akc_mh = NULL;
13221
13222 requestArgs = OSDynamicCast(OSDictionary,
13223 requestDict->getObject(kKextRequestArgumentsKey));
13224
13225 if (requestArgs == NULL) {
13226 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13227 "KextLog: No arguments in plist for loading fileset kext\n");
13228 printf("KextLog: No arguments in plist for loading fileset kext\n");
13229 return ret;
13230 }
13231
13232 ret = kOSKextReturnDisabled;
13233
13234 IORecursiveLockLock(sKextLock);
13235
13236 if (!sLoadEnabled) {
13237 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13238 "KextLog: Kext loading is disabled (attempt to load KCs).");
13239 IORecursiveLockUnlock(sKextLock);
13240 return ret;
13241 }
13242
13243 pageable_filepath = OSDynamicCast(OSString,
13244 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
13245
13246 if (allow_fileset_load && pageable_filepath != NULL) {
13247 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
13248
13249 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
13250 if (ret) {
13251 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13252 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13253
13254 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13255 ret = kOSKextReturnKCLoadFailure;
13256 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
13257 goto try_auxkc;
13258 }
13259 /*
13260 * Even if the AuxKC fails to load, we still want to send
13261 * the System KC personalities to the catalog for matching
13262 */
13263 start_matching = true;
13264 } else if (pageable_filepath != NULL) {
13265 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13266 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
13267 ret = kOSKextReturnUnsupported;
13268 }
13269
13270 try_auxkc:
13271 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
13272 if (akc_mh) {
13273 /*
13274 * If we try to load a deferred AuxKC, then don't ever attempt
13275 * a filesystem map of a file
13276 */
13277 allow_fileset_load = false;
13278
13279 /*
13280 * This function is only called once per boot, so we haven't
13281 * yet loaded an AuxKC. If we have registered the AuxKC mach
13282 * header, that means that the kext collection has been placed
13283 * in memory for us by the booter, and is waiting for us to
13284 * process it. Grab the deferred XML plist of info
13285 * dictionaries and add all the kexts.
13286 */
13287 OSSharedPtr<OSObject> parsedXML;
13288 OSSharedPtr<OSData> loaded_kcUUID;
13289 OSDictionary *infoDict;
13290 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
13291 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13292 #if !defined(VM_MAPPED_KEXTS)
13293 /*
13294 * On platforms where we don't dynamically wire-down / page-in
13295 * kext memory, we need to maintain the invariant that if the
13296 * AuxKC in memory does not contain a kext receipt, then we
13297 * should not load any of the kexts.
13298 */
13299 size_t receipt_sz = 0;
13300 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13301 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13302 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13303 ret = kOSKextReturnKCLoadFailure;
13304 goto try_codeless;
13305 }
13306 #endif
13307 if (infoDict) {
13308 bool added;
13309 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13310 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
13311 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
13312 if (!loaded_kcUUID) {
13313 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13314 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13315 } else if (!added) {
13316 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13317 "KextLog: WARNING: Failed to load AuxKC from memory.");
13318 }
13319 /* only return success if the pageable load (above) was successful */
13320 if (ret != kOSKextReturnKCLoadFailure) {
13321 ret = kOSReturnSuccess;
13322 }
13323 /* the registration of the AuxKC parsed out the KC's UUID already */
13324 } else {
13325 if (daemon_ready) {
13326 /*
13327 * Complain, but don't return an error if this isn't the first time the
13328 * IOKit daemon is checking in. If the daemon ever restarts, we will
13329 * hit this case because we've already consumed the deferred personalities.
13330 * We return success here so that a call to this function from a restarted
13331 * daemon with no codeless kexts will succeed.
13332 */
13333 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13334 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13335 if (ret != kOSKextReturnKCLoadFailure) {
13336 ret = kOSReturnSuccess;
13337 }
13338 } else {
13339 /* this is a real error case */
13340 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13341 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13342 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13343 ret = kOSKextReturnKCLoadFailure;
13344 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13345 }
13346 }
13347 }
13348
13349 aux_filepath = OSDynamicCast(OSString,
13350 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13351 if (allow_fileset_load && aux_filepath != NULL) {
13352 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13353
13354 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
13355 if (ret) {
13356 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13357 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13358
13359 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13360 ret = kOSKextReturnKCLoadFailure;
13361 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13362 goto try_codeless;
13363 }
13364 start_matching = true;
13365 } else if (aux_filepath != NULL) {
13366 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13367 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13368 if (ret != kOSKextReturnKCLoadFailure) {
13369 ret = kOSKextReturnUnsupported;
13370 }
13371 }
13372
13373 try_codeless:
13374 /*
13375 * Load codeless kexts last so that there is no possibilty of a
13376 * codeless kext bundle ID preventing a kext in the system KC from
13377 * loading
13378 */
13379 codeless_kexts = OSDynamicCast(OSArray,
13380 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13381 if (codeless_kexts != NULL) {
13382 uint32_t count = codeless_kexts->getCount();
13383 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13384 "KextLog: loading %d codeless kexts/dexts", count);
13385 for (uint32_t i = 0; i < count; i++) {
13386 OSDictionary *infoDict;
13387 infoDict = OSDynamicCast(OSDictionary,
13388 codeless_kexts->getObject(i));
13389 if (!infoDict) {
13390 continue;
13391 }
13392 // instantiate a new kext, and don't hold a reference
13393 // (the kext subsystem will hold one implicitly)
13394 OSKext::withCodelessInfo(infoDict, NULL);
13395 }
13396 /* ignore errors that are not KC load failures */
13397 if (ret != kOSKextReturnKCLoadFailure) {
13398 ret = kOSReturnSuccess;
13399 }
13400 start_matching = true;
13401 }
13402
13403 /* send personalities to the IOCatalog once */
13404 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13405 OSKext::sendAllKextPersonalitiesToCatalog(true);
13406 /*
13407 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13408 * things as active and start all the delayed matching: the
13409 * dext and codeless kext personalities should have all been
13410 * delivered via this one call.
13411 */
13412 if (!daemon_ready) {
13413 OSKext::setIOKitDaemonActive();
13414 OSKext::setDeferredLoadSucceeded(TRUE);
13415 IOService::iokitDaemonLaunched();
13416 }
13417 if (sOSKextWasResetAfterUserspaceReboot) {
13418 sOSKextWasResetAfterUserspaceReboot = false;
13419 OSKext::setIOKitDaemonActive();
13420 IOService::startDeferredMatches();
13421 }
13422 }
13423
13424 if (ret == kOSKextReturnKCLoadFailure) {
13425 ret |= kcerr;
13426 }
13427
13428 /*
13429 * Only allow this function to attempt to load the pageable and
13430 * aux KCs once per boot.
13431 */
13432 daemon_ready = true;
13433
13434 IORecursiveLockUnlock(sKextLock);
13435
13436 return ret;
13437 }
13438
13439 OSReturn
13440 OSKext::resetMutableSegments(void)
13441 {
13442 kernel_segment_command_t *seg = NULL;
13443 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13444 u_int index = 0;
13445 OSKextSavedMutableSegment *savedSegment = NULL;
13446 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
13447 OSReturn err;
13448
13449 if (!savedMutableSegments) {
13450 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13451 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13452 err = kOSKextReturnInternalError;
13453 goto finish;
13454 }
13455
13456 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
13457 if (!segmentIsMutable(seg)) {
13458 continue;
13459 }
13460 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13461 uint64_t vmsize = seg->vmsize;
13462 err = kOSKextReturnInternalError;
13463 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13464 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13465 assert(savedSegment);
13466 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13467 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13468 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13469 err = savedSegment->restoreContents(seg);
13470 if (err != kOSReturnSuccess) {
13471 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13472 }
13473 }
13474 }
13475 if (err != kOSReturnSuccess) {
13476 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13477 }
13478 }
13479 err = kOSReturnSuccess;
13480 finish:
13481 return err;
13482 }
13483
13484
13485 /*********************************************************************
13486 * Assumes sKextLock is held.
13487 *********************************************************************/
13488 /* static */
13489 OSReturn
13490 OSKext::loadKCFileSet(
13491 const char *filepath,
13492 kc_kind_t type)
13493 {
13494 #if VM_MAPPED_KEXTS
13495 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13496 OSReturn err;
13497 struct vnode *vp = NULL;
13498 void *fileset_control;
13499 off_t fsize;
13500 bool pageable = (type == KCKindPageable);
13501
13502 if ((pageable && pageableKCloaded) ||
13503 (!pageable && auxKCloaded)) {
13504 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13505 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13506
13507 return kOSKextReturnInvalidArgument;
13508 }
13509
13510 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13511 if (!pageable && !pageableKCloaded) {
13512 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13513 "Trying to load the Aux KC without loading the Pageable KC");
13514 return kOSKextReturnInvalidArgument;
13515 }
13516
13517 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13518
13519 if (fileset_control == NULL) {
13520 printf("Could not get memory control object for file %s", filepath);
13521
13522 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13523 "Could not get memory control object for file %s", filepath);
13524 return kOSKextReturnInvalidArgument;
13525 }
13526 if (vp == NULL) {
13527 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13528 "Could not find vnode for file %s", filepath);
13529 return kOSKextReturnInvalidArgument;
13530 }
13531
13532 kernel_mach_header_t *mh = NULL;
13533 uintptr_t slide = 0;
13534
13535 #if CONFIG_CSR
13536 /*
13537 * When SIP is enabled, the KC we map must be SIP-protected
13538 */
13539 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13540 struct vnode_attr va;
13541 int error;
13542 VATTR_INIT(&va);
13543 VATTR_WANTED(&va, va_flags);
13544 error = vnode_getattr(vp, &va, vfs_context_current());
13545 if (error) {
13546 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13547 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13548 err = kOSKextReturnInternalError;
13549 goto finish;
13550 }
13551 if (!(va.va_flags & SF_RESTRICTED)) {
13552 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13553 "Path to KC '%s' is not SIP-protected", filepath);
13554 err = kOSKextReturnInvalidArgument;
13555 goto finish;
13556 }
13557 }
13558 #endif
13559
13560 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13561 if (err) {
13562 printf("KextLog: mapKCFileSet returned %d\n", err);
13563
13564 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13565 "mapKCFileSet returned %d\n", err);
13566
13567 err = kOSKextReturnInvalidArgument;
13568 }
13569
13570 #if CONFIG_CSR
13571 finish:
13572 #endif
13573 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13574 assert(vp != NULL);
13575 if (err == kOSReturnSuccess) {
13576 PE_set_kc_vp(type, vp);
13577 if (pageable) {
13578 pageableKCloaded = true;
13579 } else {
13580 auxKCloaded = true;
13581 }
13582 } else {
13583 vnode_put(vp);
13584 }
13585
13586 return err;
13587 #else
13588 (void)filepath;
13589 (void)type;
13590 return kOSKextReturnUnsupported;
13591 #endif // VM_MAPPED_KEXTS
13592 }
13593
13594 #if defined(__x86_64__) || defined(__i386__)
13595 /*********************************************************************
13596 * Assumes sKextLock is held.
13597 *********************************************************************/
13598 /* static */
13599 OSReturn
13600 OSKext::mapKCFileSet(
13601 void *control,
13602 vm_size_t fsize,
13603 kernel_mach_header_t **mhp,
13604 off_t file_offset,
13605 uintptr_t *slidep,
13606 bool pageable,
13607 void *map_entry_list)
13608 {
13609 bool fileset_load = false;
13610 kern_return_t ret;
13611 OSReturn err;
13612 kernel_section_t *infoPlistSection = NULL;
13613 OSDictionary *infoDict = NULL;
13614
13615 OSSharedPtr<OSObject> parsedXML;
13616 OSSharedPtr<OSString> errorString;
13617 OSSharedPtr<OSData> loaded_kcUUID;
13618
13619 /* Check if initial load for file set */
13620 if (*mhp == NULL) {
13621 fileset_load = true;
13622
13623 /* Get a page aligned address from kext map to map the file */
13624 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13625 if (pagealigned_addr == 0) {
13626 return kOSKextReturnNoMemory;
13627 }
13628
13629 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13630
13631 /* Allocate memory for bailout mechanism */
13632 map_entry_list = allocate_kcfileset_map_entry_list();
13633 if (map_entry_list == NULL) {
13634 return kOSKextReturnNoMemory;
13635 }
13636 }
13637
13638 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13639 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13640 /* mhp and slideptr are updated by mapKCTextSegment */
13641 if (err) {
13642 if (fileset_load) {
13643 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13644 }
13645 return err;
13646 }
13647
13648 /* Initialize the kc header globals */
13649 if (fileset_load) {
13650 if (pageable) {
13651 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13652 } else {
13653 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13654 }
13655 }
13656
13657 /* Iterate through all the segments and map necessary segments */
13658 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13659 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13660 vm_map_offset_t start;
13661 kernel_mach_header_t *k_mh = NULL;
13662 kernel_segment_command_t * seg = NULL;
13663 struct fileset_entry_command *fse = NULL;
13664
13665 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13666 seg = (kernel_segment_command_t *)lcp;
13667 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13668 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13669 fse = (struct fileset_entry_command *)lcp;
13670 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13671
13672 /* Map the segments of the mach-o binary */
13673 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13674 if (err) {
13675 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13676 return kOSKextReturnInvalidArgument;
13677 }
13678 continue;
13679 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13680 /* Check if the Aux KC is built pageable style */
13681 if (!pageable && !fileset_load && !auxKCloaded) {
13682 resetAuxKCSegmentOnUnload = true;
13683 }
13684 continue;
13685 } else {
13686 continue;
13687 }
13688
13689 if (fileset_load) {
13690 if (seg->vmsize == 0) {
13691 continue;
13692 }
13693
13694 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13695 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13696 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13697 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13698 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13699 continue;
13700 }
13701 } else {
13702 if (seg->vmsize == 0) {
13703 continue;
13704 }
13705
13706 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13707 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13708 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13709 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13710 continue;
13711 }
13712 }
13713
13714 ret = vm_map_kcfileset_segment(
13715 &start, seg->vmsize,
13716 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13717
13718 if (ret != KERN_SUCCESS) {
13719 if (fileset_load) {
13720 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13721 }
13722 return kOSKextReturnInvalidArgument;
13723 }
13724 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13725 }
13726
13727 /* Return if regular mach-o */
13728 if (!fileset_load) {
13729 return 0;
13730 }
13731
13732 /*
13733 * Fixup for the Pageable KC and the Aux KC is done by
13734 * i386_slide_kext_collection_mh_addrs, but it differs in
13735 * following ways:
13736 *
13737 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13738 * The fixup of kext segments and kext load commands are done at kext
13739 * load time by calling i386_slide_individual_kext.
13740 *
13741 * AuxKC old style: Fixup all the segments and all the load commands.
13742 *
13743 * AuxKC pageable style: Same as the Pageable KC.
13744 */
13745 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13746 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13747 if (ret != KERN_SUCCESS) {
13748 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13749 return kOSKextReturnInvalidArgument;
13750 }
13751
13752 /* Get the prelink info dictionary */
13753 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13754 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13755 if (parsedXML) {
13756 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13757 }
13758
13759 if (!infoDict) {
13760 const char *errorCString = "(unknown error)";
13761
13762 if (errorString && errorString->getCStringNoCopy()) {
13763 errorCString = errorString->getCStringNoCopy();
13764 } else if (parsedXML) {
13765 errorCString = "not a dictionary";
13766 }
13767 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13768 "Error unserializing kext info plist section: %s.", errorCString);
13769 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13770 return kOSKextReturnInvalidArgument;
13771 }
13772
13773 /* Validate that the Kext Collection is prelinked to the loaded KC */
13774 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13775 if (err) {
13776 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13777 return kOSKextReturnInvalidArgument;
13778 }
13779
13780 /* Set Protection of Segments */
13781 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13782
13783 OSKext::addKextsFromKextCollection(*mhp,
13784 infoDict, kPrelinkTextSegment,
13785 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13786
13787 /* Copy in the KC UUID */
13788 if (!loaded_kcUUID) {
13789 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13790 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13791 } else if (pageable) {
13792 pageablekc_uuid_valid = TRUE;
13793 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13794 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13795 } else {
13796 auxkc_uuid_valid = TRUE;
13797 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13798 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13799 }
13800
13801 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13802
13803 return 0;
13804 }
13805
13806 /*********************************************************************
13807 * Assumes sKextLock is held.
13808 *********************************************************************/
13809 /* static */
13810 OSReturn
13811 OSKext::mapKCTextSegment(
13812 void *control,
13813 kernel_mach_header_t **mhp,
13814 off_t file_offset,
13815 uintptr_t *slidep,
13816 void *map_entry_list)
13817 {
13818 kern_return_t ret;
13819 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13820 PAGE_MASK);
13821 vm_map_offset_t load_command_map_size = 0;
13822 kernel_mach_header_t *base_mh = *mhp;
13823
13824 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13825 ret = vm_map_kcfileset_segment(
13826 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13827 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13828
13829 if (ret != KERN_SUCCESS) {
13830 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13831
13832 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13833 "Failed to map mach header of kc fileset with error %d", ret);
13834 return kOSKextReturnInvalidArgument;
13835 }
13836
13837 if (slidep) {
13838 /* Verify that it's an MH_FILESET */
13839 if (base_mh->filetype != MH_FILESET) {
13840 printf("Kext Log: mapKCTextSegment mach header filetype"
13841 " is not an MH_FILESET, it is %x", base_mh->filetype);
13842
13843 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13844 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
13845
13846 /* Unmap the mach header */
13847 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13848 return kOSKextReturnInvalidArgument;
13849 }
13850 }
13851
13852 /* Map the remaining pages of load commands */
13853 if (base_mh->sizeofcmds > mach_header_map_size) {
13854 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13855 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13856
13857 /* Map the load commands */
13858 ret = vm_map_kcfileset_segment(
13859 &load_command_addr, load_command_map_size,
13860 (memory_object_control_t)control, file_offset + mach_header_map_size,
13861 (VM_PROT_READ | VM_PROT_WRITE));
13862
13863 if (ret != KERN_SUCCESS) {
13864 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13865 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13866 "Failed to map load commands of kc fileset with error %d", ret);
13867
13868 /* Unmap the mach header */
13869 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13870 return kOSKextReturnInvalidArgument;
13871 }
13872 }
13873
13874 kernel_segment_command_t *text_seg;
13875 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13876
13877 /* Calculate the slide and vm addr of mach header */
13878 if (slidep) {
13879 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13880 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13881 }
13882
13883 /* Cache the text segment size and file offset before unmapping */
13884 vm_map_offset_t text_segment_size = text_seg->vmsize;
13885 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13886 vm_prot_t text_maxprot = text_seg->maxprot;
13887
13888 /* Unmap the first page and loadcommands and map the text segment */
13889 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13890 assert(ret == KERN_SUCCESS);
13891
13892 if (load_command_map_size) {
13893 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13894 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13895 assert(ret == KERN_SUCCESS);
13896 }
13897
13898 /* Map the text segment at actual vm addr specified in fileset */
13899 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13900 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13901 if (ret != KERN_SUCCESS) {
13902 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13903 "Failed to map Text segment of kc fileset with error %d", ret);
13904 return kOSKextReturnInvalidArgument;
13905 }
13906
13907 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13908 return 0;
13909 }
13910
13911 /*********************************************************************
13912 * Assumes sKextLock is held.
13913 *********************************************************************/
13914 /* static */
13915 OSReturn
13916 OSKext::protectKCFileSet(
13917 kernel_mach_header_t *mh,
13918 kc_kind_t type)
13919 {
13920 vm_map_t kext_map = g_kext_map;
13921 kernel_segment_command_t * seg = NULL;
13922 vm_map_offset_t start = 0;
13923 vm_map_offset_t end = 0;
13924 vm_map_size_t size = 0;
13925 OSReturn ret = 0;
13926
13927 /* Set VM permissions */
13928 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13929 while (seg) {
13930 start = round_page(seg->vmaddr);
13931 end = trunc_page(seg->vmaddr + seg->vmsize);
13932 size = end - start;
13933
13934 /*
13935 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13936 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13937 * for the Aux KC as well.
13938 */
13939 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13940 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13941 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13942 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13943 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13944 ret = OSKext_protect((kernel_mach_header_t *)mh,
13945 kext_map, start, size, seg->maxprot, TRUE, type);
13946 if (ret != KERN_SUCCESS) {
13947 printf("OSKext protect failed with error %d", ret);
13948 return kOSKextReturnInvalidArgument;
13949 }
13950
13951 ret = OSKext_protect((kernel_mach_header_t *)mh,
13952 kext_map, start, size, seg->initprot, FALSE, type);
13953 if (ret != KERN_SUCCESS) {
13954 printf("OSKext protect failed with error %d", ret);
13955 return kOSKextReturnInvalidArgument;
13956 }
13957
13958 ret = OSKext_wire((kernel_mach_header_t *)mh,
13959 kext_map, start, end, seg->initprot, FALSE, type);
13960 if (ret != KERN_SUCCESS) {
13961 printf("OSKext wire failed with error %d", ret);
13962 return kOSKextReturnInvalidArgument;
13963 }
13964 }
13965
13966 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13967 }
13968
13969 return 0;
13970 }
13971
13972 /*********************************************************************
13973 * Assumes sKextLock is held.
13974 *********************************************************************/
13975 /* static */
13976 void
13977 OSKext::freeKCFileSetcontrol(void)
13978 {
13979 PE_reset_all_kc_vp();
13980 }
13981
13982 /*********************************************************************
13983 * Assumes sKextLock is held.
13984 *
13985 * resetKCFileSetSegments: Kext start function expects data segment to
13986 * be pristine on every load, unmap the dirty segments on unload and
13987 * remap them from FileSet on disk. Remap all segments of kext since
13988 * fixups are done per kext and not per segment.
13989 *********************************************************************/
13990 OSReturn
13991 OSKext::resetKCFileSetSegments(void)
13992 {
13993 kernel_segment_command_t *seg = NULL;
13994 kernel_segment_command_t *text_seg;
13995 uint32_t text_fileoff;
13996 kernel_mach_header_t *k_mh = NULL;
13997 uintptr_t slide;
13998 struct vnode *vp = NULL;
13999 void *fileset_control = NULL;
14000 bool pageable = (kc_type == KCKindPageable);
14001 OSReturn err;
14002 kern_return_t kr;
14003
14004 /* Check the vnode reference is still available */
14005 vp = (struct vnode *)PE_get_kc_vp(kc_type);
14006 if (vp == NULL) {
14007 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
14008 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
14009 return kOSKextReturnInternalError;
14010 }
14011
14012 fileset_control = ubc_getobject(vp, 0);
14013 assert(fileset_control != NULL);
14014
14015 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
14016 "Kext %s resetting all segments", getIdentifierCString());
14017
14018 k_mh = (kernel_mach_header_t *)kmod_info->address;
14019 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
14020 text_fileoff = text_seg->fileoff;
14021 slide = PE_get_kc_slide(kc_type);
14022
14023 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
14024 while (seg) {
14025 if (seg->vmsize == 0) {
14026 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14027 continue;
14028 }
14029
14030 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
14031 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
14032 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
14033 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
14034 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14035 continue;
14036 }
14037
14038 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
14039 assert(kr == KERN_SUCCESS);
14040 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14041 }
14042
14043 /* Unmap the text segment */
14044 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
14045 assert(kr == KERN_SUCCESS);
14046
14047 /* Map all the segments of the kext */
14048 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
14049 if (err) {
14050 panic("Could not reset segments of a mapped kext, error %x", err);
14051 }
14052
14053 /* Update address in kmod_info, since it has been reset */
14054 if (kmod_info->address) {
14055 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
14056 }
14057
14058 return 0;
14059 }
14060
14061 /*********************************************************************
14062 * Mechanism to track all segment mapping while mapping KC fileset.
14063 *********************************************************************/
14064
14065 struct kcfileset_map_entry {
14066 vm_map_offset_t me_start;
14067 vm_map_offset_t me_size;
14068 };
14069
14070 struct kcfileset_map_entry_list {
14071 int kme_list_count;
14072 int kme_list_index;
14073 struct kcfileset_map_entry kme_list[];
14074 };
14075
14076 #define KCFILESET_MAP_ENTRY_MAX (16380)
14077
14078 static void *
14079 allocate_kcfileset_map_entry_list(void)
14080 {
14081 struct kcfileset_map_entry_list *entry_list;
14082
14083 entry_list = kalloc_type(struct kcfileset_map_entry_list,
14084 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
14085
14086 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
14087 entry_list->kme_list_index = 0;
14088 return entry_list;
14089 }
14090
14091 static void
14092 add_kcfileset_map_entry(
14093 void *map_entry_list,
14094 vm_map_offset_t start,
14095 vm_map_offset_t size)
14096 {
14097 if (map_entry_list == NULL) {
14098 return;
14099 }
14100
14101 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14102
14103 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
14104 panic("Ran out of map kc fileset list");
14105 }
14106
14107 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
14108 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
14109
14110 entry_list->kme_list_index++;
14111 }
14112
14113 static void
14114 deallocate_kcfileset_map_entry_list_and_unmap_entries(
14115 void *map_entry_list,
14116 boolean_t unmap_entries,
14117 bool pageable)
14118 {
14119 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14120
14121 if (unmap_entries) {
14122 for (int i = 0; i < entry_list->kme_list_index; i++) {
14123 kern_return_t ret;
14124 ret = vm_unmap_kcfileset_segment(
14125 &(entry_list->kme_list[i].me_start),
14126 entry_list->kme_list[i].me_size);
14127 assert(ret == KERN_SUCCESS);
14128 }
14129
14130 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
14131 }
14132
14133 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
14134 KCFILESET_MAP_ENTRY_MAX, entry_list);
14135 }
14136
14137 /*********************************************************************
14138 * Mechanism to map kext segment.
14139 *********************************************************************/
14140
14141 kern_return_t
14142 vm_map_kcfileset_segment(
14143 vm_map_offset_t *start,
14144 vm_map_offset_t size,
14145 void *control,
14146 vm_object_offset_t fileoffset,
14147 vm_prot_t max_prot)
14148 {
14149 vm_map_kernel_flags_t vmk_flags = {
14150 .vmf_fixed = true,
14151 .vmkf_no_copy_on_read = true,
14152 .vmkf_cs_enforcement_override = true,
14153 .vm_tag = VM_KERN_MEMORY_OSKEXT,
14154 };
14155 kern_return_t ret;
14156
14157 /* Add Write to max prot to allow fixups */
14158 max_prot = max_prot | VM_PROT_WRITE;
14159
14160 /*
14161 * Map the segments from file as COPY mappings to
14162 * make sure changes on disk to the file does not affect
14163 * mapped segments.
14164 */
14165 ret = vm_map_enter_mem_object_control(
14166 g_kext_map,
14167 start,
14168 size,
14169 (mach_vm_offset_t)0,
14170 vmk_flags,
14171 (memory_object_control_t)control,
14172 fileoffset,
14173 TRUE, /* copy */
14174 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
14175 VM_INHERIT_NONE);
14176
14177 return ret;
14178 }
14179
14180 kern_return_t
14181 vm_unmap_kcfileset_segment(
14182 vm_map_offset_t *start,
14183 vm_map_offset_t size)
14184 {
14185 return mach_vm_deallocate(g_kext_map, *start, size);
14186 }
14187
14188 #endif //(__x86_64__) || defined(__i386__)
14189
14190 /*********************************************************************
14191 * Assumes sKextLock is held.
14192 *********************************************************************/
14193 /* static */
14194 OSReturn
14195 OSKext::validateKCFileSetUUID(
14196 OSDictionary *infoDict,
14197 kc_kind_t type)
14198 {
14199 OSReturn ret = kOSReturnSuccess;
14200
14201 if (!kernelcache_uuid_valid) {
14202 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14203 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
14204 ret = kOSKextReturnInvalidArgument;
14205 goto finish;
14206 }
14207 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
14208 if (ret != 0) {
14209 goto finish;
14210 }
14211
14212 #if defined(__x86_64__) || defined(__i386__)
14213 /* Check if the Aux KC is prelinked to correct Pageable KC */
14214 if (type == KCKindAuxiliary) {
14215 if (!pageablekc_uuid_valid) {
14216 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14217 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
14218 ret = kOSKextReturnInvalidArgument;
14219 goto finish;
14220 }
14221 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
14222 if (ret != 0) {
14223 goto finish;
14224 }
14225 }
14226 #endif //(__x86_64__) || defined(__i386__)
14227
14228 printf("KextLog: Collection UUID matches with loaded KCs.\n");
14229 finish:
14230 return ret;
14231 }
14232
14233 /*********************************************************************
14234 * Assumes sKextLock is held.
14235 *********************************************************************/
14236 /* static */
14237 OSReturn
14238 OSKext::validateKCUUIDfromPrelinkInfo(
14239 uuid_t *loaded_kcuuid,
14240 kc_kind_t type,
14241 OSDictionary *infoDict,
14242 const char *uuid_key)
14243 {
14244 /* extract the UUID from the dictionary */
14245 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
14246 if (!prelinkinfoKCUUID) {
14247 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14248 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
14249 return kOSKextReturnInvalidArgument;
14250 }
14251
14252 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
14253 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14254 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
14255 return kOSKextReturnInvalidArgument;
14256 }
14257
14258 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
14259 prelinkinfoKCUUID->getLength())) {
14260 OSData *info_dict_uuid;
14261 uuid_string_t info_dict_uuid_str = {};
14262 uuid_string_t expected_uuid_str = {};
14263 uuid_string_t given_uuid_str = {};
14264 uuid_t given_uuid;
14265
14266 /* extract the KC UUID from the dictionary */
14267 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
14268 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
14269 uuid_t tmp_uuid;
14270 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
14271 uuid_unparse(tmp_uuid, info_dict_uuid_str);
14272 }
14273
14274 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
14275 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
14276 uuid_unparse(given_uuid, given_uuid_str);
14277
14278 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14279 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14280 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14281 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14282 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14283 if (type == KCKindPageable && sPanicOnKCMismatch) {
14284 panic("System KC UUID %s linked against %s, but %s is loaded",
14285 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14286 }
14287 return kOSKextReturnInvalidArgument;
14288 }
14289
14290 return 0;
14291 }
14292
14293 /*********************************************************************
14294 * Assumes sKextLock is held.
14295 *********************************************************************/
14296 /* static */
14297 OSReturn
14298 OSKext::dispatchResource(OSDictionary * requestDict)
14299 {
14300 OSReturn result = kOSReturnError;
14301 OSSharedPtr<OSDictionary> callbackRecord;
14302 OSNumber * requestTag = NULL; // do not release
14303 OSNumber * requestResult = NULL; // do not release
14304 OSData * dataObj = NULL; // do not release
14305 uint32_t dataLength = 0;
14306 const void * dataPtr = NULL; // do not free
14307 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14308 OSKextRequestResourceCallback callback = NULL;
14309 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14310 void * context = NULL; // do not free
14311 OSSharedPtr<OSKext> callbackKext;
14312
14313 /* Get the args from the request. Right now we need the tag
14314 * to look up the callback record, and the result for invoking the callback.
14315 */
14316 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14317 kKextRequestArgumentRequestTagKey));
14318 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14319 kKextRequestArgumentResultKey));
14320 if (!requestTag || !requestResult) {
14321 result = kOSKextReturnInvalidArgument;
14322 goto finish;
14323 }
14324
14325 /* Look for a callback record matching this request's tag.
14326 */
14327 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
14328 if (result != kOSReturnSuccess) {
14329 goto finish;
14330 }
14331
14332 /*****
14333 * Get the context pointer of the callback record (if there is one).
14334 */
14335 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14336 callbackRecord.get(), kKextRequestArgumentContextKey));
14337 context = _OSKextExtractPointer(contextWrapper);
14338 if (contextWrapper && !context) {
14339 goto finish;
14340 }
14341
14342 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14343 _OSKextGetRequestArgument(callbackRecord.get(),
14344 kKextRequestArgumentCallbackKey));
14345 callback = _OSKextExtractCallbackPointer(callbackWrapper);
14346 if (!callback) {
14347 goto finish;
14348 }
14349
14350 /* Check for a data obj. We might not have one and that's ok, that means
14351 * we didn't find the requested resource, and we still have to tell the
14352 * caller that via the callback.
14353 */
14354 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14355 kKextRequestArgumentValueKey));
14356 if (dataObj) {
14357 dataPtr = dataObj->getBytesNoCopy();
14358 dataLength = dataObj->getLength();
14359 }
14360
14361 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
14362 if (!callbackKext) {
14363 OSKextLog(/* kext */ NULL,
14364 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14365 "Can't invoke callback for resource request; ");
14366 goto finish;
14367 }
14368 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14369 OSKextLog(/* kext */ NULL,
14370 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14371 "Can't invoke kext resource callback; ");
14372 goto finish;
14373 }
14374
14375 (void)callback(requestTag->unsigned32BitValue(),
14376 (OSReturn)requestResult->unsigned32BitValue(),
14377 dataPtr, dataLength, context);
14378
14379 result = kOSReturnSuccess;
14380
14381 finish:
14382 return result;
14383 }
14384
14385 /*********************************************************************
14386 * Assumes sKextLock is held.
14387 *********************************************************************/
14388 /* static */
14389 OSReturn
14390 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14391 {
14392 OSSharedPtr<OSDictionary> missingIDs;
14393 OSArray *bundleIDList = NULL; // do not release
14394
14395 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14396 requestDict, kKextRequestArgumentMissingBundleIDs));
14397 if (!bundleIDList) {
14398 return kOSKextReturnInvalidArgument;
14399 }
14400
14401 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
14402 if (!missingIDs) {
14403 return kOSKextReturnNoMemory;
14404 }
14405
14406 uint32_t count, i;
14407 count = bundleIDList->getCount();
14408 for (i = 0; i < count; i++) {
14409 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14410 if (thisID) {
14411 missingIDs->setObject(thisID, kOSBooleanFalse);
14412 }
14413 }
14414
14415 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
14416
14417 return kOSReturnSuccess;
14418 }
14419
14420 /*********************************************************************
14421 * Assumes sKextLock is held.
14422 *********************************************************************/
14423 /* static */
14424 OSReturn
14425 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14426 {
14427 bool loadable = true;
14428 if (!kextIdentifier) {
14429 return kOSKextReturnInvalidArgument;
14430 }
14431
14432 if (requestDict) {
14433 OSBoolean *loadableArg;
14434 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14435 requestDict, kKextRequestArgumentBundleAvailability));
14436 /* If we find the "Bundle Available" arg, and it's false, then
14437 * mark the bundle ID as _not_ loadable
14438 */
14439 if (loadableArg && !loadableArg->getValue()) {
14440 loadable = false;
14441 }
14442 }
14443
14444 if (!sNonLoadableKextsByID) {
14445 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
14446 }
14447
14448 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
14449
14450 OSKextLog(/* kext */ NULL,
14451 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14452 "KextLog: AuxKC bundle %s marked as %s",
14453 kextIdentifier->getCStringNoCopy(),
14454 (loadable ? "loadable" : "NOT loadable"));
14455
14456 return kOSReturnSuccess;
14457 }
14458
14459 /*********************************************************************
14460 *********************************************************************/
14461 /* static */
14462 void
14463 OSKext::invokeRequestCallback(
14464 OSDictionary * callbackRecord,
14465 OSReturn callbackResult)
14466 {
14467 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
14468 OSSharedPtr<OSNumber> resultNum;
14469
14470 if (!predicate) {
14471 goto finish;
14472 }
14473
14474 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
14475 8 * sizeof(callbackResult));
14476 if (!resultNum) {
14477 goto finish;
14478 }
14479
14480 /* Insert the result into the callback record and dispatch it as if it
14481 * were the reply coming down from user space.
14482 */
14483 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
14484 resultNum.get());
14485
14486 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14487 /* This removes the pending callback record.
14488 */
14489 OSKext::dispatchResource(callbackRecord);
14490 }
14491
14492 finish:
14493 return;
14494 }
14495
14496 /*********************************************************************
14497 * Assumes sKextLock is held.
14498 *********************************************************************/
14499 /* static */
14500 OSReturn
14501 OSKext::cancelRequest(
14502 OSKextRequestTag requestTag,
14503 void ** contextOut)
14504 {
14505 OSReturn result = kOSKextReturnNoMemory;
14506 OSSharedPtr<OSDictionary> callbackRecord;
14507 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14508
14509 IORecursiveLockLock(sKextLock);
14510 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14511 callbackRecord);
14512 IORecursiveLockUnlock(sKextLock);
14513
14514 if (result == kOSReturnSuccess && contextOut) {
14515 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14516 _OSKextGetRequestArgument(callbackRecord.get(),
14517 kKextRequestArgumentContextKey));
14518 *contextOut = _OSKextExtractPointer(contextWrapper);
14519 }
14520
14521 return result;
14522 }
14523
14524 /*********************************************************************
14525 * Assumes sKextLock is held.
14526 *********************************************************************/
14527 void
14528 OSKext::invokeOrCancelRequestCallbacks(
14529 OSReturn callbackResult,
14530 bool invokeFlag)
14531 {
14532 unsigned int count, i;
14533
14534 count = sRequestCallbackRecords->getCount();
14535 if (!count) {
14536 goto finish;
14537 }
14538
14539 i = count - 1;
14540 do {
14541 OSDictionary * request = OSDynamicCast(OSDictionary,
14542 sRequestCallbackRecords->getObject(i));
14543
14544 if (!request) {
14545 continue;
14546 }
14547 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14548 _OSKextGetRequestArgument(request,
14549 kKextRequestArgumentCallbackKey));
14550
14551 if (!callbackWrapper) {
14552 sRequestCallbackRecords->removeObject(i);
14553 continue;
14554 }
14555
14556 vm_address_t callbackAddress = (vm_address_t)
14557 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14558
14559 if ((kmod_info->address <= callbackAddress) &&
14560 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14561 if (invokeFlag) {
14562 /* This removes the callback record.
14563 */
14564 invokeRequestCallback(request, callbackResult);
14565 } else {
14566 sRequestCallbackRecords->removeObject(i);
14567 }
14568 }
14569 } while (i--);
14570
14571 finish:
14572 return;
14573 }
14574
14575 /*********************************************************************
14576 * Assumes sKextLock is held.
14577 *********************************************************************/
14578 uint32_t
14579 OSKext::countRequestCallbacks(void)
14580 {
14581 uint32_t result = 0;
14582 unsigned int count, i;
14583
14584 count = sRequestCallbackRecords->getCount();
14585 if (!count) {
14586 goto finish;
14587 }
14588
14589 i = count - 1;
14590 do {
14591 OSDictionary * request = OSDynamicCast(OSDictionary,
14592 sRequestCallbackRecords->getObject(i));
14593
14594 if (!request) {
14595 continue;
14596 }
14597 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14598 _OSKextGetRequestArgument(request,
14599 kKextRequestArgumentCallbackKey));
14600
14601 if (!callbackWrapper) {
14602 continue;
14603 }
14604
14605 vm_address_t callbackAddress = (vm_address_t)
14606 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14607
14608 if ((kmod_info->address <= callbackAddress) &&
14609 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14610 result++;
14611 }
14612 } while (i--);
14613
14614 finish:
14615 return result;
14616 }
14617
14618 /*********************************************************************
14619 *********************************************************************/
14620 static OSReturn
14621 _OSKextCreateRequest(
14622 const char * predicate,
14623 OSSharedPtr<OSDictionary> & requestR)
14624 {
14625 OSReturn result = kOSKextReturnNoMemory;
14626 OSSharedPtr<OSDictionary> request;
14627
14628 request = OSDictionary::withCapacity(2);
14629 if (!request) {
14630 goto finish;
14631 }
14632 result = _OSDictionarySetCStringValue(request.get(),
14633 kKextRequestPredicateKey, predicate);
14634 if (result != kOSReturnSuccess) {
14635 goto finish;
14636 }
14637 result = kOSReturnSuccess;
14638
14639 finish:
14640 if (result == kOSReturnSuccess) {
14641 requestR = os::move(request);
14642 }
14643
14644 return result;
14645 }
14646
14647 /*********************************************************************
14648 *********************************************************************/
14649 static OSString *
14650 _OSKextGetRequestPredicate(OSDictionary * requestDict)
14651 {
14652 return OSDynamicCast(OSString,
14653 requestDict->getObject(kKextRequestPredicateKey));
14654 }
14655
14656 /*********************************************************************
14657 *********************************************************************/
14658 static OSObject *
14659 _OSKextGetRequestArgument(
14660 OSDictionary * requestDict,
14661 const char * argName)
14662 {
14663 OSDictionary * args = OSDynamicCast(OSDictionary,
14664 requestDict->getObject(kKextRequestArgumentsKey));
14665 if (args) {
14666 return args->getObject(argName);
14667 }
14668 return NULL;
14669 }
14670
14671 /*********************************************************************
14672 *********************************************************************/
14673 static bool
14674 _OSKextSetRequestArgument(
14675 OSDictionary * requestDict,
14676 const char * argName,
14677 OSMetaClassBase * value)
14678 {
14679 OSDictionary * args = OSDynamicCast(OSDictionary,
14680 requestDict->getObject(kKextRequestArgumentsKey));
14681 OSSharedPtr<OSDictionary> newArgs;
14682 if (!args) {
14683 newArgs = OSDictionary::withCapacity(2);
14684 args = newArgs.get();
14685 if (!args) {
14686 goto finish;
14687 }
14688 requestDict->setObject(kKextRequestArgumentsKey, args);
14689 }
14690 if (args) {
14691 return args->setObject(argName, value);
14692 }
14693 finish:
14694 return false;
14695 }
14696
14697 /*********************************************************************
14698 *********************************************************************/
14699 template <typename T>
14700 static T *
14701 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
14702 {
14703 if (!wrapper) {
14704 return nullptr;
14705 }
14706 return wrapper->getRef();
14707 }
14708
14709 /*********************************************************************
14710 *********************************************************************/
14711 static OSKextRequestResourceCallback
14712 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14713 {
14714 if (!wrapper) {
14715 return nullptr;
14716 }
14717 return wrapper->getRef();
14718 }
14719
14720
14721 /*********************************************************************
14722 *********************************************************************/
14723 static OSReturn
14724 _OSDictionarySetCStringValue(
14725 OSDictionary * dict,
14726 const char * cKey,
14727 const char * cValue)
14728 {
14729 OSReturn result = kOSKextReturnNoMemory;
14730 OSSharedPtr<const OSSymbol> key;
14731 OSSharedPtr<OSString> value;
14732
14733 key = OSSymbol::withCString(cKey);
14734 value = OSString::withCString(cValue);
14735 if (!key || !value) {
14736 goto finish;
14737 }
14738 if (dict->setObject(key.get(), value.get())) {
14739 result = kOSReturnSuccess;
14740 }
14741
14742 finish:
14743 return result;
14744 }
14745
14746 /*********************************************************************
14747 *********************************************************************/
14748 static bool
14749 _OSArrayContainsCString(
14750 OSArray * array,
14751 const char * cString)
14752 {
14753 bool result = false;
14754 OSSharedPtr<const OSSymbol> symbol;
14755 uint32_t count, i;
14756
14757 if (!array || !cString) {
14758 goto finish;
14759 }
14760
14761 symbol = OSSymbol::withCStringNoCopy(cString);
14762 if (!symbol) {
14763 goto finish;
14764 }
14765
14766 count = array->getCount();
14767 for (i = 0; i < count; i++) {
14768 OSObject * thisObject = array->getObject(i);
14769 if (symbol->isEqualTo(thisObject)) {
14770 result = true;
14771 goto finish;
14772 }
14773 }
14774
14775 finish:
14776 return result;
14777 }
14778
14779 #if CONFIG_KXLD
14780 /*********************************************************************
14781 * We really only care about boot / system start up related kexts.
14782 * We return true if we're less than REBUILD_MAX_TIME since start up,
14783 * otherwise return false.
14784 *********************************************************************/
14785 bool
14786 _OSKextInPrelinkRebuildWindow(void)
14787 {
14788 static bool outside_the_window = false;
14789 AbsoluteTime my_abstime;
14790 UInt64 my_ns;
14791 SInt32 my_secs;
14792
14793 if (outside_the_window) {
14794 return false;
14795 }
14796 clock_get_uptime(&my_abstime);
14797 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14798 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14799 if (my_secs > REBUILD_MAX_TIME) {
14800 outside_the_window = true;
14801 return false;
14802 }
14803 return true;
14804 }
14805 #endif /* CONFIG_KXLD */
14806
14807 /*********************************************************************
14808 *********************************************************************/
14809 bool
14810 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14811 {
14812 int unLoadedCount, i;
14813 bool result = false;
14814
14815 IORecursiveLockLock(sKextLock);
14816
14817 if (sUnloadedPrelinkedKexts == NULL) {
14818 goto finish;
14819 }
14820 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14821 if (unLoadedCount == 0) {
14822 goto finish;
14823 }
14824
14825 for (i = 0; i < unLoadedCount; i++) {
14826 const OSSymbol * myBundleID; // do not release
14827
14828 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14829 if (!myBundleID) {
14830 continue;
14831 }
14832 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
14833 result = true;
14834 break;
14835 }
14836 }
14837 finish:
14838 IORecursiveLockUnlock(sKextLock);
14839 return result;
14840 }
14841
14842 #if PRAGMA_MARK
14843 #pragma mark Personalities (IOKit Drivers)
14844 #endif
14845 /*********************************************************************
14846 *********************************************************************/
14847 /* static */
14848 OSSharedPtr<OSArray>
14849 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14850 {
14851 OSSharedPtr<OSArray> result;
14852 OSSharedPtr<OSCollectionIterator> kextIterator;
14853 OSSharedPtr<OSArray> personalities;
14854
14855 OSString * kextID = NULL; // do not release
14856 OSKext * theKext = NULL; // do not release
14857
14858 IORecursiveLockLock(sKextLock);
14859
14860 /* Let's conservatively guess that any given kext has around 3
14861 * personalities for now.
14862 */
14863 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
14864 if (!result) {
14865 goto finish;
14866 }
14867
14868 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
14869 if (!kextIterator) {
14870 goto finish;
14871 }
14872
14873 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14874 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14875 if (theKext->flags.requireExplicitLoad) {
14876 OSKextLog(theKext,
14877 kOSKextLogDebugLevel |
14878 kOSKextLogLoadFlag,
14879 "Kext %s requires an explicit kextload; "
14880 "omitting its personalities.",
14881 theKext->getIdentifierCString());
14882 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14883 personalities = theKext->copyPersonalitiesArray();
14884 if (!personalities) {
14885 continue;
14886 }
14887 result->merge(personalities.get());
14888 } else {
14889 // xxx - check for better place to put this log msg
14890 OSKextLog(theKext,
14891 kOSKextLogWarningLevel |
14892 kOSKextLogLoadFlag,
14893 "Kext %s is not loadable during safe boot; "
14894 "omitting its personalities.",
14895 theKext->getIdentifierCString());
14896 }
14897 }
14898
14899 finish:
14900 IORecursiveLockUnlock(sKextLock);
14901
14902 return result;
14903 }
14904
14905 /*********************************************************************
14906 *********************************************************************/
14907 /* static */
14908 void
14909 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14910 {
14911 int numPersonalities = 0;
14912
14913 OSKextLog(/* kext */ NULL,
14914 kOSKextLogStepLevel |
14915 kOSKextLogLoadFlag,
14916 "Sending all eligible registered kexts' personalities "
14917 "to the IOCatalogue %s.",
14918 startMatching ? "and starting matching" : "but not starting matching");
14919
14920 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14921 /* filterSafeBootFlag */ true);
14922
14923 if (personalities) {
14924 gIOCatalogue->addDrivers(personalities.get(), startMatching);
14925 numPersonalities = personalities->getCount();
14926 }
14927
14928 OSKextLog(/* kext */ NULL,
14929 kOSKextLogStepLevel |
14930 kOSKextLogLoadFlag,
14931 "%d kext personalit%s sent to the IOCatalogue; %s.",
14932 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14933 startMatching ? "matching started" : "matching not started");
14934 return;
14935 }
14936
14937 /*********************************************************************
14938 * Do not make a deep copy, just convert the IOKitPersonalities dict
14939 * to an array for sending to the IOCatalogue.
14940 *********************************************************************/
14941 OSSharedPtr<OSArray>
14942 OSKext::copyPersonalitiesArray(void)
14943 {
14944 OSSharedPtr<OSArray> result;
14945 OSDictionary * personalities = NULL; // do not release
14946 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14947
14948 OSString * personalityName = NULL; // do not release
14949 OSString * personalityBundleIdentifier = NULL; // do not release
14950
14951 personalities = OSDynamicCast(OSDictionary,
14952 getPropertyForHostArch(kIOKitPersonalitiesKey));
14953 if (!personalities) {
14954 goto finish;
14955 }
14956
14957 result = OSArray::withCapacity(personalities->getCount());
14958 if (!result) {
14959 goto finish;
14960 }
14961
14962 personalitiesIterator =
14963 OSCollectionIterator::withCollection(personalities);
14964 if (!personalitiesIterator) {
14965 goto finish;
14966 }
14967 while ((personalityName = OSDynamicCast(OSString,
14968 personalitiesIterator->getNextObject()))) {
14969 OSDictionary * personality = OSDynamicCast(OSDictionary,
14970 personalities->getObject(personalityName));
14971
14972 if (personality) {
14973 /******
14974 * If the personality doesn't have a CFBundleIdentifier, or if it
14975 * differs from the kext's, insert the kext's ID so we can find it.
14976 * The publisher ID is used to remove personalities from bundles
14977 * correctly.
14978 */
14979 personalityBundleIdentifier = OSDynamicCast(OSString,
14980 personality->getObject(kCFBundleIdentifierKey));
14981
14982 if (!personalityBundleIdentifier) {
14983 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
14984 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
14985 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
14986 }
14987 }
14988
14989 result->setObject(personality);
14990 }
14991
14992 finish:
14993 return result;
14994 }
14995
14996 /*********************************************************************
14997 * Might want to change this to a bool return?
14998 *********************************************************************/
14999 OSReturn
15000 OSKext::sendPersonalitiesToCatalog(
15001 bool startMatching,
15002 OSArray * personalityNames)
15003 {
15004 OSReturn result = kOSReturnSuccess;
15005 OSSharedPtr<OSArray> personalitiesToSend;
15006 OSDictionary * kextPersonalities = NULL; // do not release
15007 int count, i;
15008
15009 if (!sLoadEnabled) {
15010 OSKextLog(this,
15011 kOSKextLogErrorLevel |
15012 kOSKextLogLoadFlag,
15013 "Kext loading is disabled (attempt to start matching for kext %s).",
15014 getIdentifierCString());
15015 result = kOSKextReturnDisabled;
15016 goto finish;
15017 }
15018
15019 if (sSafeBoot && !isLoadableInSafeBoot()) {
15020 OSKextLog(this,
15021 kOSKextLogErrorLevel |
15022 kOSKextLogLoadFlag,
15023 "Kext %s is not loadable during safe boot; "
15024 "not sending personalities to the IOCatalogue.",
15025 getIdentifierCString());
15026 result = kOSKextReturnNotLoadable;
15027 goto finish;
15028 }
15029
15030 if (!personalityNames || !personalityNames->getCount()) {
15031 personalitiesToSend = copyPersonalitiesArray();
15032 } else {
15033 kextPersonalities = OSDynamicCast(OSDictionary,
15034 getPropertyForHostArch(kIOKitPersonalitiesKey));
15035 if (!kextPersonalities || !kextPersonalities->getCount()) {
15036 // not an error
15037 goto finish;
15038 }
15039 personalitiesToSend = OSArray::withCapacity(0);
15040 if (!personalitiesToSend) {
15041 result = kOSKextReturnNoMemory;
15042 goto finish;
15043 }
15044 count = personalityNames->getCount();
15045 for (i = 0; i < count; i++) {
15046 OSString * name = OSDynamicCast(OSString,
15047 personalityNames->getObject(i));
15048 if (!name) {
15049 continue;
15050 }
15051 OSDictionary * personality = OSDynamicCast(OSDictionary,
15052 kextPersonalities->getObject(name));
15053 if (personality) {
15054 personalitiesToSend->setObject(personality);
15055 }
15056 }
15057 }
15058 if (personalitiesToSend) {
15059 unsigned numPersonalities = personalitiesToSend->getCount();
15060 OSKextLog(this,
15061 kOSKextLogStepLevel |
15062 kOSKextLogLoadFlag,
15063 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
15064 getIdentifierCString(),
15065 numPersonalities,
15066 numPersonalities > 1 ? "ies" : "y",
15067 startMatching ? " and starting matching" : " but not starting matching");
15068 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
15069 }
15070 finish:
15071 return result;
15072 }
15073
15074 /*********************************************************************
15075 * xxx - We should allow removing the kext's declared personalities,
15076 * xxx - even with other bundle identifiers.
15077 *********************************************************************/
15078 void
15079 OSKext::removePersonalitiesFromCatalog(void)
15080 {
15081 OSSharedPtr<OSDictionary> personality;
15082
15083 personality = OSDictionary::withCapacity(1);
15084 if (!personality) {
15085 goto finish;
15086 }
15087 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
15088
15089 OSKextLog(this,
15090 kOSKextLogStepLevel |
15091 kOSKextLogLoadFlag,
15092 "Kext %s removing all personalities naming it from the IOCatalogue.",
15093 getIdentifierCString());
15094
15095 /* Have the IOCatalog remove all personalities matching this kext's
15096 * bundle ID and trigger matching anew.
15097 */
15098 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
15099
15100 finish:
15101 return;
15102 }
15103
15104 void
15105 OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
15106 {
15107 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
15108 return;
15109 }
15110
15111 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(1);
15112 if (!personalityToRemove) {
15113 return;
15114 }
15115
15116 /*
15117 * Create a personality dictionary with just the bundleID.
15118 * We will remove any personality that has a matching bundleID,
15119 * irrespective of which other keys are present on the dictionary.
15120 */
15121 personalityToRemove->setObject(kCFBundleIdentifierKey, getIdentifier());
15122 gIOCatalogue->exchangeDrivers(personalityToRemove.get(), upgradedPersonalities, true);
15123 }
15124
15125 #if PRAGMA_MARK
15126 #pragma mark Logging
15127 #endif
15128 /*********************************************************************
15129 * Do not call any function that takes sKextLock here!
15130 *********************************************************************/
15131 /* static */
15132 OSKextLogSpec
15133 OSKext::setUserSpaceLogFilter(
15134 OSKextLogSpec newUserLogFilter,
15135 bool captureFlag)
15136 {
15137 OSKextLogSpec result;
15138 bool allocError = false;
15139
15140 /* Do not call any function that takes sKextLoggingLock during
15141 * this critical block. That means do logging after.
15142 */
15143 IOLockLock(sKextLoggingLock);
15144
15145 result = sUserSpaceKextLogFilter;
15146 sUserSpaceKextLogFilter = newUserLogFilter;
15147
15148 if (newUserLogFilter && captureFlag &&
15149 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
15150 // xxx - do some measurements for a good initial capacity?
15151 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
15152 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
15153
15154 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
15155 allocError = true;
15156 }
15157 }
15158
15159 IOLockUnlock(sKextLoggingLock);
15160
15161 /* If the config flag itself is changing, log the state change
15162 * going both ways, before setting up the user-space log arrays,
15163 * so that this is only logged in the kernel.
15164 */
15165 if (result != newUserLogFilter) {
15166 OSKextLog(/* kext */ NULL,
15167 kOSKextLogDebugLevel |
15168 kOSKextLogGeneralFlag,
15169 "User-space log flags changed from 0x%x to 0x%x.",
15170 result, newUserLogFilter);
15171 }
15172 if (allocError) {
15173 OSKextLog(/* kext */ NULL,
15174 kOSKextLogErrorLevel |
15175 kOSKextLogGeneralFlag,
15176 "Failed to allocate user-space log message arrays.");
15177 }
15178
15179 return result;
15180 }
15181
15182 /*********************************************************************
15183 * Do not call any function that takes sKextLock here!
15184 *********************************************************************/
15185 /* static */
15186 OSSharedPtr<OSArray>
15187 OSKext::clearUserSpaceLogFilter(void)
15188 {
15189 OSSharedPtr<OSArray> result;
15190 OSKextLogSpec oldLogFilter;
15191 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
15192
15193 /* Do not call any function that takes sKextLoggingLock during
15194 * this critical block. That means do logging after.
15195 */
15196 IOLockLock(sKextLoggingLock);
15197
15198 result = OSArray::withCapacity(2);
15199 if (result) {
15200 result->setObject(sUserSpaceLogSpecArray.get());
15201 result->setObject(sUserSpaceLogMessageArray.get());
15202 }
15203 sUserSpaceLogSpecArray.reset();
15204 sUserSpaceLogMessageArray.reset();
15205
15206 oldLogFilter = sUserSpaceKextLogFilter;
15207 sUserSpaceKextLogFilter = newLogFilter;
15208
15209 IOLockUnlock(sKextLoggingLock);
15210
15211 /* If the config flag itself is changing, log the state change
15212 * going both ways, after tearing down the user-space log
15213 * arrays, so this is only logged within the kernel.
15214 */
15215 if (oldLogFilter != newLogFilter) {
15216 OSKextLog(/* kext */ NULL,
15217 kOSKextLogDebugLevel |
15218 kOSKextLogGeneralFlag,
15219 "User-space log flags changed from 0x%x to 0x%x.",
15220 oldLogFilter, newLogFilter);
15221 }
15222
15223 return result;
15224 }
15225
15226
15227 /*********************************************************************
15228 * Do not call any function that takes sKextLock here!
15229 *********************************************************************/
15230 /* static */
15231 OSKextLogSpec
15232 OSKext::getUserSpaceLogFilter(void)
15233 {
15234 OSKextLogSpec result;
15235
15236 IOLockLock(sKextLoggingLock);
15237 result = sUserSpaceKextLogFilter;
15238 IOLockUnlock(sKextLoggingLock);
15239
15240 return result;
15241 }
15242
15243 /*********************************************************************
15244 * This function is called by OSMetaClass during kernel C++ setup.
15245 * Be careful what you access here; assume only OSKext::initialize()
15246 * has been called.
15247 *
15248 * Do not call any function that takes sKextLock here!
15249 *********************************************************************/
15250 #define VTRESET "\033[0m"
15251
15252 #define VTBOLD "\033[1m"
15253 #define VTUNDER "\033[4m"
15254
15255 #define VTRED "\033[31m"
15256 #define VTGREEN "\033[32m"
15257 #define VTYELLOW "\033[33m"
15258 #define VTBLUE "\033[34m"
15259 #define VTMAGENTA "\033[35m"
15260 #define VTCYAN "\033[36m"
15261
15262 inline const char *
15263 colorForFlags(OSKextLogSpec flags)
15264 {
15265 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
15266
15267 switch (logLevel) {
15268 case kOSKextLogErrorLevel:
15269 return VTRED VTBOLD;
15270 case kOSKextLogWarningLevel:
15271 return VTRED;
15272 case kOSKextLogBasicLevel:
15273 return VTYELLOW VTUNDER;
15274 case kOSKextLogProgressLevel:
15275 return VTYELLOW;
15276 case kOSKextLogStepLevel:
15277 return VTGREEN;
15278 case kOSKextLogDetailLevel:
15279 return VTCYAN;
15280 case kOSKextLogDebugLevel:
15281 return VTMAGENTA;
15282 default:
15283 return ""; // white
15284 }
15285 }
15286
15287 inline bool
15288 logSpecMatch(
15289 OSKextLogSpec msgLogSpec,
15290 OSKextLogSpec logFilter)
15291 {
15292 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15293 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15294 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15295
15296 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15297 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15298 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15299
15300 /* Explicit messages always get logged.
15301 */
15302 if (msgLevel == kOSKextLogExplicitLevel) {
15303 return true;
15304 }
15305
15306 /* Warnings and errors are logged regardless of the flags.
15307 */
15308 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15309 return true;
15310 }
15311
15312 /* A verbose message that isn't for a logging-enabled kext and isn't global
15313 * does *not* get logged.
15314 */
15315 if (!msgKextGlobal && !filterKextGlobal) {
15316 return false;
15317 }
15318
15319 /* Warnings and errors are logged regardless of the flags.
15320 * All other messages must fit the flags and
15321 * have a level at or below the filter.
15322 *
15323 */
15324 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15325 return true;
15326 }
15327 return false;
15328 }
15329
15330 extern "C" {
15331 void
15332 OSKextLog(
15333 OSKext * aKext,
15334 OSKextLogSpec msgLogSpec,
15335 const char * format, ...)
15336 {
15337 va_list argList;
15338
15339 va_start(argList, format);
15340 OSKextVLog(aKext, msgLogSpec, format, argList);
15341 va_end(argList);
15342 }
15343
15344 void
15345 OSKextVLog(
15346 OSKext * aKext,
15347 OSKextLogSpec msgLogSpec,
15348 const char * format,
15349 va_list srcArgList)
15350 {
15351 bool logForKernel = false;
15352 bool logForUser = false;
15353 va_list argList;
15354 char stackBuffer[120];
15355 uint32_t length = 0;
15356 char * allocBuffer = NULL; // must kfree
15357 OSSharedPtr<OSNumber> logSpecNum;
15358 OSSharedPtr<OSString> logString;
15359 char * buffer = stackBuffer; // do not free
15360
15361 IOLockLock(sKextLoggingLock);
15362
15363 /* Set the kext/global bit in the message spec if we have no
15364 * kext or if the kext requests logging.
15365 */
15366 if (!aKext || aKext->flags.loggingEnabled) {
15367 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15368 }
15369
15370 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
15371 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15372 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
15373 }
15374
15375 if (!(logForKernel || logForUser)) {
15376 goto finish;
15377 }
15378
15379 /* No goto from here until past va_end()!
15380 */
15381 va_copy(argList, srcArgList);
15382 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15383 va_end(argList);
15384
15385 if (length + 1 >= sizeof(stackBuffer)) {
15386 allocBuffer = (char *)kalloc_data_tag(length + 1,
15387 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15388 if (!allocBuffer) {
15389 goto finish;
15390 }
15391
15392 /* No goto from here until past va_end()!
15393 */
15394 va_copy(argList, srcArgList);
15395 vsnprintf(allocBuffer, length + 1, format, argList);
15396 va_end(argList);
15397
15398 buffer = allocBuffer;
15399 }
15400
15401 /* If user space wants the log message, queue it up.
15402 */
15403 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15404 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
15405 logString = OSString::withCString(buffer);
15406 if (logSpecNum && logString) {
15407 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15408 sUserSpaceLogMessageArray->setObject(logString.get());
15409 }
15410 }
15411
15412 /* Always log messages from the kernel according to the kernel's
15413 * log flags.
15414 */
15415 if (logForKernel) {
15416 /* If we are in console mode and have a custom log filter,
15417 * colorize the log message.
15418 */
15419 if (sBootArgLogFilterFound) {
15420 const char * color = ""; // do not free
15421 color = colorForFlags(msgLogSpec);
15422 printf("%s%s%s\n", colorForFlags(msgLogSpec),
15423 buffer, color[0] ? VTRESET : "");
15424 } else {
15425 printf("%s\n", buffer);
15426 }
15427 }
15428
15429 finish:
15430 IOLockUnlock(sKextLoggingLock);
15431
15432 if (allocBuffer) {
15433 kfree_data(allocBuffer, length + 1);
15434 }
15435 return;
15436 }
15437
15438 #if KASLR_IOREG_DEBUG
15439
15440 #define IOLOG_INDENT( the_indention ) \
15441 { \
15442 int i; \
15443 for ( i = 0; i < (the_indention); i++ ) { \
15444 IOLog(" "); \
15445 } \
15446 }
15447
15448 extern vm_offset_t vm_kernel_stext;
15449 extern vm_offset_t vm_kernel_etext;
15450 extern mach_vm_offset_t kext_alloc_base;
15451 extern mach_vm_offset_t kext_alloc_max;
15452
15453 bool ScanForAddrInObject(OSObject * theObject,
15454 int indent );
15455
15456 bool
15457 ScanForAddrInObject(OSObject * theObject,
15458 int indent)
15459 {
15460 const OSMetaClass * myTypeID;
15461 OSSharedPtr<OSCollectionIterator> myIter;
15462 OSSymbol * myKey;
15463 OSObject * myValue;
15464 bool myResult = false;
15465
15466 if (theObject == NULL) {
15467 IOLog("%s: theObject is NULL \n",
15468 __FUNCTION__);
15469 return myResult;
15470 }
15471
15472 myTypeID = OSTypeIDInst(theObject);
15473
15474 if (myTypeID == OSTypeID(OSDictionary)) {
15475 OSDictionary * myDictionary;
15476
15477 myDictionary = OSDynamicCast(OSDictionary, theObject);
15478 myIter = OSCollectionIterator::withCollection( myDictionary );
15479 if (myIter == NULL) {
15480 return myResult;
15481 }
15482
15483 // !! reset the iterator
15484 myIter->reset();
15485
15486 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15487 bool myTempResult;
15488
15489 myValue = myDictionary->getObject(myKey);
15490 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15491 if (myTempResult) {
15492 // if we ever get a true result return true
15493 myResult = true;
15494 IOLOG_INDENT(indent);
15495 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15496 }
15497 }
15498
15499 // !! release the iterator
15500 myIter.reset();
15501 } else if (myTypeID == OSTypeID(OSArray)) {
15502 OSArray * myArray;
15503
15504 myArray = OSDynamicCast(OSArray, theObject);
15505 myIter = OSCollectionIterator::withCollection(myArray);
15506 if (myIter == NULL) {
15507 return myResult;
15508 }
15509 // !! reset the iterator
15510 myIter->reset();
15511
15512 while ((myValue = myIter->getNextObject())) {
15513 bool myTempResult;
15514 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15515 if (myTempResult) {
15516 // if we ever get a true result return true
15517 myResult = true;
15518 IOLOG_INDENT(indent);
15519 IOLog("OSArray: \n");
15520 }
15521 }
15522 // !! release the iterator
15523 myIter.reset();
15524 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15525 // should we look for addresses in strings?
15526 } else if (myTypeID == OSTypeID(OSData)) {
15527 void * * myPtrPtr;
15528 unsigned int myLen;
15529 OSData * myDataObj;
15530
15531 myDataObj = OSDynamicCast(OSData, theObject);
15532 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15533 myLen = myDataObj->getLength();
15534
15535 if (myPtrPtr && myLen && myLen > 7) {
15536 int i;
15537 int myPtrCount = (myLen / sizeof(void *));
15538
15539 for (i = 0; i < myPtrCount; i++) {
15540 UInt64 numberValue = (UInt64) * (myPtrPtr);
15541
15542 if (kext_alloc_max != 0 &&
15543 numberValue >= kext_alloc_base &&
15544 numberValue < kext_alloc_max) {
15545 OSSharedPtr<OSKext> myKext;
15546 // IOLog("found OSData %p in kext map %p to %p \n",
15547 // *(myPtrPtr),
15548 // (void *) kext_alloc_base,
15549 // (void *) kext_alloc_max);
15550
15551 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15552 if (myKext) {
15553 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15554 *(myPtrPtr),
15555 myKext->getIdentifierCString());
15556 }
15557 myResult = true;
15558 }
15559 if (vm_kernel_etext != 0 &&
15560 numberValue >= vm_kernel_stext &&
15561 numberValue < vm_kernel_etext) {
15562 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15563 *(myPtrPtr),
15564 (void *) vm_kernel_stext,
15565 (void *) vm_kernel_etext);
15566 myResult = true;
15567 }
15568 myPtrPtr++;
15569 }
15570 }
15571 } else if (myTypeID == OSTypeID(OSBoolean)) {
15572 // do nothing here...
15573 } else if (myTypeID == OSTypeID(OSNumber)) {
15574 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15575
15576 UInt64 numberValue = number->unsigned64BitValue();
15577
15578 if (kext_alloc_max != 0 &&
15579 numberValue >= kext_alloc_base &&
15580 numberValue < kext_alloc_max) {
15581 OSSharedPtr<OSKext> myKext;
15582 IOLog("found OSNumber in kext map %p to %p \n",
15583 (void *) kext_alloc_base,
15584 (void *) kext_alloc_max);
15585 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15586
15587 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15588 if (myKext) {
15589 IOLog("found in kext \"%s\" \n",
15590 myKext->getIdentifierCString());
15591 }
15592
15593 myResult = true;
15594 }
15595 if (vm_kernel_etext != 0 &&
15596 numberValue >= vm_kernel_stext &&
15597 numberValue < vm_kernel_etext) {
15598 IOLog("found OSNumber in kernel text segment %p to %p \n",
15599 (void *) vm_kernel_stext,
15600 (void *) vm_kernel_etext);
15601 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15602 myResult = true;
15603 }
15604 }
15605 #if 0
15606 else {
15607 const OSMetaClass* myMetaClass = NULL;
15608
15609 myMetaClass = theObject->getMetaClass();
15610 if (myMetaClass) {
15611 IOLog("class %s \n", myMetaClass->getClassName());
15612 } else {
15613 IOLog("Unknown object \n" );
15614 }
15615 }
15616 #endif
15617
15618 return myResult;
15619 }
15620 #endif // KASLR_KEXT_DEBUG
15621 }; /* extern "C" */
15622
15623 #if PRAGMA_MARK
15624 #pragma mark Backtrace Dump & kmod_get_info() support
15625 #endif
15626 /*********************************************************************
15627 * This function must be safe to call in panic context.
15628 *********************************************************************/
15629 /* static */
15630 void
15631 OSKext::printKextsInBacktrace(
15632 vm_offset_t * addr __unused,
15633 unsigned int cnt __unused,
15634 int (* printf_func)(const char *fmt, ...) __unused,
15635 uint32_t flags __unused)
15636 {
15637 addr64_t summary_page = 0;
15638 addr64_t last_summary_page = 0;
15639
15640 if (kPrintKextsLock & flags) {
15641 if (!sKextSummariesLock) {
15642 return;
15643 }
15644 IOLockLock(sKextSummariesLock);
15645 }
15646
15647 if (!gLoadedKextSummaries) {
15648 (*printf_func)(" can't perform kext scan: no kext summary");
15649 goto finish;
15650 }
15651
15652 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15653 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
15654 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15655 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
15656 (*printf_func)(" can't perform kext scan: "
15657 "missing kext summary page %p", summary_page);
15658 goto finish;
15659 }
15660 }
15661
15662 foreachKextInBacktrace(addr, cnt, 0, ^(OSKextLoadedKextSummary *summary, uint32_t index) {
15663 if (index == 0 && !(kPrintKextsTerse & flags)) {
15664 (*printf_func)(" Kernel Extensions in backtrace:\n");
15665 }
15666
15667 printSummary(summary, printf_func, flags);
15668 });
15669
15670 finish:
15671 if (kPrintKextsLock & flags) {
15672 IOLockUnlock(sKextSummariesLock);
15673 }
15674
15675 return;
15676 }
15677
15678 void
15679 OSKext::foreachKextInBacktrace(
15680 vm_offset_t * addr,
15681 uint32_t cnt,
15682 uint32_t flags,
15683 void (^ handler)(OSKextLoadedKextSummary *summary, uint32_t index))
15684 {
15685 uint32_t n = 0;
15686
15687 if (kPrintKextsLock & flags) {
15688 if (!sKextSummariesLock) {
15689 return;
15690 }
15691 IOLockLock(sKextSummariesLock);
15692 }
15693
15694 for (uint32_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15695 OSKextLoadedKextSummary * summary;
15696
15697 summary = gLoadedKextSummaries->summaries + i;
15698 if (!summary->address) {
15699 continue;
15700 }
15701
15702 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15703 continue;
15704 }
15705
15706 handler(summary, n++);
15707 }
15708
15709 if (kPrintKextsLock & flags) {
15710 IOLockUnlock(sKextSummariesLock);
15711 }
15712 }
15713
15714 /*********************************************************************
15715 * This function must be safe to call in panic context.
15716 *********************************************************************/
15717 /* static */
15718 boolean_t
15719 OSKext::summaryIsInBacktrace(
15720 OSKextLoadedKextSummary * summary,
15721 vm_offset_t * addr,
15722 unsigned int cnt)
15723 {
15724 u_int i = 0;
15725
15726 for (i = 0; i < cnt; i++) {
15727 vm_offset_t kscan_addr = addr[i];
15728 #if __has_feature(ptrauth_calls)
15729 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15730 #endif /* __has_feature(ptrauth_calls) */
15731 if ((kscan_addr >= summary->text_exec_address) &&
15732 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15733 return TRUE;
15734 }
15735 }
15736
15737 return FALSE;
15738 }
15739
15740 /*
15741 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15742 * sKextSummariesLock held.
15743 */
15744 OSKextLoadedKextSummary *
15745 OSKext::summaryForAddress(uintptr_t addr)
15746 {
15747 #if __has_feature(ptrauth_calls)
15748 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15749 #endif /* __has_feature(ptrauth_calls) */
15750 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15751 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15752 if (!summary->address) {
15753 continue;
15754 }
15755
15756 #if VM_MAPPED_KEXTS
15757 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15758 * support split kexts, but we also may unmap the kexts, which can
15759 * race with the above codepath (see OSKext::unload). As such,
15760 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15761 */
15762 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15763 return summary;
15764 }
15765 #else
15766 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15767 kernel_segment_command_t *seg;
15768
15769 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
15770 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15771 return summary;
15772 }
15773 }
15774 #endif
15775 }
15776
15777 /* addr did not map to any kext */
15778 return NULL;
15779 }
15780
15781 /* static */
15782 void *
15783 OSKext::kextForAddress(const void *address)
15784 {
15785 OSKextActiveAccount * active;
15786 OSKext * kext = NULL;
15787 uint32_t baseIdx;
15788 uint32_t lim;
15789 uintptr_t addr = (uintptr_t) address;
15790 size_t i;
15791
15792 if (!addr) {
15793 return NULL;
15794 }
15795 #if __has_feature(ptrauth_calls)
15796 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15797 #endif /* __has_feature(ptrauth_calls) */
15798
15799 if (sKextAccountsCount) {
15800 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
15801 // bsearch sKextAccounts list
15802 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15803 active = &sKextAccounts[baseIdx + (lim >> 1)];
15804 if ((addr >= active->address) && (addr < active->address_end)) {
15805 if (active->account &&
15806 (kext = active->account->kext) &&
15807 kext->kmod_info) {
15808 lck_ticket_unlock(sKextAccountsLock);
15809 return (void *)kext->kmod_info->address;
15810 }
15811 break;
15812 } else if (addr > active->address) {
15813 // move right
15814 baseIdx += (lim >> 1) + 1;
15815 lim--;
15816 }
15817 // else move left
15818 }
15819 lck_ticket_unlock(sKextAccountsLock);
15820 }
15821 if (kernel_text_contains(addr)) {
15822 return (void *)&_mh_execute_header;
15823 }
15824 if (gLoadedKextSummaries) {
15825 IOLockLock(sKextSummariesLock);
15826 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15827 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15828 if (addr >= summary->address && addr < summary->address + summary->size) {
15829 void *kextAddress = (void *)summary->address;
15830 IOLockUnlock(sKextSummariesLock);
15831 return kextAddress;
15832 }
15833 }
15834 IOLockUnlock(sKextSummariesLock);
15835 }
15836
15837 return NULL;
15838 }
15839
15840 /* static */
15841 kern_return_t
15842 OSKext::summaryForAddressExt(
15843 const void * address,
15844 OSKextLoadedKextSummary * summary)
15845 {
15846 kern_return_t result = KERN_FAILURE;
15847 const OSKextLoadedKextSummary * foundSummary = NULL;
15848
15849 /*
15850 * This needs to be safe to call even before the lock has been initialized
15851 * in OSKext::initialize(), as we might get here from the ksancov runtime
15852 * when instrumenting XNU itself with sanitizer coverage.
15853 */
15854 if (!sKextSummariesLock) {
15855 return result;
15856 }
15857
15858 IOLockLock(sKextSummariesLock);
15859 if (gLoadedKextSummaries) {
15860 foundSummary = summaryForAddress((uintptr_t)address);
15861 if (foundSummary) {
15862 memcpy(summary, foundSummary, sizeof(*summary));
15863 result = KERN_SUCCESS;
15864 } else {
15865 result = KERN_NOT_FOUND;
15866 }
15867 }
15868 IOLockUnlock(sKextSummariesLock);
15869
15870 return result;
15871 }
15872
15873 /*
15874 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15875 * Safe to call in panic context.
15876 */
15877 static OSKextLoadedKextSummary *
15878 findSummary(uint32_t tagID)
15879 {
15880 OSKextLoadedKextSummary * summary;
15881 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15882 summary = gLoadedKextSummaries->summaries + i;
15883 if (summary->loadTag == tagID) {
15884 return summary;
15885 }
15886 }
15887 return NULL;
15888 }
15889
15890 /*********************************************************************
15891 * This function must be safe to call in panic context.
15892 *********************************************************************/
15893 void
15894 OSKext::printSummary(
15895 OSKextLoadedKextSummary * summary,
15896 int (* printf_func)(const char *fmt, ...),
15897 uint32_t flags)
15898 {
15899 kmod_reference_t * kmod_ref = NULL;
15900 uuid_string_t uuid;
15901 char version[kOSKextVersionMaxLength];
15902 uint64_t tmpAddr;
15903 uint64_t tmpSize;
15904 OSKextLoadedKextSummary *dependencySummary;
15905
15906 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
15907 strlcpy(version, "unknown version", sizeof(version));
15908 }
15909 (void) uuid_unparse(summary->uuid, uuid);
15910
15911 #if defined(__arm__) || defined(__arm64__)
15912 tmpAddr = summary->text_exec_address;
15913 tmpSize = summary->text_exec_size;
15914 #else
15915 tmpAddr = summary->address;
15916 tmpSize = summary->size;
15917 #endif
15918 if (kPrintKextsUnslide & flags) {
15919 tmpAddr = ml_static_unslide(tmpAddr);
15920 }
15921 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15922 (kPrintKextsTerse & flags) ? "" : " ",
15923 summary->name, version, uuid,
15924 tmpAddr, tmpAddr + tmpSize - 1);
15925
15926 if (kPrintKextsTerse & flags) {
15927 return;
15928 }
15929
15930 /* print dependency info */
15931 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15932 kmod_ref;
15933 kmod_ref = kmod_ref->next) {
15934 kmod_info_t * rinfo;
15935
15936 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15937 (*printf_func)(" kmod dependency scan stopped "
15938 "due to missing dependency page: %p\n",
15939 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
15940 break;
15941 }
15942 rinfo = kmod_ref->info;
15943
15944 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
15945 (*printf_func)(" kmod dependency scan stopped "
15946 "due to missing kmod page: %p\n",
15947 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
15948 break;
15949 }
15950
15951 if (!rinfo->address) {
15952 continue; // skip fake entries for built-ins
15953 }
15954
15955 dependencySummary = findSummary(rinfo->id);
15956 uuid[0] = 0x00;
15957 tmpAddr = rinfo->address;
15958 tmpSize = rinfo->size;
15959 if (dependencySummary) {
15960 (void) uuid_unparse(dependencySummary->uuid, uuid);
15961 #if defined(__arm__) || defined(__arm64__)
15962 tmpAddr = dependencySummary->text_exec_address;
15963 tmpSize = dependencySummary->text_exec_size;
15964 #endif
15965 }
15966
15967 if (kPrintKextsUnslide & flags) {
15968 tmpAddr = ml_static_unslide(tmpAddr);
15969 }
15970 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15971 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15972 }
15973 return;
15974 }
15975
15976
15977 #if !defined(__arm__) && !defined(__arm64__)
15978 /*******************************************************************************
15979 * substitute() looks at an input string (a pointer within a larger buffer)
15980 * for a match to a substring, and on match it writes the marker & substitution
15981 * character to an output string, updating the scan (from) and
15982 * output (to) indexes as appropriate.
15983 *******************************************************************************/
15984 static int substitute(
15985 const char * scan_string,
15986 char * string_out,
15987 uint32_t * to_index,
15988 uint32_t * from_index,
15989 const char * substring,
15990 char marker,
15991 char substitution);
15992
15993 /* string_out must be at least KMOD_MAX_NAME bytes.
15994 */
15995 static int
15996 substitute(
15997 const char * scan_string,
15998 char * string_out,
15999 uint32_t * to_index,
16000 uint32_t * from_index,
16001 const char * substring,
16002 char marker,
16003 char substitution)
16004 {
16005 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
16006
16007 /* On a substring match, append the marker (if there is one) and then
16008 * the substitution character, updating the output (to) index accordingly.
16009 * Then update the input (from) length by the length of the substring
16010 * that got replaced.
16011 */
16012 if (!strncmp(scan_string, substring, substring_length)) {
16013 if (marker) {
16014 string_out[(*to_index)++] = marker;
16015 }
16016 string_out[(*to_index)++] = substitution;
16017 (*from_index) += substring_length;
16018 return 1;
16019 }
16020 return 0;
16021 }
16022
16023 /*******************************************************************************
16024 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
16025 * KMOD_MAX_NAME characters and performs various substitutions of common
16026 * prefixes & substrings as defined by tables in kext_panic_report.h.
16027 *******************************************************************************/
16028 static void compactIdentifier(
16029 const char * identifier,
16030 char * identifier_out,
16031 char ** identifier_out_end);
16032
16033 static void
16034 compactIdentifier(
16035 const char * identifier,
16036 char * identifier_out,
16037 char ** identifier_out_end)
16038 {
16039 uint32_t from_index, to_index;
16040 uint32_t scan_from_index = 0;
16041 uint32_t scan_to_index = 0;
16042 subs_entry_t * subs_entry = NULL;
16043 int did_sub = 0;
16044
16045 from_index = to_index = 0;
16046 identifier_out[0] = '\0';
16047
16048 /* Replace certain identifier prefixes with shorter @+character sequences.
16049 * Check the return value of substitute() so we only replace the prefix.
16050 */
16051 for (subs_entry = &kext_identifier_prefix_subs[0];
16052 subs_entry->substring && !did_sub;
16053 subs_entry++) {
16054 did_sub = substitute(identifier, identifier_out,
16055 &scan_to_index, &scan_from_index,
16056 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
16057 }
16058 did_sub = 0;
16059
16060 /* Now scan through the identifier looking for the common substrings
16061 * and replacing them with shorter !+character sequences via substitute().
16062 */
16063 for (/* see above */;
16064 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
16065 /* see loop */) {
16066 const char * scan_string = &identifier[scan_from_index];
16067
16068 did_sub = 0;
16069
16070 if (scan_from_index) {
16071 for (subs_entry = &kext_identifier_substring_subs[0];
16072 subs_entry->substring && !did_sub;
16073 subs_entry++) {
16074 did_sub = substitute(scan_string, identifier_out,
16075 &scan_to_index, &scan_from_index,
16076 subs_entry->substring, '!', subs_entry->substitute);
16077 }
16078 }
16079
16080 /* If we didn't substitute, copy the input character to the output.
16081 */
16082 if (!did_sub) {
16083 identifier_out[scan_to_index++] = identifier[scan_from_index++];
16084 }
16085 }
16086
16087 identifier_out[scan_to_index] = '\0';
16088 if (identifier_out_end) {
16089 *identifier_out_end = &identifier_out[scan_to_index];
16090 }
16091
16092 return;
16093 }
16094 #endif /* !defined(__arm__) && !defined(__arm64__) */
16095
16096 /*******************************************************************************
16097 * assemble_identifier_and_version() adds to a string buffer a compacted
16098 * bundle identifier followed by a version string.
16099 *******************************************************************************/
16100
16101 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
16102 */
16103 static size_t assemble_identifier_and_version(
16104 kmod_info_t * kmod_info,
16105 char * identPlusVers,
16106 size_t bufSize);
16107
16108 static size_t
16109 assemble_identifier_and_version(
16110 kmod_info_t * kmod_info,
16111 char * identPlusVers,
16112 size_t bufSize)
16113 {
16114 size_t result = 0;
16115
16116 #if defined(__arm__) || defined(__arm64__)
16117 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
16118 #else
16119 compactIdentifier(kmod_info->name, identPlusVers, NULL);
16120 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
16121 #endif
16122 identPlusVers[result++] = '\t'; // increment for real char
16123 identPlusVers[result] = '\0'; // don't increment for nul char
16124 result = strlcat(identPlusVers, kmod_info->version, bufSize);
16125 if (result >= bufSize) {
16126 identPlusVers[bufSize - 1] = '\0';
16127 result = bufSize - 1;
16128 }
16129
16130 return result;
16131 }
16132
16133 /*******************************************************************************
16134 * Assumes sKextLock is held.
16135 *******************************************************************************/
16136 /* static */
16137 int
16138 OSKext::saveLoadedKextPanicListTyped(
16139 const char * prefix,
16140 int invertFlag,
16141 int libsFlag,
16142 char * paniclist,
16143 uint32_t list_size)
16144 {
16145 int result = -1;
16146 unsigned int count, i;
16147
16148 count = sLoadedKexts->getCount();
16149 if (!count) {
16150 goto finish;
16151 }
16152
16153 i = count - 1;
16154 do {
16155 OSObject * rawKext = sLoadedKexts->getObject(i);
16156 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
16157 int match;
16158 size_t identPlusVersLength;
16159 size_t tempLen;
16160 char identPlusVers[2 * KMOD_MAX_NAME];
16161
16162 if (!rawKext) {
16163 printf("OSKext::saveLoadedKextPanicListTyped - "
16164 "NULL kext in loaded kext list; continuing\n");
16165 continue;
16166 }
16167
16168 if (!theKext) {
16169 printf("OSKext::saveLoadedKextPanicListTyped - "
16170 "Kext type cast failed in loaded kext list; continuing\n");
16171 continue;
16172 }
16173
16174 /* Skip all built-in kexts.
16175 */
16176 if (theKext->isKernelComponent()) {
16177 continue;
16178 }
16179
16180 kmod_info_t * kmod_info = theKext->kmod_info;
16181
16182 /* Filter for kmod name (bundle identifier).
16183 */
16184 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
16185 if ((match && invertFlag) || (!match && !invertFlag)) {
16186 continue;
16187 }
16188
16189 /* Filter for libraries (kexts that have a compatible version).
16190 */
16191 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
16192 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
16193 continue;
16194 }
16195
16196 if (!kmod_info ||
16197 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
16198 printf("kext scan stopped due to missing kmod_info page: %p\n",
16199 kmod_info);
16200 goto finish;
16201 }
16202
16203 identPlusVersLength = assemble_identifier_and_version(kmod_info,
16204 identPlusVers,
16205 sizeof(identPlusVers));
16206 if (!identPlusVersLength) {
16207 printf("error saving loaded kext info\n");
16208 goto finish;
16209 }
16210
16211 /* make sure everything fits and we null terminate.
16212 */
16213 tempLen = strlcat(paniclist, identPlusVers, list_size);
16214 if (tempLen >= list_size) {
16215 // panic list is full, keep it and null terminate
16216 paniclist[list_size - 1] = 0x00;
16217 result = 0;
16218 goto finish;
16219 }
16220 tempLen = strlcat(paniclist, "\n", list_size);
16221 if (tempLen >= list_size) {
16222 // panic list is full, keep it and null terminate
16223 paniclist[list_size - 1] = 0x00;
16224 result = 0;
16225 goto finish;
16226 }
16227 } while (i--);
16228
16229 result = 0;
16230 finish:
16231
16232 return result;
16233 }
16234
16235 /*********************************************************************
16236 *********************************************************************/
16237 /* static */
16238 void
16239 OSKext::saveLoadedKextPanicList(void)
16240 {
16241 char * newlist = NULL;
16242 uint32_t newlist_size = 0;
16243
16244 newlist_size = KEXT_PANICLIST_SIZE;
16245 newlist = (char *)kalloc_data_tag(newlist_size,
16246 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
16247
16248 if (!newlist) {
16249 OSKextLog(/* kext */ NULL,
16250 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
16251 "Couldn't allocate kext panic log buffer.");
16252 goto finish;
16253 }
16254
16255 newlist[0] = '\0';
16256
16257 // non-"com.apple." kexts
16258 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
16259 /* libs? */ -1, newlist, newlist_size) != 0) {
16260 goto finish;
16261 }
16262 // "com.apple." nonlibrary kexts
16263 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16264 /* libs? */ 0, newlist, newlist_size) != 0) {
16265 goto finish;
16266 }
16267 // "com.apple." library kexts
16268 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16269 /* libs? */ 1, newlist, newlist_size) != 0) {
16270 goto finish;
16271 }
16272
16273 if (loaded_kext_paniclist) {
16274 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
16275 }
16276 loaded_kext_paniclist = newlist;
16277 newlist = NULL;
16278 loaded_kext_paniclist_size = newlist_size;
16279
16280 finish:
16281 if (newlist) {
16282 kfree_data(newlist, newlist_size);
16283 }
16284 return;
16285 }
16286
16287 /*********************************************************************
16288 * Assumes sKextLock is held.
16289 *********************************************************************/
16290 void
16291 OSKext::savePanicString(bool isLoading)
16292 {
16293 u_long len;
16294
16295 if (!kmod_info) {
16296 return; // do not goto finish here b/c of lock
16297 }
16298
16299 len = assemble_identifier_and_version( kmod_info,
16300 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
16301 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
16302 if (!len) {
16303 printf("error saving unloaded kext info\n");
16304 goto finish;
16305 }
16306
16307 if (isLoading) {
16308 last_loaded_strlen = len;
16309 last_loaded_address = (void *)kmod_info->address;
16310 last_loaded_size = kmod_info->size;
16311 clock_get_uptime(&last_loaded_timestamp);
16312 } else {
16313 last_unloaded_strlen = len;
16314 last_unloaded_address = (void *)kmod_info->address;
16315 last_unloaded_size = kmod_info->size;
16316 clock_get_uptime(&last_unloaded_timestamp);
16317 }
16318
16319 finish:
16320 return;
16321 }
16322
16323 /*********************************************************************
16324 *********************************************************************/
16325 /* static */
16326 void
16327 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
16328 {
16329 if (last_loaded_strlen) {
16330 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
16331 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16332 last_loaded_strlen, last_loaded_str_buf,
16333 last_loaded_address, last_loaded_size);
16334 }
16335
16336 if (last_unloaded_strlen) {
16337 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16338 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16339 last_unloaded_strlen, last_unloaded_str_buf,
16340 last_unloaded_address, last_unloaded_size);
16341 }
16342
16343 printf_func("loaded kexts:\n");
16344 if (loaded_kext_paniclist &&
16345 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16346 loaded_kext_paniclist[0]) {
16347 printf_func("%.*s",
16348 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
16349 loaded_kext_paniclist);
16350 } else {
16351 printf_func("(none)\n");
16352 }
16353 return;
16354 }
16355
16356 /*********************************************************************
16357 * Assumes sKextLock is held.
16358 *********************************************************************/
16359 /* static */
16360 void
16361 OSKext::updateLoadedKextSummaries(void)
16362 {
16363 kern_return_t result = KERN_FAILURE;
16364 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16365 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16366 OSKext *aKext;
16367 vm_map_offset_t start;
16368 size_t summarySize = 0;
16369 size_t size;
16370 u_int count;
16371 u_int maxKexts;
16372 u_int i, j;
16373 OSKextActiveAccount * accountingList;
16374 OSKextActiveAccount * prevAccountingList;
16375 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16376
16377 prevAccountingList = NULL;
16378 prevAccountingListCount = 0;
16379
16380 #if DEVELOPMENT || DEBUG
16381 if (IORecursiveLockHaveLock(sKextLock) == false) {
16382 panic("sKextLock must be held");
16383 }
16384 #endif
16385
16386 IOLockLock(sKextSummariesLock);
16387
16388 count = sLoadedKexts->getCount();
16389 for (i = 0, maxKexts = 0; i < count; ++i) {
16390 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16391 maxKexts += (aKext && (aKext->isExecutable() || aKext->isSpecialKernelBinary()));
16392 }
16393
16394 if (!maxKexts) {
16395 goto finish;
16396 }
16397 if (maxKexts < kOSKextTypicalLoadCount) {
16398 maxKexts = kOSKextTypicalLoadCount;
16399 }
16400
16401 /* Calculate the size needed for the new summary headers.
16402 */
16403
16404 size = sizeof(*gLoadedKextSummaries);
16405 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16406 size = round_page(size);
16407
16408 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16409 if (gLoadedKextSummaries) {
16410 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
16411 gLoadedKextSummaries = NULL;
16412 gLoadedKextSummariesTimestamp = mach_absolute_time();
16413 sLoadedKextSummariesAllocSize = 0;
16414 }
16415 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
16416 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
16417 if (result != KERN_SUCCESS) {
16418 goto finish;
16419 }
16420 summaryHeader = summaryHeaderAlloc;
16421 summarySize = size;
16422 } else {
16423 summaryHeader = gLoadedKextSummaries;
16424 summarySize = sLoadedKextSummariesAllocSize;
16425
16426 start = (vm_map_offset_t) summaryHeader;
16427 result = mach_vm_protect(kernel_map,
16428 start,
16429 summarySize,
16430 false,
16431 VM_PROT_DEFAULT);
16432 if (result != KERN_SUCCESS) {
16433 goto finish;
16434 }
16435 }
16436
16437 /* Populate the summary header.
16438 */
16439
16440 bzero(summaryHeader, summarySize);
16441 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16442 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16443
16444 /* Populate each kext summary.
16445 */
16446
16447 count = sLoadedKexts->getCount();
16448 accountingListAlloc = 0;
16449 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16450 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16451 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16452 continue;
16453 }
16454
16455 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
16456 summaryHeader->numSummaries++;
16457 accountingListAlloc++;
16458 }
16459
16460 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16461 accountingListCount = 0;
16462 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16463 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16464 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16465 continue;
16466 }
16467
16468 OSKextActiveAccount activeAccount;
16469 aKext->updateActiveAccount(&activeAccount);
16470 // order by address
16471 for (idx = 0; idx < accountingListCount; idx++) {
16472 if (activeAccount.address < accountingList[idx].address) {
16473 break;
16474 }
16475 }
16476 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
16477 accountingList[idx] = activeAccount;
16478 accountingListCount++;
16479 }
16480 assert(accountingListCount == accountingListAlloc);
16481 /* Write protect the buffer and move it into place.
16482 */
16483
16484 start = (vm_map_offset_t) summaryHeader;
16485
16486 result = mach_vm_protect(kernel_map, start, summarySize, false, VM_PROT_READ);
16487 if (result != KERN_SUCCESS) {
16488 goto finish;
16489 }
16490
16491 gLoadedKextSummaries = summaryHeader;
16492 gLoadedKextSummariesTimestamp = mach_absolute_time();
16493 sLoadedKextSummariesAllocSize = summarySize;
16494 summaryHeaderAlloc = NULL;
16495
16496 /* Call the magic breakpoint function through a static function pointer so
16497 * the compiler can't optimize the function away.
16498 */
16499 if (sLoadedKextSummariesUpdated) {
16500 (*sLoadedKextSummariesUpdated)();
16501 }
16502
16503 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16504 prevAccountingList = sKextAccounts;
16505 prevAccountingListCount = sKextAccountsCount;
16506 sKextAccounts = accountingList;
16507 sKextAccountsCount = accountingListCount;
16508 lck_ticket_unlock(sKextAccountsLock);
16509
16510 finish:
16511 IOLockUnlock(sKextSummariesLock);
16512
16513 /* If we had to allocate a new buffer but failed to generate the summaries,
16514 * free that now.
16515 */
16516 if (summaryHeaderAlloc) {
16517 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
16518 }
16519 if (prevAccountingList) {
16520 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16521 }
16522
16523 return;
16524 }
16525
16526 /*********************************************************************
16527 *********************************************************************/
16528 void
16529 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16530 {
16531 OSSharedPtr<OSData> uuid;
16532
16533 strlcpy(summary->name, getIdentifierCString(),
16534 sizeof(summary->name));
16535
16536 uuid = copyUUID();
16537 if (uuid) {
16538 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
16539 }
16540
16541 if (flags.builtin) {
16542 // this value will stop lldb from parsing the mach-o header
16543 // summary->address = UINT64_MAX;
16544 // summary->size = 0;
16545 summary->address = kmod_info->address;
16546 summary->size = kmod_info->size;
16547 } else {
16548 summary->address = kmod_info->address;
16549 summary->size = kmod_info->size;
16550 }
16551 summary->version = getVersion();
16552 summary->loadTag = kmod_info->id;
16553 summary->flags = 0;
16554 summary->reference_list = (uint64_t) kmod_info->reference_list;
16555
16556 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16557 if (summary->text_exec_address == 0) {
16558 // Fallback to __TEXT
16559 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16560 }
16561
16562 /**
16563 * If the addresses within the Mach-O are unslid, then manually slide any
16564 * addresses coming from the Mach-O as higher layer software using these
16565 * summaries expects a slid address here.
16566 */
16567 if (flags.unslidMachO) {
16568 summary->text_exec_address = (uint64_t) ml_static_slide((vm_offset_t) summary->text_exec_address);
16569 }
16570
16571 return;
16572 }
16573
16574 /*********************************************************************
16575 *********************************************************************/
16576
16577 void
16578 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16579 {
16580 kernel_mach_header_t *hdr = NULL;
16581 kernel_segment_command_t *seg = NULL;
16582
16583 bzero(accountp, sizeof(*accountp));
16584
16585 hdr = (kernel_mach_header_t *)kmod_info->address;
16586 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16587 /*
16588 * If this kext supports split segments (or is in a new
16589 * MH_FILESET kext collection), use the first
16590 * executable segment as the range for instructions
16591 * (and thus for backtracing.
16592 */
16593 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
16594 if (seg->initprot & VM_PROT_EXECUTE) {
16595 break;
16596 }
16597 }
16598 }
16599 if (seg) {
16600 accountp->address = seg->vmaddr;
16601 if (accountp->address) {
16602 accountp->address_end = seg->vmaddr + seg->vmsize;
16603 }
16604 } else {
16605 /* For non-split kexts and for kexts without executable
16606 * segments, just use the kmod_info range (as the kext
16607 * is either all in one range or should not show up in
16608 * instruction backtraces).
16609 */
16610 accountp->address = kmod_info->address;
16611 if (accountp->address) {
16612 accountp->address_end = kmod_info->address + kmod_info->size;
16613 }
16614 }
16615
16616 accountp->account = this->account;
16617 }
16618
16619 bool
16620 OSKext::isDriverKit(void)
16621 {
16622 OSString *bundleType;
16623
16624 if (infoDict) {
16625 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16626 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16627 return TRUE;
16628 }
16629 }
16630 return FALSE;
16631 }
16632
16633 bool
16634 OSKext::isInFileset(void)
16635 {
16636 if (!kmod_info) {
16637 goto check_prelinked;
16638 }
16639
16640 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16641 return true;
16642 }
16643
16644 check_prelinked:
16645 if (isPrelinked()) {
16646 /*
16647 * If we haven't setup kmod_info yet, but we know
16648 * we're loading a prelinked kext in an MH_FILESET KC,
16649 * then return true
16650 */
16651 kc_format_t kc_format;
16652 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
16653 return true;
16654 }
16655 }
16656 return false;
16657 }
16658
16659 OSSharedPtr<OSDextStatistics>
16660 OSKext::copyDextStatistics(void)
16661 {
16662 return dextStatistics;
16663 }
16664
16665 bool
16666 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16667 {
16668 kern_return_t result;
16669 if (!super::init()) {
16670 return false;
16671 }
16672 if (seg == nullptr) {
16673 return false;
16674 }
16675 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
16676 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16677 if (result != KERN_SUCCESS) {
16678 return false;
16679 }
16680 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
16681 savedSegment = seg;
16682 vmsize = seg->vmsize;
16683 vmaddr = seg->vmaddr;
16684 return true;
16685 }
16686
16687 OSSharedPtr<OSKextSavedMutableSegment>
16688 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16689 {
16690 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16691 if (me && !me->initWithSegment(seg)) {
16692 return nullptr;
16693 }
16694 return me;
16695 }
16696
16697 void
16698 OSKextSavedMutableSegment::free(void)
16699 {
16700 if (data) {
16701 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
16702 }
16703 }
16704
16705 vm_offset_t
16706 OSKextSavedMutableSegment::getVMAddr() const
16707 {
16708 return vmaddr;
16709 }
16710
16711 vm_offset_t
16712 OSKextSavedMutableSegment::getVMSize() const
16713 {
16714 return vmsize;
16715 }
16716
16717 OSReturn
16718 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16719 {
16720 if (seg != savedSegment) {
16721 return kOSKextReturnInvalidArgument;
16722 }
16723 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16724 return kOSKextReturnInvalidArgument;
16725 }
16726 memcpy((void *)seg->vmaddr, data, vmsize);
16727 return kOSReturnSuccess;
16728 }
16729
16730 extern "C" kern_return_t
16731 OSKextSetReceiptQueried(void)
16732 {
16733 OSKextLog(/* kext */ NULL,
16734 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16735 "Setting kext receipt as queried");
16736
16737 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
16738 return KERN_SUCCESS;
16739 }
16740
16741 extern "C" const vm_allocation_site_t *
16742 OSKextGetAllocationSiteForCaller(uintptr_t address)
16743 {
16744 OSKextActiveAccount * active;
16745 vm_allocation_site_t * site;
16746 vm_allocation_site_t * releasesite;
16747
16748 uint32_t baseIdx;
16749 uint32_t lim;
16750 #if __has_feature(ptrauth_calls)
16751 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16752 #endif /* __has_feature(ptrauth_calls) */
16753
16754 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16755 site = releasesite = NULL;
16756
16757 // bsearch sKextAccounts list
16758 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16759 active = &sKextAccounts[baseIdx + (lim >> 1)];
16760 if ((address >= active->address) && (address < active->address_end)) {
16761 site = &active->account->site;
16762 if (!site->tag) {
16763 vm_tag_alloc_locked(site, &releasesite);
16764 }
16765 break;
16766 } else if (address > active->address) {
16767 // move right
16768 baseIdx += (lim >> 1) + 1;
16769 lim--;
16770 }
16771 // else move left
16772 }
16773 lck_ticket_unlock(sKextAccountsLock);
16774 if (releasesite) {
16775 kern_allocation_name_release(releasesite);
16776 }
16777
16778 return site;
16779 }
16780
16781 #if DEVELOPMENT || DEBUG
16782 extern "C" void
16783 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16784 {
16785 OSKextActiveAccount * active;
16786
16787 uint32_t baseIdx;
16788 uint32_t lim;
16789 #if __has_feature(ptrauth_calls)
16790 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16791 #endif /* __has_feature(ptrauth_calls) */
16792
16793 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16794
16795 // bsearch sKextAccounts list
16796 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16797 active = &sKextAccounts[baseIdx + (lim >> 1)];
16798 if ((address >= active->address) && (address < active->address_end)) {
16799 cb(&active->account->task_refgrp);
16800 break;
16801 } else if (address > active->address) {
16802 // move right
16803 baseIdx += (lim >> 1) + 1;
16804 lim--;
16805 }
16806 // else move left
16807 }
16808 lck_ticket_unlock(sKextAccountsLock);
16809 }
16810 #endif /* DEVELOPMENT || DEBUG */
16811
16812 extern "C" uint32_t
16813 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16814 {
16815 OSKextAccount * account = (typeof(account))site;
16816 const char * kname;
16817
16818 if (name) {
16819 if (account->kext) {
16820 kname = account->kext->getIdentifierCString();
16821 } else {
16822 kname = "<>";
16823 }
16824 strlcpy(name, kname, namelen);
16825 }
16826
16827 return account->loadTag;
16828 }
16829
16830 extern "C" void
16831 OSKextFreeSite(vm_allocation_site_t * site)
16832 {
16833 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16834 IOFreeType(freeAccount, OSKextAccount);
16835 }
16836
16837 /*********************************************************************
16838 *********************************************************************/
16839
16840 #if CONFIG_IMAGEBOOT
16841 int
16842 OSKextGetUUIDForName(const char *name, uuid_t uuid)
16843 {
16844 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
16845 if (!kext) {
16846 return 1;
16847 }
16848
16849 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16850 if (uuid_data) {
16851 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
16852 return 0;
16853 }
16854
16855 return 1;
16856 }
16857 #endif
16858
16859
16860
16861 class OSDextCrash : public OSObject {
16862 OSDeclareDefaultStructors(OSDextCrash);
16863 public:
16864 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16865 uint64_t getTimestamp();
16866
16867 private:
16868 virtual bool initWithTimestamp(uint64_t timestamp);
16869 uint64_t fTimestamp;
16870 };
16871
16872 OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16873
16874 OSSharedPtr<OSDextCrash>
16875 OSDextCrash::withTimestamp(uint64_t timestamp)
16876 {
16877 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16878 if (!result->initWithTimestamp(timestamp)) {
16879 return NULL;
16880 }
16881 return result;
16882 }
16883
16884 bool
16885 OSDextCrash::initWithTimestamp(uint64_t timestamp)
16886 {
16887 if (!OSObject::init()) {
16888 return false;
16889 }
16890 fTimestamp = timestamp;
16891 return true;
16892 }
16893
16894 uint64_t
16895 OSDextCrash::getTimestamp()
16896 {
16897 return fTimestamp;
16898 }
16899
16900 OSSharedPtr<OSDextStatistics>
16901 OSDextStatistics::create()
16902 {
16903 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16904 if (!result->init()) {
16905 return NULL;
16906 }
16907 return result;
16908 }
16909
16910 bool
16911 OSDextStatistics::init()
16912 {
16913 if (!OSObject::init()) {
16914 return false;
16915 }
16916
16917 lock = IOLockAlloc();
16918 crashes = OSArray::withCapacity(kMaxDextCrashesInOneDay);
16919 return true;
16920 }
16921
16922 void
16923 OSDextStatistics::free()
16924 {
16925 if (lock) {
16926 IOLockFree(lock);
16927 }
16928 crashes.reset();
16929 OSObject::free();
16930 }
16931
16932 OSDextCrashPolicy
16933 OSDextStatistics::recordCrash()
16934 {
16935 size_t i = 0;
16936 uint64_t timestamp = mach_continuous_time();
16937 uint64_t interval;
16938 nanoseconds_to_absolutetime(86400 * NSEC_PER_SEC /* 1 day */, &interval);
16939 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16940 OSDextCrashPolicy policy;
16941
16942 IOLockLock(lock);
16943 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16944 for (i = 0; i < crashes->getCount();) {
16945 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16946 assert(current != NULL);
16947 if (current->getTimestamp() < lastTimestamp) {
16948 crashes->removeObject(i);
16949 } else {
16950 i++;
16951 }
16952 }
16953
16954 crashes->setObject(crash);
16955
16956 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16957 policy = kOSDextCrashPolicyReboot;
16958 } else {
16959 policy = kOSDextCrashPolicyNone;
16960 }
16961
16962 IOLockUnlock(lock);
16963
16964 return policy;
16965 }
16966
16967 size_t
16968 OSDextStatistics::getCrashCount()
16969 {
16970 size_t result = 0;
16971 IOLockLock(lock);
16972 result = crashes->getCount();
16973 IOLockUnlock(lock);
16974 return result;
16975 }
16976
16977 static int
16978 sysctl_willuserspacereboot
16979 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
16980 {
16981 int new_value = 0, old_value = 0, changed = 0;
16982 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
16983 if (error) {
16984 return error;
16985 }
16986 if (changed) {
16987 OSKext::willUserspaceReboot();
16988 }
16989 return 0;
16990 }
16991
16992 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
16993 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
16994 NULL, 0, sysctl_willuserspacereboot, "I", "");
16995