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 <sys/reboot.h>
54 #include <pexpert/pexpert.h>
55 #include <pexpert/device_tree.h>
56
57 #include <sys/pgo.h>
58
59 #if CONFIG_CSR
60 #include <sys/csr.h>
61 #include <sys/stat.h>
62 #include <sys/vnode.h>
63 #endif /* CONFIG_CSR */
64 };
65
66 #if CONFIG_MACF
67 #include <sys/kauth.h>
68 #include <security/mac_framework.h>
69 #endif
70
71 #include <vm/vm_kern_xnu.h>
72 #include <sys/sysctl.h>
73 #include <kern/task.h>
74 #include <os/cpp_util.h>
75
76 #include <libkern/OSKextLibPrivate.h>
77 #include <libkern/c++/OSKext.h>
78 #include <libkern/c++/OSLib.h>
79
80 #include <IOKit/IOLib.h>
81 #include <IOKit/IOCatalogue.h>
82 #include <IOKit/IORegistryEntry.h>
83 #include <IOKit/IOService.h>
84 #include <IOKit/IOUserServer.h>
85
86 #include <IOKit/IOStatisticsPrivate.h>
87 #include <IOKit/IOBSD.h>
88 #include <IOKit/IOPlatformExpert.h>
89
90 #include <san/kasan.h>
91
92 #if CONFIG_SPTM
93 #include <arm64/sptm/sptm.h>
94 #endif
95
96 #if PRAGMA_MARK
97 #pragma mark External & Internal Function Protos
98 #endif
99 /*********************************************************************
100 *********************************************************************/
101 extern "C" {
102 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
103 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
104
105 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
106 extern int dtrace_keep_kernel_symbols(void);
107
108 #if defined(__x86_64__) || defined(__i386__)
109 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
110 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
111 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
112 static void *allocate_kcfileset_map_entry_list(void);
113 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
114 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
115 int vnode_put(struct vnode *vp);
116 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
117 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
118 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
119 void * ubc_getobject(struct vnode *vp, __unused int flags);
120 #endif //(__x86_64__) || defined(__i386__)
121 }
122
123 extern unsigned long gVirtBase;
124 extern unsigned long gPhysBase;
125
126 bool pageableKCloaded = false;
127 bool auxKCloaded = false;
128 bool resetAuxKCSegmentOnUnload = false;
129
130 extern boolean_t pageablekc_uuid_valid;
131 extern uuid_t pageablekc_uuid;
132 extern uuid_string_t pageablekc_uuid_string;
133
134 extern boolean_t auxkc_uuid_valid;
135 extern uuid_t auxkc_uuid;
136 extern uuid_string_t auxkc_uuid_string;
137
138 static OSReturn _OSKextCreateRequest(
139 const char * predicate,
140 OSSharedPtr<OSDictionary> & requestP);
141 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
142 static OSObject * _OSKextGetRequestArgument(
143 OSDictionary * requestDict,
144 const char * argName);
145 static bool _OSKextSetRequestArgument(
146 OSDictionary * requestDict,
147 const char * argName,
148 OSMetaClassBase * value);
149 template <typename T>
150 static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
151 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
152 static OSReturn _OSDictionarySetCStringValue(
153 OSDictionary * dict,
154 const char * key,
155 const char * value);
156 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
157 #if CONFIG_KXLD
158 static bool _OSKextInPrelinkRebuildWindow(void);
159 #endif
160
161 // We really should add containsObject() & containsCString to OSCollection & subclasses.
162 // So few pad slots, though....
163 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
164 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
165
166 static const char *getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size);
167
168 /* Prelinked arm kexts do not have VM entries because the method we use to
169 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
170 * not work on ARM. To get around that, we must free prelinked kext
171 * executables with ml_static_mfree() instead of kext_free().
172 */
173 #if __i386__ || __x86_64__
174 #define VM_MAPPED_KEXTS 1
175 #define KASLR_KEXT_DEBUG 0
176 #define KASLR_IOREG_DEBUG 0
177 #elif __arm__ || __arm64__
178 #define VM_MAPPED_KEXTS 0
179 #define KASLR_KEXT_DEBUG 0
180 #else
181 #error Unsupported architecture
182 #endif
183
184 #if PRAGMA_MARK
185 #pragma mark Constants & Macros
186 #endif
187 /*********************************************************************
188 * Constants & Macros
189 *********************************************************************/
190
191 /* Use this number to create containers.
192 */
193 #define kOSKextTypicalLoadCount (150)
194 #define kOSKextTypicalUpgradeCount (5)
195
196 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
197 * A loaded kext will no dependents or external retains will have 2 retains.
198 */
199 #define kOSKextMinRetainCount (1)
200 #define kOSKextMinLoadedRetainCount (2)
201
202 #define kOSKextMaxDextLaunchedCount (~((uint32_t)0))
203 #define KOSBundleDextUniqueIdentifierMaxStringLength (KOSBundleDextUniqueIdentifierMaxLength * 2 +1)
204
205 /**********
206 * Strings and substrings used in dependency resolution.
207 */
208 #define APPLE_KEXT_PREFIX "com.apple."
209 #define KERNEL_LIB "com.apple.kernel"
210
211 #define PRIVATE_KPI "com.apple.kpi.private"
212
213 /* Version for compatbility pseudokexts (com.apple.kernel.*),
214 * compatible back to v6.0.
215 */
216 #define KERNEL6_LIB "com.apple.kernel.6.0"
217 #define KERNEL6_VERSION "7.9.9"
218
219 #define KERNEL_LIB_PREFIX "com.apple.kernel."
220 #define KPI_LIB_PREFIX "com.apple.kpi."
221
222 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
223
224 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
225 #define MINIMUM_WAKEUP_SECONDS (30)
226
227 /*********************************************************************
228 * infoDict keys for internally-stored data. Saves on ivar slots for
229 * objects we don't keep around past boot time or during active load.
230 *********************************************************************/
231
232 /* A usable, uncompressed file is stored under this key.
233 */
234 #define _kOSKextExecutableKey "_OSKextExecutable"
235
236 /* An indirect reference to the executable file from an mkext
237 * is stored under this key.
238 */
239 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
240
241 /* If the file is contained in a larger buffer laid down by the booter or
242 * sent from user space, the OSKext stores that OSData under this key so that
243 * references are properly tracked. This is always an mkext, right now.
244 */
245 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
246
247 #define OS_LOG_HDR_VERSION 1
248 #define NUM_OS_LOG_SECTIONS 3
249
250 #define OS_LOG_SECT_IDX 0
251 #define CSTRING_SECT_IDX 1
252 #define ASAN_CSTRING_SECT_IDX 2
253
254 #if PRAGMA_MARK
255 #pragma mark Typedefs
256 #endif
257 /*********************************************************************
258 * Typedefs
259 *********************************************************************/
260
261 /*********************************************************************
262 * osLogDataHeaderRef describes the header information of an OSData
263 * object that is returned when querying for kOSBundleLogStringsKey.
264 * We currently return information regarding 2 sections - os_log and
265 * cstring. In the case that the os_log section doesn't exist, we just
266 * return an offset and length of 0 for that section.
267 *********************************************************************/
268 typedef struct osLogDataHeader {
269 uint32_t version;
270 uint32_t sect_count;
271 struct {
272 uint32_t sect_offset;
273 uint32_t sect_size;
274 } sections[0];
275 } osLogDataHeaderRef;
276
277 /*********************************************************************
278 * MkextEntryRef describes the contents of an OSData object
279 * referencing a file entry from an mkext so that we can uncompress
280 * (if necessary) and extract it on demand.
281 *
282 * It contains the mkextVersion in case we ever wind up supporting
283 * multiple mkext formats. Mkext format 1 is officially retired as of
284 * Snow Leopard.
285 *********************************************************************/
286 typedef struct MkextEntryRef {
287 mkext_basic_header * mkext; // beginning of whole mkext file
288 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
289 } MkextEntryRef;
290
291 #if PRAGMA_MARK
292 #pragma mark Global and static Module Variables
293 #endif
294 /*********************************************************************
295 * Global & static variables, used to keep track of kexts.
296 *********************************************************************/
297
298 static bool sPrelinkBoot = false;
299 static bool sSafeBoot = false;
300 static bool sKeepSymbols = false;
301 static bool sPanicOnKCMismatch = false;
302 static bool sOSKextWasResetAfterUserspaceReboot = false;
303
304 /*********************************************************************
305 * sKextLock is the principal lock for OSKext, and guards all static
306 * and global variables not owned by other locks (declared further
307 * below). It must be taken by any entry-point method or function,
308 * including internal functions called on scheduled threads.
309 *
310 * sKextLock and sKextInnerLock are recursive due to multiple functions
311 * that are called both externally and internally. The other locks are
312 * nonrecursive.
313 *
314 * Which locks are taken depends on what they protect, but if more than
315 * one must be taken, they must always be locked in this order
316 * (and unlocked in reverse order) to prevent deadlocks:
317 *
318 * 1. sKextLock
319 * 2. sKextInnerLock
320 * 3. sKextSummariesLock
321 * 4. sKextLoggingLock
322 */
323 static IORecursiveLock * sKextLock = NULL;
324
325 static OSSharedPtr<OSDictionary> sKextsByID;
326 static OSSharedPtr<OSDictionary> sExcludeListByID;
327 static OSKextVersion sExcludeListVersion = 0;
328 static OSSharedPtr<OSArray> sLoadedKexts;
329 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
330 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
331 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
332 static OSSharedPtr<OSDictionary> sDriverKitToUpgradeByID;
333
334 // Requests to the IOKit daemon waiting to be picked up.
335 static OSSharedPtr<OSArray> sKernelRequests;
336 // Identifier of kext load requests in sKernelRequests
337 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
338 static OSSharedPtr<OSArray> sRequestCallbackRecords;
339
340 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
341 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
342 #if CONFIG_KXLD
343 static KXLDContext * sKxldContext = NULL;
344 #endif
345 static uint32_t sNextLoadTag = 0;
346 static uint32_t sNextRequestTag = 0;
347
348 static bool sUserLoadsActive = false;
349 static bool sIOKitDaemonActive = false;
350 static bool sDeferredLoadSucceeded = false;
351 static bool sConsiderUnloadsExecuted = false;
352
353 #if NO_KEXTD
354 static bool sKernelRequestsEnabled = false;
355 #else
356 static bool sKernelRequestsEnabled = true;
357 #endif
358 static bool sLoadEnabled = true;
359 static bool sUnloadEnabled = true;
360
361 /*********************************************************************
362 * Stuff for the OSKext representing the kernel itself.
363 **********/
364 static OSKext * sKernelKext = NULL;
365
366 /* Load Tag IDs used by statically loaded binaries (e.g, the kernel itself). */
367 enum : uint32_t {
368 kOSKextKernelLoadTag = 0,
369 #if CONFIG_SPTM
370 kOSKextSPTMLoadTag = 1,
371 kOSKextTXMLoadTag = 2,
372 #endif /* CONFIG_SPTM */
373 kOSKextLoadTagCount
374 };
375
376 /* Set up a fake kmod_info struct for the kernel.
377 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
378 * before OSKext is initialized; that call only needs the name
379 * and address to be set correctly.
380 *
381 * We don't do much else with the kerne's kmod_info; we never
382 * put it into the kmod list, never adjust the reference count,
383 * and never have kernel components reference it.
384 * For that matter, we don't do much with kmod_info structs
385 * at all anymore! We just keep them filled in for gdb and
386 * binary compability.
387 */
388 kmod_info_t g_kernel_kmod_info = {
389 .next = NULL,
390 .info_version = KMOD_INFO_VERSION,
391 .id = kOSKextKernelLoadTag, // loadTag: kernel is always 0
392 .name = kOSKextKernelIdentifier,// bundle identifier
393 .version = "0", // filled in in OSKext::initialize()
394 .reference_count = -1, // never adjusted; kernel never unloads
395 .reference_list = NULL,
396 .address = 0,
397 .size = 0, // filled in in OSKext::initialize()
398 .hdr_size = 0,
399 .start = NULL,
400 .stop = NULL
401 };
402
403 #if CONFIG_SPTM
404 /* The SPTM and TXM need fake kmod structures just like the kernel. */
405 kmod_info_t g_sptm_kmod_info = {
406 .next = NULL,
407 .info_version = KMOD_INFO_VERSION,
408 .id = kOSKextSPTMLoadTag, // Always one after the kernel
409 .name = kOSKextSPTMIdentifier,// bundle identifier
410 .version = "0", // filled in by OSKext::initialize()
411 .reference_count = -1, // never adjusted; SPTM never unloads
412 .reference_list = NULL,
413 .address = 0,
414 .size = 0, // filled in by OSKext::initialize()
415 .hdr_size = 0,
416 .start = NULL,
417 .stop = NULL
418 };
419
420 kmod_info_t g_txm_kmod_info = {
421 .next = NULL,
422 .info_version = KMOD_INFO_VERSION,
423 .id = kOSKextTXMLoadTag, // Always one after the SPTM
424 .name = kOSKextTXMIdentifier,// bundle identifier
425 .version = "0", // filled in by OSKext::initialize()
426 .reference_count = -1, // never adjusted; TXM never unloads
427 .reference_list = NULL,
428 .address = 0,
429 .size = 0, // filled in by OSKext::initialize()
430 .hdr_size = 0,
431 .start = NULL,
432 .stop = NULL
433 };
434 #endif /* CONFIG_SPTM */
435
436 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
437
438 kmod_info_t invalid_kmod_info = {
439 .next = NULL,
440 .info_version = KMOD_INFO_VERSION,
441 .id = UINT32_MAX,
442 .name = "invalid",
443 .version = "0",
444 .reference_count = -1,
445 .reference_list = NULL,
446 .address = 0,
447 .size = 0,
448 .hdr_size = 0,
449 .start = NULL,
450 .stop = NULL
451 };
452
453 extern "C" {
454 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
455 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
456 // misc_protos.h, db_low_trace.c, kgmacros
457 // 'kmod' is a holdover from the old kmod system, we can't rename it.
458 kmod_info_t * kmod = NULL;
459
460 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
461
462
463 static char * loaded_kext_paniclist = NULL;
464 static uint32_t loaded_kext_paniclist_size = 0;
465
466 AbsoluteTime last_loaded_timestamp;
467 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
468 static u_long last_loaded_strlen = 0;
469 static void * last_loaded_address = NULL;
470 static u_long last_loaded_size = 0;
471
472 AbsoluteTime last_unloaded_timestamp;
473 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
474 static u_long last_unloaded_strlen = 0;
475 static void * last_unloaded_address = NULL;
476 static u_long last_unloaded_size = 0;
477
478 // Statically linked kmods described by several mach-o sections:
479 //
480 // kPrelinkInfoSegment:kBuiltinInfoSection
481 // Array of pointers to kmod_info_t structs.
482 //
483 // kPrelinkInfoSegment:kBuiltinInfoSection
484 // Array of pointers to an embedded mach-o header.
485 //
486 // __DATA:kBuiltinInitSection, kBuiltinTermSection
487 // Structors for all kmods. Has to be filtered by proc address.
488 //
489
490 static uint32_t gBuiltinKmodsCount;
491 static kernel_section_t * gBuiltinKmodsSectionInfo;
492 static kernel_section_t * gBuiltinKmodsSectionStart;
493
494 const OSSymbol * gIOSurfaceIdentifier;
495 vm_tag_t gIOSurfaceTag;
496
497 /*********************************************************************
498 * sKextInnerLock protects against cross-calls with IOService and
499 * IOCatalogue, and owns the variables declared immediately below.
500 *
501 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
502 *
503 * When both sKextLock and sKextInnerLock need to be taken,
504 * always lock sKextLock first and unlock it second. Never take both
505 * locks in an entry point to OSKext; if you need to do so, you must
506 * spawn an independent thread to avoid potential deadlocks for threads
507 * calling into OSKext.
508 **********/
509 static IORecursiveLock * sKextInnerLock = NULL;
510
511 #if XNU_TARGET_OS_OSX
512 static bool sAutounloadEnabled = true;
513 #endif
514 static bool sConsiderUnloadsCalled = false;
515 static bool sConsiderUnloadsPending = false;
516
517 static unsigned int sConsiderUnloadDelay = 60; // seconds
518 static thread_call_t sUnloadCallout = NULL;
519 #if CONFIG_KXLD
520 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
521 #endif // CONFIG_KXLD
522 static bool sSystemSleep = false; // true when system going to sleep
523 static AbsoluteTime sLastWakeTime; // last time we woke up
524
525 /*********************************************************************
526 * Backtraces can be printed at various times so we need a tight lock
527 * on data used for that. sKextSummariesLock protects the variables
528 * declared immediately below.
529 *
530 * gLoadedKextSummaries is accessed by other modules, but only during
531 * a panic so the lock isn't needed then.
532 *
533 * gLoadedKextSummaries has the "used" attribute in order to ensure
534 * that it remains visible even when we are performing extremely
535 * aggressive optimizations, as it is needed to allow the debugger
536 * to automatically parse the list of loaded kexts.
537 **********/
538 static IOLock * sKextSummariesLock = NULL;
539 extern "C" lck_grp_t vm_page_lck_grp_bucket;
540 static lck_grp_t * sKextAccountsLockGrp = &vm_page_lck_grp_bucket;
541 #define sKextAccountsLock (&vm_allocation_sites_lock)
542
543 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
544 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
545 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
546 static size_t sLoadedKextSummariesAllocSize = 0;
547
548 static OSKextActiveAccount * sKextAccounts;
549 static uint32_t sKextAccountsCount;
550 };
551
552 /*********************************************************************
553 * sKextLoggingLock protects the logging variables declared immediately below.
554 **********/
555 __static_testable IOLock * sKextLoggingLock = NULL;
556
557 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
558 kOSKextLogVerboseFlagsMask;
559 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
560 static bool sBootArgLogFilterFound = false;
561 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
562 0, "kernel kext logging");
563
564 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
565 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
566 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
567
568 /*********
569 * End scope for sKextInnerLock-protected variables.
570 *********************************************************************/
571
572 /*********************************************************************
573 * OSValueObject concrete type instantiations
574 **********/
575 OSDefineValueObjectForDependentType(void*)
576 OSDefineValueObjectForDependentType(OSKextRequestResourceCallback)
577
578
579 /**********************************************************************/
580
581 TUNABLE(uint32_t, kMaxDextCrashesInOneDay, "daily_max_dext_crashes", kMaxDextCrashesInOneDayDefault);
582
583 /*********************************************************************
584 * helper function used for collecting PGO data upon unload of a kext
585 */
586
587 static int OSKextGrabPgoDataLocked(OSKext *kext,
588 bool metadata,
589 uuid_t instance_uuid,
590 uint64_t *pSize,
591 char *pBuffer,
592 uint64_t bufferSize);
593
594 /**********************************************************************/
595
596
597
598 #if PRAGMA_MARK
599 #pragma mark OSData callbacks (need to move to OSData)
600 #endif
601 /*********************************************************************
602 * C functions used for callbacks.
603 *********************************************************************/
604 extern "C" {
605 void
osdata_kmem_free(void * ptr,unsigned int length)606 osdata_kmem_free(void * ptr, unsigned int length)
607 {
608 kmem_free(kernel_map, (vm_address_t)ptr, length);
609 return;
610 }
611
612 void
osdata_phys_free(void * ptr,unsigned int length)613 osdata_phys_free(void * ptr, unsigned int length)
614 {
615 ml_static_mfree((vm_offset_t)ptr, length);
616 return;
617 }
618
619 void
osdata_vm_deallocate(void * ptr,unsigned int length)620 osdata_vm_deallocate(void * ptr, unsigned int length)
621 {
622 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
623 return;
624 }
625
626 void
osdata_kext_free(void * ptr,unsigned int length)627 osdata_kext_free(void * ptr, unsigned int length)
628 {
629 (void)kext_free((vm_offset_t)ptr, length);
630 }
631 };
632
633 #if PRAGMA_MARK
634 #pragma mark KXLD Allocation Callback
635 #endif
636 #if CONFIG_KXLD
637 /*********************************************************************
638 * KXLD Allocation Callback
639 *********************************************************************/
640 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)641 kern_allocate(
642 u_long size,
643 KXLDAllocateFlags * flags,
644 void * user_data)
645 {
646 vm_address_t result = 0; // returned
647 kern_return_t mach_result = KERN_FAILURE;
648 bool success = false;
649 OSKext * theKext = (OSKext *)user_data;
650 unsigned int roundSize = 0;
651 OSSharedPtr<OSData> linkBuffer;
652
653 if (round_page(size) > UINT_MAX) {
654 OSKextLog(theKext,
655 kOSKextLogErrorLevel |
656 kOSKextLogGeneralFlag,
657 "%s: Requested memory size is greater than UINT_MAX.",
658 theKext->getIdentifierCString());
659 goto finish;
660 }
661
662 roundSize = (unsigned int)round_page(size);
663
664 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
665 if (mach_result != KERN_SUCCESS) {
666 OSKextLog(theKext,
667 kOSKextLogErrorLevel |
668 kOSKextLogGeneralFlag,
669 "Can't allocate kernel memory to link %s.",
670 theKext->getIdentifierCString());
671 goto finish;
672 }
673
674 /* Create an OSData wrapper for the allocated buffer.
675 */
676 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
677 if (!linkBuffer) {
678 OSKextLog(theKext,
679 kOSKextLogErrorLevel |
680 kOSKextLogGeneralFlag,
681 "Can't allocate linked executable wrapper for %s.",
682 theKext->getIdentifierCString());
683 goto finish;
684 }
685 linkBuffer->setDeallocFunction(osdata_kext_free);
686 OSKextLog(theKext,
687 kOSKextLogProgressLevel |
688 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
689 "Allocated link buffer for kext %s at %p (%lu bytes).",
690 theKext->getIdentifierCString(),
691 (void *)result, (unsigned long)roundSize);
692
693 theKext->setLinkedExecutable(linkBuffer.get());
694
695 *flags = kKxldAllocateWritable;
696 success = true;
697
698 finish:
699 if (!success && result) {
700 kext_free(result, roundSize);
701 result = 0;
702 }
703
704 return (kxld_addr_t)result;
705 }
706
707 /*********************************************************************
708 *********************************************************************/
709 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)710 kxld_log_callback(
711 KXLDLogSubsystem subsystem,
712 KXLDLogLevel level,
713 const char * format,
714 va_list argList,
715 void * user_data)
716 {
717 OSKext *theKext = (OSKext *) user_data;
718 OSKextLogSpec logSpec = 0;
719
720 switch (subsystem) {
721 case kKxldLogLinking:
722 logSpec |= kOSKextLogLinkFlag;
723 break;
724 case kKxldLogPatching:
725 logSpec |= kOSKextLogPatchFlag;
726 break;
727 }
728
729 switch (level) {
730 case kKxldLogExplicit:
731 logSpec |= kOSKextLogExplicitLevel;
732 break;
733 case kKxldLogErr:
734 logSpec |= kOSKextLogErrorLevel;
735 break;
736 case kKxldLogWarn:
737 logSpec |= kOSKextLogWarningLevel;
738 break;
739 case kKxldLogBasic:
740 logSpec |= kOSKextLogProgressLevel;
741 break;
742 case kKxldLogDetail:
743 logSpec |= kOSKextLogDetailLevel;
744 break;
745 case kKxldLogDebug:
746 logSpec |= kOSKextLogDebugLevel;
747 break;
748 }
749
750 OSKextVLog(theKext, logSpec, format, argList);
751 }
752 #endif // CONFIG_KXLD
753
754 #if PRAGMA_MARK
755 #pragma mark IOStatistics defines
756 #endif
757
758 #if IOKITSTATS
759
760 #define notifyKextLoadObservers(kext, kmod_info) \
761 do { \
762 IOStatistics::onKextLoad(kext, kmod_info); \
763 } while (0)
764
765 #define notifyKextUnloadObservers(kext) \
766 do { \
767 IOStatistics::onKextUnload(kext); \
768 } while (0)
769
770 #define notifyAddClassObservers(kext, addedClass, flags) \
771 do { \
772 IOStatistics::onClassAdded(kext, addedClass); \
773 } while (0)
774
775 #define notifyRemoveClassObservers(kext, removedClass, flags) \
776 do { \
777 IOStatistics::onClassRemoved(kext, removedClass); \
778 } while (0)
779
780 #else
781
782 #define notifyKextLoadObservers(kext, kmod_info)
783 #define notifyKextUnloadObservers(kext)
784 #define notifyAddClassObservers(kext, addedClass, flags)
785 #define notifyRemoveClassObservers(kext, removedClass, flags)
786
787 #endif /* IOKITSTATS */
788
789 #if PRAGMA_MARK
790 #pragma mark Module Config (Startup & Shutdown)
791 #endif
792 /*********************************************************************
793 * Module Config (Class Definition & Class Methods)
794 *********************************************************************/
795 #define super OSObject
796 OSDefineMetaClassAndStructors(OSKext, OSObject)
797
798 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
799
800 OSDefineMetaClassAndStructors(OSDextStatistics, OSObject);
801
802 /*********************************************************************
803 *********************************************************************/
804 /**
805 * Allocate and intialize a fake/representative OSKext object for a statically
806 * loaded (by iBoot) binary (e.g., the XNU kernel itself).
807 *
808 * @param kmod_info Pointer to the kmod_info structure for the binary being
809 * setup. At least the "name" and "id" fields needs to already
810 * be set correctly.
811 *
812 * @return The allocated and initialized OSKext object.
813 */
814 /* static */
815 OSKext *
allocAndInitFakeKext(kmod_info_t * kmod_info)816 OSKext::allocAndInitFakeKext(kmod_info_t *kmod_info)
817 {
818 vm_offset_t load_address = 0;
819 const char *bundle_name = NULL;
820 bool macho_is_unslid = false;
821 bool set_custom_path = false;
822 const char *executable_fallback_name = NULL;
823
824 if (kmod_info->id == kOSKextKernelLoadTag) {
825 load_address = (vm_offset_t)&_mh_execute_header;
826 bundle_name = "mach_kernel";
827
828 /* The kernel Mach-O header is fixed up to slide all of its addresses. */
829 macho_is_unslid = false;
830
831 /**
832 * No path to the binary is set for the kernel in its OSKext object. The
833 * kernel binary is located in fixed directories depending on the OS.
834 */
835 set_custom_path = false;
836 executable_fallback_name = NULL;
837 #if CONFIG_SPTM
838 } else if (kmod_info->id == kOSKextSPTMLoadTag) {
839 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_SPTM];
840 bundle_name = "sptm";
841
842 /* The addresses in the SPTM Mach-O header are all unslid. */
843 macho_is_unslid = true;
844
845 set_custom_path = true;
846 executable_fallback_name = "sptm.no.binname.in.macho";
847 } else if (kmod_info->id == kOSKextTXMLoadTag) {
848 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_TXM];
849 bundle_name = "txm";
850
851 /* The addresses in the TXM Mach-O header are all unslid. */
852 macho_is_unslid = true;
853
854 set_custom_path = true;
855 executable_fallback_name = "txm.no.binname.in.macho";
856 #endif /* CONFIG_SPTM */
857 } else {
858 panic("%s: Unsupported kmod_info->id (%d)", __func__, kmod_info->id);
859 }
860
861 /* Set up an OSKext instance to represent the statically loaded binary. */
862 OSKext *fakeKext = new OSKext;
863 assert(fakeKext);
864 assert(load_address != 0);
865
866 /*
867 * The start address is always a slid address whereas the last VA returned
868 * by getlastaddr() might be unslid depending on the Mach-O. If the address
869 * coming from the Mach-O is unslid, then unslide the start address before
870 * computing the length of the executable.
871 */
872 size_t binaryLength = getlastaddr((kernel_mach_header_t*)load_address);
873 binaryLength -= (macho_is_unslid) ? ml_static_unslide(load_address) : load_address;
874 assert(binaryLength <= UINT_MAX);
875
876 /**
877 * The load address is always slid. That value will be unslid before being
878 * exposed to userspace.
879 */
880 OSSharedPtr<OSData> executable = OSData::withBytesNoCopy(
881 (void*)load_address, (unsigned int)binaryLength);
882 assert(executable);
883
884 fakeKext->loadTag = sNextLoadTag++;
885 fakeKext->bundleID = OSSymbol::withCString(kmod_info->name);
886
887 fakeKext->version = OSKextParseVersionString(osrelease);
888 fakeKext->compatibleVersion = fakeKext->version;
889 fakeKext->linkedExecutable = os::move(executable);
890 fakeKext->interfaceUUID = fakeKext->copyUUID();
891
892 fakeKext->flags.hasAllDependencies = 1;
893 fakeKext->flags.kernelComponent = 1;
894 fakeKext->flags.prelinked = 0;
895 fakeKext->flags.loaded = 1;
896 fakeKext->flags.started = 1;
897 fakeKext->flags.CPPInitialized = 0;
898 fakeKext->flags.jettisonLinkeditSeg = 0;
899 fakeKext->flags.unslidMachO = macho_is_unslid;
900
901 #if CONFIG_SPTM
902 if (set_custom_path) {
903 /* Only SPTM/TXM should have custom paths to their executables set. */
904 assert((kmod_info->id == kOSKextSPTMLoadTag) ||
905 (kmod_info->id == kOSKextTXMLoadTag));
906
907 /* All SPTM/TXM binaries are placed into the same path on internal systems. */
908 fakeKext->path = OSString::withCStringNoCopy("/usr/appleinternal/standalone/platform");
909
910 /**
911 * Each SPTM/TXM Mach-O should contain a __TEXT,__binname section which contains
912 * a character array representing the name of the Mach-O executable.
913 */
914 kernel_section_t *binname_sect =
915 getsectbynamefromheader((kernel_mach_header_t*)load_address, "__TEXT", "__binname");
916
917 if (binname_sect != NULL) {
918 const char *binname = (const char *)ml_static_slide(binname_sect->addr);
919 fakeKext->executableRelPath = OSString::withCStringNoCopy(binname);
920 } else {
921 fakeKext->executableRelPath = OSString::withCStringNoCopy(executable_fallback_name);
922 }
923 }
924 #endif /* CONFIG_SPTM */
925
926 fakeKext->kmod_info = kmod_info;
927 strlcpy(kmod_info->version, osrelease,
928 sizeof(kmod_info->version));
929 kmod_info->size = binaryLength;
930 assert(kmod_info->id == fakeKext->loadTag);
931
932 /*
933 * Con up an info dict, so we don't have to have special-case checking all
934 * over.
935 */
936 fakeKext->infoDict = OSDictionary::withCapacity(5);
937 assert(fakeKext->infoDict);
938 bool setResult = fakeKext->infoDict->setObject(kCFBundleIdentifierKey,
939 fakeKext->bundleID.get());
940 assert(setResult);
941 setResult = fakeKext->infoDict->setObject(kOSKernelResourceKey,
942 kOSBooleanTrue);
943 assert(setResult);
944
945 {
946 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
947 assert(scratchString);
948 setResult = fakeKext->infoDict->setObject(kCFBundleVersionKey,
949 scratchString.get());
950 assert(setResult);
951 }
952
953 {
954 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(bundle_name));
955 assert(scratchString);
956 setResult = fakeKext->infoDict->setObject(kCFBundleNameKey,
957 scratchString.get());
958 assert(setResult);
959 }
960
961 return fakeKext;
962 }
963
964 /* static */
965 void
initialize(void)966 OSKext::initialize(void)
967 {
968 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
969 IORegistryEntry * registryRoot = NULL;// do not release
970 OSSharedPtr<OSNumber> kernelCPUType;
971 OSSharedPtr<OSNumber> kernelCPUSubtype;
972 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
973 bool setResult = false;
974 uint64_t * timestamp = NULL;
975 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
976
977 /* This must be the first thing allocated. Everything else grabs this lock.
978 */
979 sKextLock = IORecursiveLockAlloc();
980 sKextInnerLock = IORecursiveLockAlloc();
981 sKextSummariesLock = IOLockAlloc();
982 sKextLoggingLock = IOLockAlloc();
983 assert(sKextLock);
984 assert(sKextInnerLock);
985 assert(sKextSummariesLock);
986 assert(sKextLoggingLock);
987
988 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
989 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
990 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
991 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
992 sKernelRequests = OSArray::withCapacity(0);
993 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
994 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
995 sRequestCallbackRecords = OSArray::withCapacity(0);
996 sDriverKitToUpgradeByID = OSDictionary::withCapacity(kOSKextTypicalUpgradeCount);
997
998 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
999 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
1000 sRequestCallbackRecords && sUnloadedPrelinkedKexts && sDriverKitToUpgradeByID);
1001
1002 /* Read the log flag boot-args and set the log flags.
1003 */
1004 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
1005 sBootArgLogFilterFound = true;
1006 sKernelLogFilter = bootLogFilter;
1007 // log this if any flags are set
1008 OSKextLog(/* kext */ NULL,
1009 kOSKextLogBasicLevel |
1010 kOSKextLogFlagsMask,
1011 "Kernel kext log filter 0x%x per kextlog boot arg.",
1012 (unsigned)sKernelLogFilter);
1013 }
1014
1015 #if !defined(__arm__) && !defined(__arm64__)
1016 /*
1017 * On our ARM targets, the kernelcache/boot kernel collection contains
1018 * the set of kexts required to boot, as specified by KCB. Safeboot is
1019 * either unsupported, or is supported by the bootloader only loading
1020 * the boot kernel collection; as a result OSKext has no role to play
1021 * in safeboot policy on ARM.
1022 */
1023 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
1024 sizeof(bootArgBuffer)) ? true : false;
1025 #endif /* defined(__arm__) && defined(__arm64__) */
1026
1027 if (sSafeBoot) {
1028 OSKextLog(/* kext */ NULL,
1029 kOSKextLogWarningLevel |
1030 kOSKextLogGeneralFlag,
1031 "SAFE BOOT DETECTED - "
1032 "only valid OSBundleRequired kexts will be loaded.");
1033 }
1034
1035 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
1036 #if CONFIG_DTRACE
1037 if (dtrace_keep_kernel_symbols()) {
1038 sKeepSymbols = true;
1039 }
1040 #endif /* CONFIG_DTRACE */
1041 #if KASAN_DYNAMIC_DENYLIST
1042 /* needed for function lookup */
1043 sKeepSymbols = true;
1044 #endif /* KASAN_DYNAMIC_DENYLIST */
1045
1046 /*
1047 * Should we panic when the SystemKC is not linked against the
1048 * BootKC that was loaded by the booter? By default: yes, if the
1049 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
1050 * on mis-match and instead just print an error and continue.
1051 */
1052 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
1053 sizeof(bootArgBuffer)) ? false : true;
1054
1055 /* Set up an OSKext instance to represent the kernel itself. */
1056 sKernelKext = allocAndInitFakeKext(&g_kernel_kmod_info);
1057 assert(sKernelKext);
1058
1059 #if CONFIG_SPTM
1060 /* Set up OSKext instances to represent the SPTM/TXM. */
1061 OSKext *SPTMKext = allocAndInitFakeKext(&g_sptm_kmod_info);
1062 OSKext *TXMKext = allocAndInitFakeKext(&g_txm_kmod_info);
1063 #endif
1064
1065 /* Add the kernel kext to the bookkeeping dictionaries. Note that
1066 * the kernel kext doesn't have a kmod_info struct. copyInfo()
1067 * gathers info from other places anyhow.
1068 */
1069 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
1070 assert(setResult);
1071 setResult = sLoadedKexts->setObject(sKernelKext);
1072 assert(setResult);
1073
1074 #if CONFIG_SPTM
1075 setResult = sKextsByID->setObject(SPTMKext->bundleID.get(), SPTMKext);
1076 assert(setResult);
1077 setResult = sLoadedKexts->setObject(SPTMKext);
1078 assert(setResult);
1079
1080 setResult = sKextsByID->setObject(TXMKext->bundleID.get(), TXMKext);
1081 assert(setResult);
1082 setResult = sLoadedKexts->setObject(TXMKext);
1083 assert(setResult);
1084 #endif /* CONFIG_SPTM */
1085
1086 // XXX: better way with OSSharedPtr?
1087 // sKernelKext remains a valid pointer even after the decref
1088 sKernelKext->release();
1089 #if CONFIG_SPTM
1090 SPTMKext->release();
1091 TXMKext->release();
1092 #endif /* CONFIG_SPTM */
1093
1094 registryRoot = IORegistryEntry::getRegistryRoot();
1095 kernelCPUType = OSNumber::withNumber(
1096 (long long unsigned int)_mh_execute_header.cputype,
1097 8 * sizeof(_mh_execute_header.cputype));
1098 kernelCPUSubtype = OSNumber::withNumber(
1099 (long long unsigned int)_mh_execute_header.cpusubtype,
1100 8 * sizeof(_mh_execute_header.cpusubtype));
1101 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
1102
1103 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
1104 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
1105
1106 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
1107 if (gBuiltinKmodsSectionInfo) {
1108 uint32_t count;
1109
1110 assert(gBuiltinKmodsSectionInfo->addr);
1111 assert(gBuiltinKmodsSectionInfo->size);
1112 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
1113 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
1114
1115 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
1116 assert(gBuiltinKmodsSectionStart);
1117 assert(gBuiltinKmodsSectionStart->addr);
1118 assert(gBuiltinKmodsSectionStart->size);
1119 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
1120 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
1121 // one extra pointer for the end of last kmod
1122 assert(count == (gBuiltinKmodsCount + 1));
1123
1124 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
1125 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
1126 }
1127
1128 // Don't track this object -- it's never released
1129 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
1130
1131 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
1132 *timestamp = 0;
1133 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
1134 *timestamp = 0;
1135 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
1136 *timestamp = 0;
1137
1138 OSKextLog(/* kext */ NULL,
1139 kOSKextLogProgressLevel |
1140 kOSKextLogGeneralFlag,
1141 "Kext system initialized.");
1142
1143 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
1144 #if CONFIG_SPTM
1145 notifyKextLoadObservers(SPTMKext, SPTMKext->kmod_info);
1146 notifyKextLoadObservers(TXMKext, TXMKext->kmod_info);
1147 #endif
1148
1149 return;
1150 }
1151
1152 /*********************************************************************
1153 * This is expected to be called exactly once, from exactly one thread
1154 * context, during kernel bootstrap.
1155 *********************************************************************/
1156 /* static */
1157 OSReturn
removeKextBootstrap(void)1158 OSKext::removeKextBootstrap(void)
1159 {
1160 OSReturn result = kOSReturnError;
1161
1162 const char * dt_kernel_header_name = "Kernel-__HEADER";
1163 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
1164 kernel_mach_header_t * dt_mach_header = NULL;
1165 int dt_mach_header_size = 0;
1166 struct symtab_command * dt_symtab = NULL;
1167 int dt_symtab_size = 0;
1168 int dt_result = 0;
1169
1170 kernel_segment_command_t * seg_kld = NULL;
1171 kernel_segment_command_t * seg_klddata = NULL;
1172 kernel_segment_command_t * seg_linkedit = NULL;
1173
1174 const char __unused * dt_segment_name = NULL;
1175 void __unused * segment_paddress = NULL;
1176 int __unused segment_size = 0;
1177
1178 OSKextLog(/* kext */ NULL,
1179 kOSKextLogProgressLevel |
1180 kOSKextLogGeneralFlag,
1181 "Jettisoning kext bootstrap segments.");
1182
1183 /*
1184 * keep the linkedit segment around when booted from a new MH_FILESET
1185 * KC because all the kexts shared a linkedit segment.
1186 */
1187 kc_format_t kc_format;
1188 if (!PE_get_primary_kc_format(&kc_format)) {
1189 OSKextLog(/* kext */ NULL,
1190 kOSKextLogErrorLevel |
1191 kOSKextLogGeneralFlag,
1192 "Unable to determine primary KC format");
1193 }
1194
1195 /*****
1196 * Dispose of unnecessary stuff that the booter didn't need to load.
1197 */
1198 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1199 (void **)&dt_mach_header, &dt_mach_header_size);
1200 if (dt_result == 0 && dt_mach_header) {
1201 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1202 round_page_32(dt_mach_header_size));
1203 }
1204 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1205 (void **)&dt_symtab, &dt_symtab_size);
1206 if (dt_result == 0 && dt_symtab) {
1207 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1208 round_page_32(dt_symtab_size));
1209 }
1210
1211 /*****
1212 * KLD & KLDDATA bootstrap segments.
1213 */
1214 // xxx - should rename KLD segment
1215 seg_kld = getsegbyname("__KLD");
1216 seg_klddata = getsegbyname("__KLDDATA");
1217 if (seg_klddata) {
1218 // __mod_term_func is part of __KLDDATA
1219 OSRuntimeUnloadCPPForSegment(seg_klddata);
1220 }
1221
1222 #if __arm__ || __arm64__
1223 /* Free the memory that was set up by iBoot.
1224 */
1225 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR) && !defined(KERNEL_INTEGRITY_PV_CTRR)
1226 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1227 * is covered by the contiguous rorgn.
1228 */
1229 dt_segment_name = "Kernel-__KLD";
1230 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1231 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1232 (int)segment_size); // calls ml_static_mfree
1233 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1234 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1235 #if !CONFIG_SPTM
1236 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1237 seg_kld->vmsize);
1238 #else
1239 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1240 #endif
1241 }
1242 #endif
1243 dt_segment_name = "Kernel-__KLDDATA";
1244 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1245 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1246 (int)segment_size); // calls ml_static_mfree
1247 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1248 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1249 #if !CONFIG_SPTM
1250 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1251 seg_klddata->vmsize);
1252 #else
1253 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1254 #endif
1255 }
1256 #elif __i386__ || __x86_64__
1257 /* On x86, use the mapping data from the segment load command to
1258 * unload KLD & KLDDATA directly.
1259 * This may invalidate any assumptions about "avail_start"
1260 * defining the lower bound for valid physical addresses.
1261 */
1262 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1263 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1264 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1265 }
1266 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1267 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1268 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1269 }
1270 #else
1271 #error arch
1272 #endif
1273
1274 /*****
1275 * Prelinked kernel's symtab (if there is one).
1276 */
1277 if (kc_format != KCFormatFileset) {
1278 kernel_section_t * sect;
1279 sect = getsectbyname("__PRELINK", "__symtab");
1280 if (sect && sect->addr && sect->size) {
1281 ml_static_mfree(sect->addr, sect->size);
1282 }
1283 }
1284
1285 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1286
1287 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1288 * pageable, unless keepsyms is set. To do that, we have to copy it from
1289 * its booter-allocated memory, free the booter memory, reallocate proper
1290 * managed memory, then copy the segment back in.
1291 *
1292 * NOTE: This optimization is not valid for fileset KCs because each
1293 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1294 * that points to one fileset-global LINKEDIT segment. This
1295 * optimization is also only valid for platforms that support vm
1296 * mapped kexts or mapped kext collections (pageable KCs)
1297 */
1298 #if VM_MAPPED_KEXTS
1299 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1300 kern_return_t mem_result;
1301 void *seg_copy = NULL;
1302 void *seg_data = NULL;
1303 vm_map_offset_t seg_offset = 0;
1304 vm_map_offset_t seg_copy_offset = 0;
1305 vm_map_size_t seg_length = 0;
1306
1307 seg_data = (void *) seg_linkedit->vmaddr;
1308 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1309 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1310
1311 /* Allocate space for the LINKEDIT copy.
1312 */
1313 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1314 seg_length, KMA_ZERO, VM_KERN_MEMORY_KEXT);
1315 if (mem_result != KERN_SUCCESS) {
1316 OSKextLog(/* kext */ NULL,
1317 kOSKextLogErrorLevel |
1318 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1319 "Can't copy __LINKEDIT segment for VM reassign.");
1320 return result;
1321 }
1322 seg_copy_offset = (vm_map_offset_t) seg_copy;
1323
1324 /* Copy it out.
1325 */
1326 memcpy(seg_copy, seg_data, seg_length);
1327
1328 /* Dump the booter memory.
1329 */
1330 ml_static_mfree(seg_offset, seg_length);
1331
1332 /* Set up the VM region.
1333 */
1334 mem_result = mach_vm_map_kernel(
1335 kernel_map,
1336 &seg_offset,
1337 seg_length, /* mask */ 0,
1338 VM_MAP_KERNEL_FLAGS_FIXED(.vmf_overwrite = true),
1339 (ipc_port_t)NULL,
1340 (vm_object_offset_t) 0,
1341 /* copy */ FALSE,
1342 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1343 /* max_protection */ VM_PROT_ALL,
1344 /* inheritance */ VM_INHERIT_DEFAULT);
1345 if ((mem_result != KERN_SUCCESS) ||
1346 (seg_offset != (vm_map_offset_t) seg_data)) {
1347 OSKextLog(/* kext */ NULL,
1348 kOSKextLogErrorLevel |
1349 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1350 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1351 seg_data, seg_length, mem_result);
1352 return result;
1353 }
1354
1355 /* And copy it back.
1356 */
1357 memcpy(seg_data, seg_copy, seg_length);
1358
1359 /* Free the copy.
1360 */
1361 kmem_free(kernel_map, seg_copy_offset, seg_length);
1362 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1363 /* Remove the linkedit segment of the Boot KC */
1364 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1365 OSKext::jettisonFileSetLinkeditSegment(mh);
1366 }
1367 #else // !VM_MAPPED_KEXTS
1368 /*****
1369 * Dump the LINKEDIT segment, unless keepsyms is set.
1370 */
1371 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1372 dt_segment_name = "Kernel-__LINKEDIT";
1373 if (0 == IODTGetLoaderInfo(dt_segment_name,
1374 &segment_paddress, &segment_size)) {
1375 #ifdef SECURE_KERNEL
1376 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1377 bzero((void*)vmaddr, segment_size);
1378 #endif
1379 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1380 (int)segment_size);
1381 }
1382 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1383 /* Remove the linkedit segment of the Boot KC */
1384 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1385 OSKext::jettisonFileSetLinkeditSegment(mh);
1386 } else {
1387 OSKextLog(/* kext */ NULL,
1388 kOSKextLogBasicLevel |
1389 kOSKextLogGeneralFlag,
1390 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1391 }
1392 #endif // VM_MAPPED_KEXTS
1393
1394 result = kOSReturnSuccess;
1395
1396 return result;
1397 }
1398
1399 #if CONFIG_KXLD
1400 /*********************************************************************
1401 *********************************************************************/
1402 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1403 OSKext::flushNonloadedKexts(
1404 Boolean flushPrelinkedKexts)
1405 {
1406 OSSharedPtr<OSSet> keepKexts;
1407
1408 /* TODO: make this more efficient with MH_FILESET kexts */
1409
1410 // Do not unload prelinked kexts on arm because the kernelcache is not
1411 // structured in a way that allows them to be unmapped
1412 #if !defined(__x86_64__)
1413 flushPrelinkedKexts = false;
1414 #endif /* defined(__x86_64__) */
1415
1416 IORecursiveLockLock(sKextLock);
1417
1418 OSKextLog(/* kext */ NULL,
1419 kOSKextLogProgressLevel |
1420 kOSKextLogKextBookkeepingFlag,
1421 "Flushing nonloaded kexts and other unused data.");
1422
1423 OSKext::considerDestroyingLinkContext();
1424
1425 /* If we aren't flushing unused prelinked kexts, we have to put them
1426 * aside while we flush everything else so make a container for them.
1427 */
1428 keepKexts = OSSet::withCapacity(16);
1429 if (!keepKexts) {
1430 goto finish;
1431 }
1432
1433 /* Set aside prelinked kexts (in-use or not) and break
1434 * any lingering inter-kext references for nonloaded kexts
1435 * so they have min. retain counts.
1436 */
1437 {
1438 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1439 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1440 if (!thisKext) {
1441 return false;
1442 }
1443 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1444 keepKexts->setObject(thisKext);
1445 } else if (!thisKext->declaresExecutable()) {
1446 /*
1447 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1448 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1449 * flushNonloadedKexts().
1450 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1451 */
1452 keepKexts->setObject(thisKext);
1453 } else if (thisKext->isInFileset()) {
1454 /* keep all kexts in the new MH_FILESET KC */
1455 keepKexts->setObject(thisKext);
1456 }
1457
1458 thisKext->flushDependencies(/* forceIfLoaded */ false);
1459 return false;
1460 });
1461 }
1462 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1463 */
1464 sKextsByID->flushCollection();
1465
1466 /* Now put the loaded kexts back into the ID dictionary.
1467 */
1468 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1469 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1470 if (!thisKext) {
1471 return false;
1472 }
1473 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1474 return false;
1475 });
1476
1477 /* Finally, put back the kept kexts if we saved any.
1478 */
1479 keepKexts->iterateObjects(^bool (OSObject * obj) {
1480 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1481 if (!thisKext) {
1482 return false;
1483 }
1484 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1485 return false;
1486 });
1487
1488 finish:
1489 IORecursiveLockUnlock(sKextLock);
1490 return;
1491 }
1492 #else /* !CONFIG_KXLD */
1493
1494 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1495 OSKext::flushNonloadedKexts(
1496 Boolean flushPrelinkedKexts __unused)
1497 {
1498 IORecursiveLockLock(sKextLock);
1499
1500 OSKextLog(/* kext */ NULL,
1501 kOSKextLogProgressLevel |
1502 kOSKextLogKextBookkeepingFlag,
1503 "Flushing dependency info for non-loaded kexts.");
1504
1505 /*
1506 * In a world where we don't dynamically link kexts, they all come
1507 * from a kext collection that's either in wired memory, or
1508 * wire-on-demand. We don't need to mess around with moving kexts in
1509 * and out of the sKextsByID array - they can all just stay there.
1510 * Here we just flush the dependency list for kexts that are not
1511 * loaded.
1512 */
1513 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1514 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1515 if (!thisKext) {
1516 return false;
1517 }
1518 thisKext->flushDependencies(/* forceIfLoaded */ false);
1519 return false;
1520 });
1521
1522 IORecursiveLockUnlock(sKextLock);
1523 return;
1524 }
1525
1526 #endif /* CONFIG_KXLD */
1527
1528 /*********************************************************************
1529 *********************************************************************/
1530 /* static */
1531 void
setIOKitDaemonActive(bool active)1532 OSKext::setIOKitDaemonActive(bool active)
1533 {
1534 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1535 IORecursiveLockLock(sKextLock);
1536 sIOKitDaemonActive = active;
1537 if (sKernelRequests->getCount()) {
1538 OSKext::pingIOKitDaemon();
1539 }
1540 IORecursiveLockUnlock(sKextLock);
1541
1542 return;
1543 }
1544
1545 /*********************************************************************
1546 * OSKextLib.cpp might need access to this someday but for now it's
1547 * private.
1548 *********************************************************************/
1549 extern "C" {
1550 extern void ipc_port_release_send(ipc_port_t);
1551 };
1552
1553 /* static */
1554 OSReturn
pingIOKitDaemon(void)1555 OSKext::pingIOKitDaemon(void)
1556 {
1557 OSReturn result = kOSReturnError;
1558 #if !NO_KEXTD
1559 mach_port_t kextd_port = IPC_PORT_NULL;
1560
1561 if (!sIOKitDaemonActive) {
1562 result = kOSKextReturnDisabled; // basically unavailable
1563 goto finish;
1564 }
1565
1566 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1567 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1568 OSKextLog(/* kext */ NULL,
1569 kOSKextLogErrorLevel |
1570 kOSKextLogIPCFlag,
1571 "Can't get " kIOKitDaemonName " port.");
1572 goto finish;
1573 }
1574
1575 result = kextd_ping(kextd_port);
1576 if (result != KERN_SUCCESS) {
1577 OSKextLog(/* kext */ NULL,
1578 kOSKextLogErrorLevel |
1579 kOSKextLogIPCFlag,
1580 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1581 goto finish;
1582 }
1583
1584 finish:
1585 if (IPC_PORT_VALID(kextd_port)) {
1586 ipc_port_release_send(kextd_port);
1587 }
1588 #endif
1589
1590 return result;
1591 }
1592
1593 /*********************************************************************
1594 *********************************************************************/
1595 /* static */
1596
1597 bool
driverkitEnabled(void)1598 OSKext::driverkitEnabled(void)
1599 {
1600 #if XNU_TARGET_OS_WATCH
1601 /*
1602 * Driverkit support is available on watchOS only if the device
1603 * tree has the "supports-driverkit" property in its "/product" node
1604 */
1605 DTEntry entry;
1606 void const *prop = NULL;
1607 unsigned int prop_size;
1608
1609 if (kSuccess != SecureDTLookupEntry(NULL, "/product", &entry)) {
1610 return false;
1611 }
1612 if (kSuccess != SecureDTGetProperty(entry, "supports-driverkit", &prop, &prop_size)) {
1613 return false;
1614 }
1615 #endif /* XNU_TARGET_OS_WATCH */
1616
1617 return true;
1618 }
1619
1620 /*********************************************************************
1621 *********************************************************************/
1622 /* static */
1623 bool
iokitDaemonAvailable(void)1624 OSKext::iokitDaemonAvailable(void)
1625 {
1626 #if !XNU_TARGET_OS_IOS && !XNU_TARGET_OS_OSX && !XNU_TARGET_OS_WATCH
1627 int notused;
1628 if (PE_parse_boot_argn("-restore", ¬used, sizeof(notused))) {
1629 return false;
1630 }
1631 #endif /* !XNU_TARGET_OS_IOS && !XNU_TARGET_OS_OSX && !XNU_TARGET_OS_WATCH */
1632 return driverkitEnabled();
1633 }
1634
1635 /*********************************************************************
1636 *********************************************************************/
1637 /* static */
1638 void
setDeferredLoadSucceeded(Boolean succeeded)1639 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1640 {
1641 IORecursiveLockLock(sKextLock);
1642 sDeferredLoadSucceeded = succeeded;
1643 IORecursiveLockUnlock(sKextLock);
1644
1645 return;
1646 }
1647
1648 /*********************************************************************
1649 * Called from IOSystemShutdownNotification.
1650 *********************************************************************/
1651 /* static */
1652 void
willShutdown(void)1653 OSKext::willShutdown(void)
1654 {
1655 #if !NO_KEXTD
1656 OSReturn checkResult = kOSReturnError;
1657 #endif
1658 OSSharedPtr<OSDictionary> exitRequest;
1659
1660 IORecursiveLockLock(sKextLock);
1661
1662 OSKext::setLoadEnabled(false);
1663 OSKext::setUnloadEnabled(false);
1664 OSKext::setAutounloadsEnabled(false);
1665 OSKext::setKernelRequestsEnabled(false);
1666
1667 #if defined(__x86_64__) || defined(__i386__)
1668 if (IOPMRootDomainGetWillShutdown()) {
1669 OSKext::freeKCFileSetcontrol();
1670 }
1671 #endif // (__x86_64__) || defined(__i386__)
1672
1673 #if !NO_KEXTD
1674 OSKextLog(/* kext */ NULL,
1675 kOSKextLogProgressLevel |
1676 kOSKextLogGeneralFlag,
1677 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1678
1679 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1680 exitRequest);
1681 if (checkResult != kOSReturnSuccess) {
1682 goto finish;
1683 }
1684 if (!sKernelRequests->setObject(exitRequest.get())) {
1685 goto finish;
1686 }
1687
1688 OSKext::pingIOKitDaemon();
1689
1690 finish:
1691 #endif
1692
1693 IORecursiveLockUnlock(sKextLock);
1694 return;
1695 }
1696
1697 void
setWillUserspaceReboot(void)1698 OSKext::setWillUserspaceReboot(void)
1699 {
1700 OSKext::willShutdown();
1701 IOService::setWillUserspaceReboot();
1702 gIOCatalogue->terminateDriversForUserspaceReboot();
1703 }
1704
1705 void
resetAfterUserspaceReboot(void)1706 OSKext::resetAfterUserspaceReboot(void)
1707 {
1708 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1709 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1710
1711 IORecursiveLockLock(sKextLock);
1712 gIOCatalogue->resetAfterUserspaceReboot();
1713 IOService::userSpaceDidReboot();
1714 OSKext::removeDaemonExitRequests();
1715 OSKext::setLoadEnabled(true);
1716 OSKext::setUnloadEnabled(true);
1717 OSKext::setAutounloadsEnabled(true);
1718 OSKext::setKernelRequestsEnabled(true);
1719 sOSKextWasResetAfterUserspaceReboot = true;
1720 IORecursiveLockUnlock(sKextLock);
1721 }
1722
1723 extern "C" int
OSKextIsInUserspaceReboot(void)1724 OSKextIsInUserspaceReboot(void)
1725 {
1726 return IOService::getWillUserspaceReboot();
1727 }
1728
1729 extern "C" void
OSKextResetAfterUserspaceReboot(void)1730 OSKextResetAfterUserspaceReboot(void)
1731 {
1732 OSKext::resetAfterUserspaceReboot();
1733 }
1734
1735 /*
1736 * Remove daemon exit requests from sKernelRequests
1737 *
1738 * If we sent a daemon exit request during a userspace reboot and launchd
1739 * killed the IOKit daemon before it was able to dequeue the exit request, the
1740 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1741 *
1742 * This removes exit requests so that this does not happen.
1743 */
1744 void
removeDaemonExitRequests(void)1745 OSKext::removeDaemonExitRequests(void)
1746 {
1747 OSDictionary * current = NULL;
1748 OSString * predicate = NULL;
1749 size_t index = 0;
1750 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1751
1752 while (index < sKernelRequests->getCount()) {
1753 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1754 if (current) {
1755 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1756 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1757 sKernelRequests->removeObject(index);
1758 continue;
1759 }
1760 }
1761 index++;
1762 }
1763 }
1764
1765 /*********************************************************************
1766 *********************************************************************/
1767 /* static */
1768 bool
getLoadEnabled(void)1769 OSKext::getLoadEnabled(void)
1770 {
1771 bool result;
1772
1773 IORecursiveLockLock(sKextLock);
1774 result = sLoadEnabled;
1775 IORecursiveLockUnlock(sKextLock);
1776 return result;
1777 }
1778
1779 /*********************************************************************
1780 *********************************************************************/
1781 /* static */
1782 bool
setLoadEnabled(bool flag)1783 OSKext::setLoadEnabled(bool flag)
1784 {
1785 bool result;
1786
1787 IORecursiveLockLock(sKextLock);
1788 result = sLoadEnabled;
1789 sLoadEnabled = (flag ? true : false);
1790
1791 if (sLoadEnabled != result) {
1792 OSKextLog(/* kext */ NULL,
1793 kOSKextLogBasicLevel |
1794 kOSKextLogLoadFlag,
1795 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1796 }
1797
1798 IORecursiveLockUnlock(sKextLock);
1799
1800 return result;
1801 }
1802
1803 /*********************************************************************
1804 *********************************************************************/
1805 /* static */
1806 bool
getUnloadEnabled(void)1807 OSKext::getUnloadEnabled(void)
1808 {
1809 bool result;
1810
1811 IORecursiveLockLock(sKextLock);
1812 result = sUnloadEnabled;
1813 IORecursiveLockUnlock(sKextLock);
1814 return result;
1815 }
1816
1817 /*********************************************************************
1818 *********************************************************************/
1819 /* static */
1820 bool
setUnloadEnabled(bool flag)1821 OSKext::setUnloadEnabled(bool flag)
1822 {
1823 bool result;
1824
1825 IORecursiveLockLock(sKextLock);
1826 result = sUnloadEnabled;
1827 sUnloadEnabled = (flag ? true : false);
1828 IORecursiveLockUnlock(sKextLock);
1829
1830 if (sUnloadEnabled != result) {
1831 OSKextLog(/* kext */ NULL,
1832 kOSKextLogBasicLevel |
1833 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1834 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1835 }
1836
1837 return result;
1838 }
1839
1840 /*********************************************************************
1841 * Do not call any function that takes sKextLock here!
1842 *********************************************************************/
1843 /* static */
1844 bool
getAutounloadEnabled(void)1845 OSKext::getAutounloadEnabled(void)
1846 {
1847 #if XNU_TARGET_OS_OSX
1848 bool result;
1849
1850 IORecursiveLockLock(sKextInnerLock);
1851 result = sAutounloadEnabled ? true : false;
1852 IORecursiveLockUnlock(sKextInnerLock);
1853 return result;
1854 #else
1855 return false;
1856 #endif /* XNU_TARGET_OS_OSX */
1857 }
1858
1859 /*********************************************************************
1860 * Do not call any function that takes sKextLock here!
1861 *********************************************************************/
1862 /* static */
1863 bool
setAutounloadsEnabled(bool flag)1864 OSKext::setAutounloadsEnabled(bool flag)
1865 {
1866 #if XNU_TARGET_OS_OSX
1867 bool result;
1868
1869 IORecursiveLockLock(sKextInnerLock);
1870
1871 result = sAutounloadEnabled;
1872 sAutounloadEnabled = (flag ? true : false);
1873 if (!sAutounloadEnabled && sUnloadCallout) {
1874 thread_call_cancel(sUnloadCallout);
1875 }
1876
1877 if (sAutounloadEnabled != result) {
1878 OSKextLog(/* kext */ NULL,
1879 kOSKextLogBasicLevel |
1880 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1881 "Kext autounloading now %sabled.",
1882 sAutounloadEnabled ? "en" : "dis");
1883 }
1884
1885 IORecursiveLockUnlock(sKextInnerLock);
1886
1887 return result;
1888 #else
1889 (void)flag;
1890 return false;
1891 #endif /* XNU_TARGET_OS_OSX */
1892 }
1893
1894 /*********************************************************************
1895 *********************************************************************/
1896 /* instance method operating on OSKext field */
1897 bool
setAutounloadEnabled(bool flag)1898 OSKext::setAutounloadEnabled(bool flag)
1899 {
1900 bool result = flags.autounloadEnabled ? true : false;
1901 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1902
1903 if (result != (flag ? true : false)) {
1904 OSKextLog(this,
1905 kOSKextLogProgressLevel |
1906 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1907 "Autounloading for kext %s now %sabled.",
1908 getIdentifierCString(),
1909 flags.autounloadEnabled ? "en" : "dis");
1910 }
1911 return result;
1912 }
1913
1914 /*********************************************************************
1915 *********************************************************************/
1916 /* static */
1917 bool
setKernelRequestsEnabled(bool flag)1918 OSKext::setKernelRequestsEnabled(bool flag)
1919 {
1920 bool result;
1921
1922 IORecursiveLockLock(sKextLock);
1923 result = sKernelRequestsEnabled;
1924 sKernelRequestsEnabled = flag ? true : false;
1925
1926 if (sKernelRequestsEnabled != result) {
1927 OSKextLog(/* kext */ NULL,
1928 kOSKextLogBasicLevel |
1929 kOSKextLogGeneralFlag,
1930 "Kernel requests now %sabled.",
1931 sKernelRequestsEnabled ? "en" : "dis");
1932 }
1933 IORecursiveLockUnlock(sKextLock);
1934 return result;
1935 }
1936
1937 /*********************************************************************
1938 *********************************************************************/
1939 /* static */
1940 bool
getKernelRequestsEnabled(void)1941 OSKext::getKernelRequestsEnabled(void)
1942 {
1943 bool result;
1944
1945 IORecursiveLockLock(sKextLock);
1946 result = sKernelRequestsEnabled;
1947 IORecursiveLockUnlock(sKextLock);
1948 return result;
1949 }
1950
1951 static bool
segmentIsMutable(kernel_segment_command_t * seg)1952 segmentIsMutable(kernel_segment_command_t *seg)
1953 {
1954 /* Mutable segments have to have VM_PROT_WRITE */
1955 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1956 return false;
1957 }
1958 /* Exclude the __DATA_CONST segment */
1959 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1960 return false;
1961 }
1962 /* Exclude __LINKEDIT */
1963 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1964 return false;
1965 }
1966 return true;
1967 }
1968
1969 #if PRAGMA_MARK
1970 #pragma mark Kext Life Cycle
1971 #endif
1972 /*********************************************************************
1973 *********************************************************************/
1974 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1975 OSKext::withPrelinkedInfoDict(
1976 OSDictionary * anInfoDict,
1977 bool doCoalescedSlides,
1978 kc_kind_t type)
1979 {
1980 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1981
1982 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1983 return NULL;
1984 }
1985
1986 return newKext;
1987 }
1988
1989 OSData *
parseDextUniqueID(OSDictionary * anInfoDict,const char * dextIDCS)1990 OSKext::parseDextUniqueID(
1991 OSDictionary * anInfoDict,
1992 const char *dextIDCS)
1993 {
1994 OSData *ret = NULL;
1995 OSData *data_duid = OSDynamicCast(OSData, anInfoDict->getObject(kOSBundleDextUniqueIdentifierKey));
1996 if (data_duid != NULL) {
1997 if (data_duid->getLength() > KOSBundleDextUniqueIdentifierMaxLength) {
1998 OSKextLog(NULL,
1999 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2000 "Dext %s DextUniqueIdentifier too long.",
2001 dextIDCS);
2002 } else {
2003 /*
2004 * If the DextUniqueID exists it should be
2005 * present also into the personalities.
2006 */
2007 setDextUniqueIDInPersonalities(anInfoDict, data_duid);
2008 ret = data_duid;
2009 }
2010 } else {
2011 OSKextLog(NULL,
2012 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2013 "Dext %s does not have a DextUniqueIdentifier",
2014 dextIDCS);
2015 }
2016 return ret;
2017 }
2018
2019 void
setDextUniqueIDInPersonalities(OSDictionary * anInfoDict,OSData * dextUniqueID)2020 OSKext::setDextUniqueIDInPersonalities(
2021 OSDictionary * anInfoDict,
2022 OSData * dextUniqueID)
2023 {
2024 OSDictionary * dextPersonalities = NULL;
2025 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
2026 OSString * personalityName = NULL;
2027
2028 dextPersonalities = OSDynamicCast(OSDictionary,
2029 anInfoDict->getObject(kIOKitPersonalitiesKey));
2030 if (!dextPersonalities || !dextPersonalities->getCount()) {
2031 return;
2032 }
2033
2034 personalitiesIterator =
2035 OSCollectionIterator::withCollection(dextPersonalities);
2036 if (!personalitiesIterator) {
2037 return;
2038 }
2039 while ((personalityName = OSDynamicCast(OSString,
2040 personalitiesIterator->getNextObject()))) {
2041 OSDictionary * personality = OSDynamicCast(OSDictionary,
2042 dextPersonalities->getObject(personalityName));
2043 if (personality) {
2044 OSObject *duid = personality->getObject(kOSBundleDextUniqueIdentifierKey);
2045 if (duid == NULL) {
2046 personality->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID);
2047 }
2048 }
2049 }
2050 }
2051 /*********************************************************************
2052 *********************************************************************/
2053 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)2054 OSKext::initWithPrelinkedInfoDict(
2055 OSDictionary * anInfoDict,
2056 bool doCoalescedSlides,
2057 kc_kind_t type)
2058 {
2059 bool result = false;
2060 OSString * kextPath = NULL; // do not release
2061 OSNumber * addressNum = NULL; // reused; do not release
2062 OSNumber * lengthNum = NULL; // reused; do not release
2063 OSBoolean * scratchBool = NULL; // do not release
2064 void * data = NULL; // do not free
2065 void * srcData = NULL; // do not free
2066 OSSharedPtr<OSData> prelinkedExecutable;
2067 uint32_t length = 0; // reused
2068 uintptr_t kext_slide = PE_get_kc_slide(type);
2069 bool shouldSaveSegments = false;
2070 kc_format format = KCFormatUnknown;
2071
2072 if (!super::init()) {
2073 goto finish;
2074 }
2075
2076 /* Get the path. Don't look for an arch-specific path property.
2077 */
2078 kextPath = OSDynamicCast(OSString,
2079 anInfoDict->getObject(kPrelinkBundlePathKey));
2080
2081 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2082 goto finish;
2083 }
2084
2085 #if KASLR_KEXT_DEBUG
2086 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
2087 #endif
2088
2089 /* Also get the executable's bundle-relative path if present.
2090 * Don't look for an arch-specific path property.
2091 */
2092 executableRelPath.reset(OSDynamicCast(OSString,
2093 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
2094 userExecutableRelPath.reset(OSDynamicCast(OSString,
2095 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2096
2097 /* Don't need the paths to be in the info dictionary any more.
2098 */
2099 anInfoDict->removeObject(kPrelinkBundlePathKey);
2100 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
2101
2102 scratchBool = OSDynamicCast(OSBoolean,
2103 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2104 if (scratchBool == kOSBooleanTrue) {
2105 flags.requireExplicitLoad = 1;
2106 }
2107
2108 /* Create an OSData wrapper around the linked executable.
2109 */
2110 addressNum = OSDynamicCast(OSNumber,
2111 anInfoDict->getObject(kPrelinkExecutableLoadKey));
2112 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
2113 lengthNum = OSDynamicCast(OSNumber,
2114 anInfoDict->getObject(kPrelinkExecutableSizeKey));
2115 if (!lengthNum) {
2116 OSKextLog(this,
2117 kOSKextLogErrorLevel |
2118 kOSKextLogArchiveFlag,
2119 "Kext %s can't find prelinked kext executable size.",
2120 getIdentifierCString());
2121 return result;
2122 }
2123
2124 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2125 length = (uint32_t) (lengthNum->unsigned32BitValue());
2126
2127 #if KASLR_KEXT_DEBUG
2128 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
2129 (unsigned long)ml_static_unslide((vm_offset_t)data),
2130 (unsigned long)data,
2131 length);
2132 #endif
2133
2134 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
2135 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
2136
2137 /* If the kext's load address differs from its source address, allocate
2138 * space in the kext map at the load address and copy the kext over.
2139 */
2140 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
2141 if (addressNum) {
2142 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2143
2144 #if KASLR_KEXT_DEBUG
2145 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
2146 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
2147 (unsigned long)srcData);
2148 #endif
2149
2150 if (data != srcData) {
2151 #if __LP64__
2152 kern_return_t alloc_result;
2153
2154 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
2155 if (alloc_result != KERN_SUCCESS) {
2156 OSKextLog(this,
2157 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2158 "Failed to allocate space for prelinked kext %s.",
2159 getIdentifierCString());
2160 goto finish;
2161 }
2162 memcpy(data, srcData, length);
2163 #else
2164 OSKextLog(this,
2165 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2166 "Error: prelinked kext %s - source and load addresses "
2167 "differ on ILP32 architecture.",
2168 getIdentifierCString());
2169 goto finish;
2170 #endif /* __LP64__ */
2171 }
2172
2173 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
2174 }
2175
2176 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
2177 if (!prelinkedExecutable) {
2178 OSKextLog(this,
2179 kOSKextLogErrorLevel |
2180 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
2181 "Kext %s failed to create executable wrapper.",
2182 getIdentifierCString());
2183 goto finish;
2184 }
2185
2186 /*
2187 * Fileset KCs are mapped as a whole by iBoot.
2188 * Individual kext executables should not be unmapped
2189 * by xnu.
2190 * Doing so may result in panics like rdar://85419651
2191 */
2192 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
2193 prelinkedExecutable->setDeallocFunction(NULL);
2194 } else { // Not from a Fileset KC
2195 #if VM_MAPPED_KEXTS
2196 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
2197 #else
2198 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
2199 #endif
2200 }
2201 setLinkedExecutable(prelinkedExecutable.get());
2202 addressNum = OSDynamicCast(OSNumber,
2203 anInfoDict->getObject(kPrelinkKmodInfoKey));
2204 if (!addressNum) {
2205 OSKextLog(this,
2206 kOSKextLogErrorLevel |
2207 kOSKextLogArchiveFlag,
2208 "Kext %s can't find prelinked kext kmod_info address.",
2209 getIdentifierCString());
2210 goto finish;
2211 }
2212
2213 if (addressNum->unsigned64BitValue() != 0) {
2214 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2215 if (kmod_info->address) {
2216 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
2217 } else {
2218 kmod_info->address = (uintptr_t)data;
2219 kmod_info->size = length;
2220 }
2221 #if KASLR_KEXT_DEBUG
2222 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
2223 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
2224 (unsigned long)kmod_info);
2225 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
2226 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
2227 (unsigned long)kmod_info->address);
2228 #endif
2229 }
2230
2231 anInfoDict->removeObject(kPrelinkKmodInfoKey);
2232 }
2233
2234 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
2235 uintptr_t builtinTextStart;
2236 uintptr_t builtinTextEnd;
2237
2238 flags.builtin = true;
2239 builtinKmodIdx = addressNum->unsigned32BitValue();
2240 assert(builtinKmodIdx < gBuiltinKmodsCount);
2241
2242 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
2243 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
2244
2245 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
2246 kmod_info->address = builtinTextStart;
2247 kmod_info->size = builtinTextEnd - builtinTextStart;
2248 }
2249
2250 /* If the plist has a UUID for an interface, save that off.
2251 */
2252 if (isInterface()) {
2253 interfaceUUID.reset(OSDynamicCast(OSData,
2254 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
2255 if (interfaceUUID) {
2256 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
2257 }
2258 }
2259
2260 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
2261 if (!result) {
2262 goto finish;
2263 }
2264
2265 kc_type = type;
2266 /* Exclude builtin and codeless kexts */
2267 if (prelinkedExecutable && kmod_info) {
2268 switch (kc_type) {
2269 case KCKindPrimary:
2270 shouldSaveSegments = (
2271 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
2272 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
2273 if (shouldSaveSegments) {
2274 flags.resetSegmentsFromImmutableCopy = 1;
2275 } else {
2276 flags.unloadUnsupported = 1;
2277 }
2278 break;
2279 case KCKindPageable:
2280 flags.resetSegmentsFromVnode = 1;
2281 break;
2282 case KCKindAuxiliary:
2283 if (!pageableKCloaded) {
2284 flags.resetSegmentsFromImmutableCopy = 1;
2285 } else if (resetAuxKCSegmentOnUnload) {
2286 flags.resetSegmentsFromVnode = 1;
2287 } else {
2288 flags.unloadUnsupported = 1;
2289 }
2290 break;
2291 default:
2292 break;
2293 }
2294 }
2295
2296 if (flags.resetSegmentsFromImmutableCopy) {
2297 /* Save a pristine copy of the mutable segments */
2298 kernel_segment_command_t *seg = NULL;
2299 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
2300
2301 savedMutableSegments = OSArray::withCapacity(0);
2302
2303 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
2304 if (!segmentIsMutable(seg)) {
2305 continue;
2306 }
2307 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
2308 uint64_t vmsize = seg->vmsize;
2309 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2310 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2311 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
2312 if (!savedSegment) {
2313 OSKextLog(this,
2314 kOSKextLogErrorLevel |
2315 kOSKextLogGeneralFlag,
2316 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2317 result = false;
2318 goto finish;
2319 }
2320 savedMutableSegments->setObject(savedSegment);
2321 }
2322 }
2323
2324 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2325 /*
2326 * set VM protections now, wire pages for the old style Aux KC now,
2327 * wire pages for the rest of the KC types at load time.
2328 */
2329 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2330 if (!result) {
2331 goto finish;
2332 }
2333 }
2334
2335 flags.prelinked = true;
2336
2337 if (isDriverKit()) {
2338 dextStatistics = OSDextStatistics::create();
2339 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2340 dextLaunchedCount = 0;
2341 }
2342
2343 /* If we created a kext from prelink info,
2344 * we must be booting from a prelinked kernel.
2345 */
2346 sPrelinkBoot = true;
2347
2348 result = (registerIdentifier() == kOSKextInitialized);
2349 finish:
2350 return result;
2351 }
2352
2353 /*********************************************************************
2354 *********************************************************************/
2355 /* static */
2356 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict,OSKextInitResult * result)2357 OSKext::withCodelessInfo(OSDictionary * anInfoDict, OSKextInitResult *result)
2358 {
2359 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2360 if (!newKext) {
2361 return NULL;
2362 }
2363
2364 OSKextInitResult ret = newKext->initWithCodelessInfo(anInfoDict);
2365 if (result != NULL) {
2366 *result = ret;
2367 }
2368 if (ret != kOSKextInitialized) {
2369 return NULL;
2370 }
2371
2372 return newKext;
2373 }
2374
2375 /*********************************************************************
2376 *********************************************************************/
2377 OSKextInitResult
initWithCodelessInfo(OSDictionary * anInfoDict)2378 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2379 {
2380 OSKextInitResult result = kOSKextInitFailure;
2381 OSString * kextPath = NULL; // do not release
2382 OSBoolean * scratchBool = NULL; // do not release
2383
2384 if (anInfoDict == NULL || !super::init()) {
2385 goto finish;
2386 }
2387
2388 /*
2389 * Get the path. Don't look for an arch-specific path property.
2390 */
2391 kextPath = OSDynamicCast(OSString,
2392 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2393 if (!kextPath) {
2394 OSKextLog(NULL,
2395 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2396 "Requested codeless kext dictionary does not contain the '%s' key",
2397 kKextRequestArgumentCodelessInfoBundlePathKey);
2398 goto finish;
2399 }
2400
2401 uniquePersonalityProperties(anInfoDict);
2402
2403 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2404 goto finish;
2405 }
2406
2407 /*
2408 * This path is meant to initialize codeless kexts only. Refuse
2409 * anything that looks like it has an executable and/or declares
2410 * itself as a kernel component.
2411 */
2412 if (declaresExecutable() || isKernelComponent()) {
2413 OSKextLog(NULL,
2414 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2415 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2416 getIdentifierCString());
2417 goto finish;
2418 }
2419
2420 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2421 boolean_t updated = updateExcludeList(infoDict.get());
2422 if (updated) {
2423 OSKextLog(this,
2424 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2425 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2426 }
2427 }
2428
2429 kc_type = KCKindNone;
2430
2431 scratchBool = OSDynamicCast(OSBoolean,
2432 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2433 if (scratchBool == kOSBooleanTrue) {
2434 flags.requireExplicitLoad = 1;
2435 }
2436
2437 /* Also get the executable's bundle-relative path if present.
2438 * Don't look for an arch-specific path property.
2439 */
2440 userExecutableRelPath.reset(OSDynamicCast(OSString,
2441 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2442
2443 /* remove unnecessary paths from the info dict */
2444 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2445
2446 if (isDriverKit()) {
2447 dextStatistics = OSDextStatistics::create();
2448 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2449 dextLaunchedCount = 0;
2450 }
2451
2452 result = registerIdentifier();
2453
2454 finish:
2455 return result;
2456 }
2457
2458 /*********************************************************************
2459 *********************************************************************/
2460 /* static */
2461 void
setAllVMAttributes(void)2462 OSKext::setAllVMAttributes(void)
2463 {
2464 OSSharedPtr<OSCollectionIterator> kextIterator;
2465 const OSSymbol * thisID = NULL; // do not release
2466
2467 IORecursiveLockLock(sKextLock);
2468
2469 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2470 if (!kextIterator) {
2471 goto finish;
2472 }
2473
2474 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2475 OSKext * thisKext; // do not release
2476
2477 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2478 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2479 continue;
2480 }
2481
2482 if (!thisKext->flags.resetSegmentsFromVnode) {
2483 /*
2484 * set VM protections now, wire pages for the old style Aux KC now,
2485 * wire pages for the rest of the KC types at load time.
2486 */
2487 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2488 }
2489 }
2490
2491 finish:
2492 IORecursiveLockUnlock(sKextLock);
2493
2494 return;
2495 }
2496
2497 /*********************************************************************
2498 *********************************************************************/
2499 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2500 OSKext::withBooterData(
2501 OSString * deviceTreeName,
2502 OSData * booterData)
2503 {
2504 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2505
2506 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2507 return NULL;
2508 }
2509
2510 return newKext;
2511 }
2512
2513 /*********************************************************************
2514 *********************************************************************/
2515 typedef struct _BooterKextFileInfo {
2516 uint32_t infoDictPhysAddr;
2517 uint32_t infoDictLength;
2518 uint32_t executablePhysAddr;
2519 uint32_t executableLength;
2520 uint32_t bundlePathPhysAddr;
2521 uint32_t bundlePathLength;
2522 } _BooterKextFileInfo;
2523
2524 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2525 OSKext::initWithBooterData(
2526 OSString * deviceTreeName,
2527 OSData * booterData)
2528 {
2529 bool result = false;
2530 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2531 char * infoDictAddr = NULL; // do not free
2532 void * executableAddr = NULL; // do not free
2533 char * bundlePathAddr = NULL; // do not free
2534
2535 OSDictionary * theInfoDict = NULL; // do not release
2536 OSSharedPtr<OSObject> parsedXML;
2537 OSSharedPtr<OSString> kextPath;
2538
2539 OSSharedPtr<OSString> errorString;
2540 OSSharedPtr<OSData> executable;
2541
2542 if (!super::init()) {
2543 goto finish;
2544 }
2545
2546 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2547 if (!kextFileInfo) {
2548 OSKextLog(this,
2549 kOSKextLogErrorLevel |
2550 kOSKextLogGeneralFlag,
2551 "No booter-provided data for kext device tree entry %s.",
2552 deviceTreeName->getCStringNoCopy());
2553 goto finish;
2554 }
2555
2556 /* The info plist must exist or we can't read the kext.
2557 */
2558 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2559 OSKextLog(this,
2560 kOSKextLogErrorLevel |
2561 kOSKextLogGeneralFlag,
2562 "No kext info dictionary for booter device tree entry %s.",
2563 deviceTreeName->getCStringNoCopy());
2564 goto finish;
2565 }
2566
2567 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2568 if (!infoDictAddr) {
2569 OSKextLog(this,
2570 kOSKextLogErrorLevel |
2571 kOSKextLogGeneralFlag,
2572 "Can't translate physical address 0x%x of kext info dictionary "
2573 "for device tree entry %s.",
2574 (int)kextFileInfo->infoDictPhysAddr,
2575 deviceTreeName->getCStringNoCopy());
2576 goto finish;
2577 }
2578
2579 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2580 if (parsedXML) {
2581 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2582 }
2583 if (!theInfoDict) {
2584 const char * errorCString = "(unknown error)";
2585
2586 if (errorString && errorString->getCStringNoCopy()) {
2587 errorCString = errorString->getCStringNoCopy();
2588 } else if (parsedXML) {
2589 errorCString = "not a dictionary";
2590 }
2591 OSKextLog(this,
2592 kOSKextLogErrorLevel |
2593 kOSKextLogGeneralFlag,
2594 "Error unserializing info dictionary for device tree entry %s: %s.",
2595 deviceTreeName->getCStringNoCopy(), errorCString);
2596 goto finish;
2597 }
2598
2599 /* A bundle path is not mandatory.
2600 */
2601 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2602 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2603 if (!bundlePathAddr) {
2604 OSKextLog(this,
2605 kOSKextLogErrorLevel |
2606 kOSKextLogGeneralFlag,
2607 "Can't translate physical address 0x%x of kext bundle path "
2608 "for device tree entry %s.",
2609 (int)kextFileInfo->bundlePathPhysAddr,
2610 deviceTreeName->getCStringNoCopy());
2611 goto finish;
2612 }
2613 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2614
2615 kextPath = OSString::withCString(bundlePathAddr);
2616 if (!kextPath) {
2617 OSKextLog(this,
2618 kOSKextLogErrorLevel |
2619 kOSKextLogGeneralFlag,
2620 "Failed to create wrapper for device tree entry %s kext path %s.",
2621 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2622 goto finish;
2623 }
2624 }
2625
2626 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2627 goto finish;
2628 }
2629
2630 /* An executable is not mandatory.
2631 */
2632 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2633 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2634 if (!executableAddr) {
2635 OSKextLog(this,
2636 kOSKextLogErrorLevel |
2637 kOSKextLogGeneralFlag,
2638 "Can't translate physical address 0x%x of kext executable "
2639 "for device tree entry %s.",
2640 (int)kextFileInfo->executablePhysAddr,
2641 deviceTreeName->getCStringNoCopy());
2642 goto finish;
2643 }
2644
2645 executable = OSData::withBytesNoCopy(executableAddr,
2646 kextFileInfo->executableLength);
2647 if (!executable) {
2648 OSKextLog(this,
2649 kOSKextLogErrorLevel |
2650 kOSKextLogGeneralFlag,
2651 "Failed to create executable wrapper for device tree entry %s.",
2652 deviceTreeName->getCStringNoCopy());
2653 goto finish;
2654 }
2655
2656 /* A kext with an executable needs to retain the whole booterData
2657 * object to keep the executable in memory.
2658 */
2659 if (!setExecutable(executable.get(), booterData)) {
2660 OSKextLog(this,
2661 kOSKextLogErrorLevel |
2662 kOSKextLogGeneralFlag,
2663 "Failed to set kext executable for device tree entry %s.",
2664 deviceTreeName->getCStringNoCopy());
2665 goto finish;
2666 }
2667 }
2668
2669 if (isDriverKit()) {
2670 dextStatistics = OSDextStatistics::create();
2671 dextUniqueID.reset(parseDextUniqueID(theInfoDict, getIdentifierCString()), OSRetain);
2672 dextLaunchedCount = 0;
2673 }
2674
2675 result = (registerIdentifier() == kOSKextInitialized);
2676
2677 finish:
2678 return result;
2679 }
2680
2681 /*********************************************************************
2682 *********************************************************************/
2683 OSKextInitResult
registerIdentifier(void)2684 OSKext::registerIdentifier(void)
2685 {
2686 OSKextInitResult result = kOSKextInitFailure;
2687 OSKext * existingKext = NULL; // do not release
2688 bool existingIsLoaded = false;
2689 bool existingIsPrelinked = false;
2690 bool existingIsCodeless = false;
2691 bool existingIsDext = false;
2692 OSKextVersion newVersion = -1;
2693 OSKextVersion existingVersion = -1;
2694 char newVersionCString[kOSKextVersionMaxLength];
2695 char existingVersionCString[kOSKextVersionMaxLength];
2696 OSSharedPtr<OSData> newUUID;
2697 OSSharedPtr<OSData> existingUUID;
2698 const char *newDextUniqueIDCString = NULL;
2699 const char *existingDextUniqueIDCString = NULL;
2700 unsigned int newDextUniqueIDCStringSize = 0;
2701 unsigned int existingDextUniqueIDCStringSize = 0;
2702
2703 IORecursiveLockLock(sKextLock);
2704
2705 /* Get the new kext's version for checks & log messages.
2706 */
2707 newVersion = getVersion();
2708 OSKextVersionGetString(newVersion, newVersionCString,
2709 kOSKextVersionMaxLength);
2710
2711 /* If we don't have an existing kext with this identifier,
2712 * just record the new kext and we're done!
2713 */
2714 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2715 if (!existingKext) {
2716 sKextsByID->setObject(bundleID.get(), this);
2717 result = kOSKextInitialized;
2718 goto finish;
2719 }
2720
2721 /* Get the existing kext's version for checks & log messages.
2722 */
2723 existingVersion = existingKext->getVersion();
2724 OSKextVersionGetString(existingVersion,
2725 existingVersionCString, kOSKextVersionMaxLength);
2726
2727 existingIsLoaded = existingKext->isLoaded();
2728 existingIsPrelinked = existingKext->isPrelinked();
2729 existingIsDext = existingKext->isDriverKit();
2730 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2731
2732 /*
2733 * Check if we are trying to upgrade a dext
2734 * with another dext.
2735 */
2736 if (isDriverKit() && existingIsDext) {
2737 OSData *newDextUID = getDextUniqueID();
2738 if (!newDextUID) {
2739 OSKextLog(this,
2740 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2741 "New dext %s, v%s requested does not have a unique dext identifier\n",
2742 getIdentifierCString(), newVersionCString);
2743 goto finish;
2744 }
2745 newDextUniqueIDCString = getDextUniqueIDCString(newDextUID, &newDextUniqueIDCStringSize);
2746 assert(newDextUniqueIDCString != NULL);
2747
2748 OSData *existingDextUID = existingKext->getDextUniqueID();
2749 if (!existingDextUID) {
2750 OSKextLog(this,
2751 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2752 "Found a dext %s, v%s: with no unique dext identifier\n",
2753 existingKext->getIdentifierCString(), existingVersionCString);
2754 goto finish;
2755 }
2756 existingDextUniqueIDCString = getDextUniqueIDCString(existingDextUID, &existingDextUniqueIDCStringSize);
2757 assert(existingDextUniqueIDCString != NULL);
2758
2759 /*
2760 * We might get multiple requests to save the same dext.
2761 * Check if we already have saved it or if this is an upgrade
2762 * for a dext with the same BundleID.
2763 * Dexts are uniquely identified by DextUniqueID, if a new DextUniqueID
2764 * is requested for a BundleID we are going to upgrade to the newest
2765 * received irrespective from the dext version.
2766 */
2767 if (newDextUID->isEqualTo(existingDextUID) && existingKext->flags.dextToReplace == 0) {
2768 OSKextLog(this,
2769 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2770 "Refusing new dext %s, v%s:"
2771 "a dext v %s with the same unique dext identifier (%s) already exists\n",
2772 getIdentifierCString(), newVersionCString,
2773 existingVersionCString, newDextUniqueIDCString);
2774 result = kOSKextAlreadyExist;
2775 goto finish;
2776 }
2777
2778 bool upgraded = upgradeDext(existingKext, this);
2779 if (upgraded) {
2780 /* If the dext was upgraded existingKext might have been deallocated */
2781 existingKext = NULL;
2782 OSKextLog(this,
2783 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2784 "Dext %s, v%s , unique dext identifier %s "
2785 "Upgraded to v%s, unique dext identifier %s \n",
2786 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2787 newVersionCString, newDextUniqueIDCString);
2788 result = kOSKextInitialized;
2789 } else {
2790 OSKextLog(this,
2791 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2792 "Upgrade delayed for %s v%s, unique dext identifier %s "
2793 "with v%s, unique dext identifier %s.\n",
2794 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2795 newVersionCString, newDextUniqueIDCString);
2796 result = kOSKextAlreadyExist;
2797 }
2798
2799 goto finish;
2800 }
2801
2802 /* If we have a non-codeless kext with this identifier that's already
2803 * loaded/prelinked, we can't use the new one, but let's be really
2804 * thorough and check how the two are related for a precise diagnostic
2805 * log message.
2806 *
2807 * This check is valid for kexts that declare an executable and for
2808 * dexts, but not for codeless kexts - we can just replace those.
2809 */
2810 if ((!existingIsCodeless || existingIsDext) &&
2811 (existingIsLoaded || existingIsPrelinked)) {
2812 bool sameVersion = (newVersion == existingVersion);
2813 bool sameExecutable = true; // assume true unless we have UUIDs
2814
2815 /* Only get the UUID if the existing kext is loaded. Doing so
2816 * might have to uncompress an mkext executable and we shouldn't
2817 * take that hit when neither kext is loaded.
2818 *
2819 * Note: there is no decompression that happens when all kexts
2820 * are loaded from kext collecitons.
2821 */
2822 newUUID = copyUUID();
2823 existingUUID = existingKext->copyUUID();
2824
2825 if (existingIsDext && !isDriverKit()) {
2826 OSKextLog(this,
2827 kOSKextLogWarningLevel |
2828 kOSKextLogKextBookkeepingFlag,
2829 "Notice - new kext %s, v%s matches a %s dext"
2830 "with the same bundle ID, v%s.",
2831 getIdentifierCString(), newVersionCString,
2832 (existingIsLoaded ? "loaded" : "prelinked"),
2833 existingVersionCString);
2834 goto finish;
2835 }
2836
2837 /* I'm entirely too paranoid about checking equivalence of executables,
2838 * but I remember nasty problems with it in the past.
2839 *
2840 * - If we have UUIDs for both kexts, compare them.
2841 * - If only one kext has a UUID, they're definitely different.
2842 */
2843 if (newUUID && existingUUID) {
2844 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2845 } else if (newUUID || existingUUID) {
2846 sameExecutable = false;
2847 }
2848
2849 if (!newUUID && !existingUUID) {
2850 /* If there are no UUIDs, we can't really tell that the executables
2851 * are *different* without a lot of work; the loaded kext's
2852 * unrelocated executable is no longer around (and we never had it
2853 * in-kernel for a prelinked kext). We certainly don't want to do
2854 * a whole fake link for the new kext just to compare, either.
2855 */
2856 OSKextLog(this,
2857 kOSKextLogWarningLevel |
2858 kOSKextLogKextBookkeepingFlag,
2859 "Notice - new kext %s, v%s matches %s kext "
2860 "but can't determine if executables are the same (no UUIDs).",
2861 getIdentifierCString(),
2862 newVersionCString,
2863 (existingIsLoaded ? "loaded" : "prelinked"));
2864 }
2865
2866 if (sameVersion && sameExecutable) {
2867 OSKextLog(this,
2868 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2869 kOSKextLogKextBookkeepingFlag,
2870 "Refusing new kext %s, v%s: a %s copy is already present "
2871 "(same version and executable).",
2872 getIdentifierCString(), newVersionCString,
2873 (existingIsLoaded ? "loaded" : "prelinked"));
2874 } else {
2875 if (!sameVersion) {
2876 /* This condition is significant so log it under warnings.
2877 */
2878 OSKextLog(this,
2879 kOSKextLogWarningLevel |
2880 kOSKextLogKextBookkeepingFlag,
2881 "Refusing new kext %s, v%s: already have %s v%s.",
2882 getIdentifierCString(),
2883 newVersionCString,
2884 (existingIsLoaded ? "loaded" : "prelinked"),
2885 existingVersionCString);
2886 } else {
2887 /* This condition is significant so log it under warnings.
2888 */
2889 OSKextLog(this,
2890 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2891 "Refusing new kext %s, v%s: a %s copy with a different "
2892 "executable UUID is already present.",
2893 getIdentifierCString(), newVersionCString,
2894 (existingIsLoaded ? "loaded" : "prelinked"));
2895 }
2896 }
2897 goto finish;
2898 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2899
2900 /* Refuse to allow an existing loaded codeless kext be replaced by a
2901 * normal kext with the same bundle ID.
2902 */
2903 if (existingIsCodeless && declaresExecutable()) {
2904 OSKextLog(this,
2905 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2906 "Refusing new kext %s, v%s: a codeless copy is already %s",
2907 getIdentifierCString(), newVersionCString,
2908 (existingIsLoaded ? "loaded" : "prelinked"));
2909 goto finish;
2910 }
2911
2912 /* Dexts packaged in the BootKC will be protected against replacement
2913 * by non-dexts by the logic above which checks if they are prelinked.
2914 * Dexts which are prelinked into the System KC will be registered
2915 * before any other kexts in the AuxKC are registered, and we never
2916 * put dexts in the AuxKC. Therefore, there is no need to check if an
2917 * existing object is a dext and is being replaced by a non-dext.
2918 * The scenario cannot happen by construction.
2919 *
2920 * See: OSKext::loadFileSetKexts()
2921 */
2922
2923
2924 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2925 * user loads are happening or if we're still in early boot. User agents are
2926 * supposed to resolve dependencies topside and include only the exact
2927 * kexts needed; so we always accept the new kext (in fact we should never
2928 * see an older unloaded copy hanging around).
2929 */
2930 if (sUserLoadsActive) {
2931 sKextsByID->setObject(bundleID.get(), this);
2932 result = kOSKextInitialized;
2933
2934 OSKextLog(this,
2935 kOSKextLogStepLevel |
2936 kOSKextLogKextBookkeepingFlag,
2937 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2938 getIdentifierCString(),
2939 existingVersionCString,
2940 newVersionCString);
2941
2942 goto finish;
2943 }
2944
2945 /* During early boot, the kext with the highest version always wins out.
2946 * Prelinked kernels will never hit this, but mkexts and booter-read
2947 * kexts might have duplicates.
2948 */
2949 if (newVersion > existingVersion) {
2950 sKextsByID->setObject(bundleID.get(), this);
2951 result = kOSKextInitialized;
2952
2953 OSKextLog(this,
2954 kOSKextLogStepLevel |
2955 kOSKextLogKextBookkeepingFlag,
2956 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2957 existingVersionCString,
2958 getIdentifierCString(),
2959 newVersionCString);
2960 } else {
2961 OSKextLog(this,
2962 kOSKextLogStepLevel |
2963 kOSKextLogKextBookkeepingFlag,
2964 "Kext %s is already registered with a higher/same version (v%s); "
2965 "dropping newly-added (v%s).",
2966 getIdentifierCString(),
2967 existingVersionCString,
2968 newVersionCString);
2969 }
2970
2971 /* result has been set appropriately by now. */
2972
2973 finish:
2974
2975 IORecursiveLockUnlock(sKextLock);
2976
2977 if (newDextUniqueIDCString != NULL) {
2978 kfree_data(newDextUniqueIDCString, newDextUniqueIDCStringSize);
2979 }
2980 if (existingDextUniqueIDCString != NULL) {
2981 kfree_data(existingDextUniqueIDCString, existingDextUniqueIDCStringSize);
2982 }
2983
2984 if (result == kOSKextInitialized) {
2985 OSKextLog(this,
2986 kOSKextLogStepLevel |
2987 kOSKextLogKextBookkeepingFlag,
2988 "Kext %s, v%s registered and available for loading.",
2989 getIdentifierCString(), newVersionCString);
2990 }
2991
2992 return result;
2993 }
2994
2995 /*********************************************************************
2996 * Does the bare minimum validation to look up a kext.
2997 * All other validation is done on the spot as needed.
2998 **********************************************************************/
2999 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)3000 OSKext::setInfoDictionaryAndPath(
3001 OSDictionary * aDictionary,
3002 OSString * aPath)
3003 {
3004 bool result = false;
3005 OSString * bundleIDString = NULL; // do not release
3006 OSString * versionString = NULL; // do not release
3007 OSString * compatibleVersionString = NULL; // do not release
3008 const char * versionCString = NULL; // do not free
3009 const char * compatibleVersionCString = NULL; // do not free
3010 OSBoolean * scratchBool = NULL; // do not release
3011 OSDictionary * scratchDict = NULL; // do not release
3012
3013 if (infoDict) {
3014 panic("Attempt to set info dictionary on a kext "
3015 "that already has one (%s).",
3016 getIdentifierCString());
3017 }
3018
3019 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
3020 goto finish;
3021 }
3022
3023 infoDict.reset(aDictionary, OSRetain);
3024
3025 /* Check right away if the info dictionary has any log flags.
3026 */
3027 scratchBool = OSDynamicCast(OSBoolean,
3028 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
3029 if (scratchBool == kOSBooleanTrue) {
3030 flags.loggingEnabled = 1;
3031 }
3032
3033 /* The very next thing to get is the bundle identifier. Unlike
3034 * in user space, a kext with no bundle identifier gets axed
3035 * immediately.
3036 */
3037 bundleIDString = OSDynamicCast(OSString,
3038 getPropertyForHostArch(kCFBundleIdentifierKey));
3039 if (!bundleIDString) {
3040 OSKextLog(this,
3041 kOSKextLogErrorLevel |
3042 kOSKextLogValidationFlag,
3043 "CFBundleIdentifier missing/invalid type in kext %s.",
3044 aPath ? aPath->getCStringNoCopy() : "(unknown)");
3045 goto finish;
3046 }
3047 bundleID = OSSymbol::withString(bundleIDString);
3048 if (!bundleID) {
3049 OSKextLog(this,
3050 kOSKextLogErrorLevel |
3051 kOSKextLogValidationFlag,
3052 "Can't copy bundle identifier as symbol for kext %s.",
3053 bundleIDString->getCStringNoCopy());
3054 goto finish;
3055 }
3056
3057 /* Save the path if we got one (it should always be available but it's
3058 * just something nice to have for bookkeeping).
3059 */
3060 if (aPath) {
3061 path.reset(aPath, OSRetain);
3062 }
3063
3064 /*****
3065 * Minimal validation to initialize. We'll do other validation on the spot.
3066 */
3067 if (bundleID->getLength() >= KMOD_MAX_NAME) {
3068 OSKextLog(this,
3069 kOSKextLogErrorLevel |
3070 kOSKextLogValidationFlag,
3071 "Kext %s error - CFBundleIdentifier over max length %d.",
3072 getIdentifierCString(), KMOD_MAX_NAME - 1);
3073 goto finish;
3074 }
3075
3076 version = compatibleVersion = -1;
3077
3078 versionString = OSDynamicCast(OSString,
3079 getPropertyForHostArch(kCFBundleVersionKey));
3080 if (!versionString) {
3081 OSKextLog(this,
3082 kOSKextLogErrorLevel |
3083 kOSKextLogValidationFlag,
3084 "Kext %s error - CFBundleVersion missing/invalid type.",
3085 getIdentifierCString());
3086 goto finish;
3087 }
3088 versionCString = versionString->getCStringNoCopy();
3089 version = OSKextParseVersionString(versionCString);
3090 if (version < 0) {
3091 OSKextLog(this,
3092 kOSKextLogErrorLevel |
3093 kOSKextLogValidationFlag,
3094 "Kext %s error - CFBundleVersion bad value '%s'.",
3095 getIdentifierCString(), versionCString);
3096 goto finish;
3097 }
3098
3099 compatibleVersion = -1; // set to illegal value for kexts that don't have
3100
3101 compatibleVersionString = OSDynamicCast(OSString,
3102 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
3103 if (compatibleVersionString) {
3104 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
3105 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
3106 if (compatibleVersion < 0) {
3107 OSKextLog(this,
3108 kOSKextLogErrorLevel |
3109 kOSKextLogValidationFlag,
3110 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
3111 getIdentifierCString(), compatibleVersionCString);
3112 goto finish;
3113 }
3114
3115 if (compatibleVersion > version) {
3116 OSKextLog(this,
3117 kOSKextLogErrorLevel |
3118 kOSKextLogValidationFlag,
3119 "Kext %s error - %s %s > %s %s (must be <=).",
3120 getIdentifierCString(),
3121 kOSBundleCompatibleVersionKey, compatibleVersionCString,
3122 kCFBundleVersionKey, versionCString);
3123 goto finish;
3124 }
3125 }
3126
3127 /* Check to see if this kext is in exclude list */
3128 if (isInExcludeList()) {
3129 OSKextLog(this,
3130 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3131 "Kext %s is in exclude list, not loadable",
3132 getIdentifierCString());
3133 goto finish;
3134 }
3135
3136 /* Set flags for later use if the infoDict gets flushed. We only
3137 * check for true values, not false ones(!)
3138 */
3139 scratchBool = OSDynamicCast(OSBoolean,
3140 getPropertyForHostArch(kOSBundleIsInterfaceKey));
3141 if (scratchBool == kOSBooleanTrue) {
3142 flags.interface = 1;
3143 }
3144
3145 scratchBool = OSDynamicCast(OSBoolean,
3146 getPropertyForHostArch(kOSKernelResourceKey));
3147 if (scratchBool == kOSBooleanTrue) {
3148 flags.kernelComponent = 1;
3149 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
3150 flags.started = 1;
3151
3152 /* A kernel component has one implicit dependency on the kernel.
3153 */
3154 flags.hasAllDependencies = 1;
3155 }
3156
3157 /* Make sure common string values in personalities are uniqued to OSSymbols.
3158 */
3159 scratchDict = OSDynamicCast(OSDictionary,
3160 getPropertyForHostArch(kIOKitPersonalitiesKey));
3161 if (scratchDict) {
3162 uniquePersonalityProperties(scratchDict);
3163 }
3164
3165 result = true;
3166
3167 finish:
3168
3169 return result;
3170 }
3171
3172 /*********************************************************************
3173 * Not used for prelinked kernel boot as there is no unrelocated
3174 * executable.
3175 *********************************************************************/
3176 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)3177 OSKext::setExecutable(
3178 OSData * anExecutable,
3179 OSData * externalData,
3180 bool externalDataIsMkext)
3181 {
3182 bool result = false;
3183 const char * executableKey = NULL; // do not free
3184
3185 if (!anExecutable) {
3186 infoDict->removeObject(_kOSKextExecutableKey);
3187 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3188 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3189 result = true;
3190 goto finish;
3191 }
3192
3193 if (infoDict->getObject(_kOSKextExecutableKey) ||
3194 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
3195 panic("Attempt to set an executable on a kext "
3196 "that already has one (%s).",
3197 getIdentifierCString());
3198 goto finish;
3199 }
3200
3201 if (externalDataIsMkext) {
3202 executableKey = _kOSKextMkextExecutableReferenceKey;
3203 } else {
3204 executableKey = _kOSKextExecutableKey;
3205 }
3206
3207 if (anExecutable) {
3208 infoDict->setObject(executableKey, anExecutable);
3209 if (externalData) {
3210 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
3211 }
3212 }
3213
3214 result = true;
3215
3216 finish:
3217 return result;
3218 }
3219
3220 /*********************************************************************
3221 *********************************************************************/
3222 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)3223 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
3224 {
3225 OSObject * value = NULL; // do not release
3226 OSString * stringValue = NULL; // do not release
3227 OSSharedPtr<const OSSymbol> symbolValue;
3228
3229 value = dict->getObject(key);
3230 if (!value) {
3231 goto finish;
3232 }
3233 if (OSDynamicCast(OSSymbol, value)) {
3234 /* this is already an OSSymbol: we're good */
3235 goto finish;
3236 }
3237
3238 stringValue = OSDynamicCast(OSString, value);
3239 if (!stringValue) {
3240 goto finish;
3241 }
3242
3243 symbolValue = OSSymbol::withString(stringValue);
3244 if (!symbolValue) {
3245 goto finish;
3246 }
3247
3248 dict->setObject(key, symbolValue.get());
3249
3250 finish:
3251 return;
3252 }
3253
3254 /*********************************************************************
3255 *********************************************************************/
3256 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)3257 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
3258 {
3259 OSObject * value = NULL; // do not release
3260 OSString * stringValue = NULL; // do not release
3261 OSSharedPtr<const OSSymbol> symbolValue;
3262
3263 value = dict->getObject(key);
3264 if (!value) {
3265 goto finish;
3266 }
3267 if (OSDynamicCast(OSSymbol, value)) {
3268 /* this is already an OSSymbol: we're good */
3269 goto finish;
3270 }
3271
3272 stringValue = OSDynamicCast(OSString, value);
3273 if (!stringValue) {
3274 goto finish;
3275 }
3276
3277 symbolValue = OSSymbol::withString(stringValue);
3278 if (!symbolValue) {
3279 goto finish;
3280 }
3281
3282 dict->setObject(key, symbolValue.get());
3283
3284 finish:
3285 return;
3286 }
3287
3288 void
uniquePersonalityProperties(OSDictionary * personalityDict)3289 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
3290 {
3291 OSKext::uniquePersonalityProperties(personalityDict, true);
3292 }
3293
3294 /*********************************************************************
3295 * Replace common personality property values with uniqued instances
3296 * to save on wired memory.
3297 *********************************************************************/
3298 /* static */
3299 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)3300 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
3301 {
3302 /* Properties every personality has.
3303 */
3304 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
3305 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
3306 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
3307 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
3308 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
3309 } else if (defaultAddKernelBundleIdentifier) {
3310 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
3311 }
3312
3313 /* Other commonly used properties.
3314 */
3315 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
3316 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
3317 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
3318
3319 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
3320 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
3321 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
3322 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
3323 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
3324 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
3325 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
3326 uniqueStringPlistProperty(personalityDict, "Vendor");
3327 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
3328 uniqueStringPlistProperty(personalityDict, "Vendor Name");
3329 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
3330 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
3331 uniqueStringPlistProperty(personalityDict, "idProduct");
3332
3333 return;
3334 }
3335
3336 /*********************************************************************
3337 *********************************************************************/
3338 void
free(void)3339 OSKext::free(void)
3340 {
3341 if (isLoaded()) {
3342 panic("Attempt to free loaded kext %s.", getIdentifierCString());
3343 }
3344
3345 if (isDriverKit()) {
3346 if (dextLaunchedCount > 0) {
3347 panic("Freeing dext %s but dextLaunchedCount is %d\n", getIdentifierCString(), dextLaunchedCount);
3348 }
3349 }
3350
3351 infoDict.reset();
3352 bundleID.reset();
3353 path.reset();
3354 executableRelPath.reset();
3355 userExecutableRelPath.reset();
3356 dependencies.reset();
3357 linkedExecutable.reset();
3358 metaClasses.reset();
3359 interfaceUUID.reset();
3360 driverKitUUID.reset();
3361 dextStatistics.reset();
3362 dextUniqueID.reset();
3363
3364 if (isInterface() && kmod_info) {
3365 kfree_type(kmod_info_t, kmod_info);
3366 }
3367
3368 super::free();
3369 return;
3370 }
3371
3372 #if PRAGMA_MARK
3373 #pragma mark Mkext files
3374 #endif
3375
3376 #if CONFIG_KXLD
3377 /*
3378 * mkext archives are really only relevant on kxld-enabled kernels.
3379 * Without a dynamic kernel linker, we don't need to support any mkexts.
3380 */
3381
3382 /*********************************************************************
3383 *********************************************************************/
3384 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)3385 OSKext::readMkextArchive(OSData * mkextData,
3386 uint32_t * checksumPtr)
3387 {
3388 OSReturn result = kOSKextReturnBadData;
3389 uint32_t mkextLength = 0;
3390 mkext_header * mkextHeader = NULL; // do not free
3391 uint32_t mkextVersion = 0;
3392
3393 /* Note default return of kOSKextReturnBadData above.
3394 */
3395 mkextLength = mkextData->getLength();
3396 if (mkextLength < sizeof(mkext_basic_header)) {
3397 OSKextLog(/* kext */ NULL,
3398 kOSKextLogErrorLevel |
3399 kOSKextLogArchiveFlag,
3400 "Mkext archive too small to be valid.");
3401 goto finish;
3402 }
3403
3404 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
3405
3406 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
3407 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
3408 OSKextLog(/* kext */ NULL,
3409 kOSKextLogErrorLevel |
3410 kOSKextLogArchiveFlag,
3411 "Mkext archive has invalid magic or signature.");
3412 goto finish;
3413 }
3414
3415 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
3416 OSKextLog(/* kext */ NULL,
3417 kOSKextLogErrorLevel |
3418 kOSKextLogArchiveFlag,
3419 "Mkext archive recorded length doesn't match actual file length.");
3420 goto finish;
3421 }
3422
3423 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3424
3425 if (mkextVersion == MKEXT_VERS_2) {
3426 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
3427 } else {
3428 OSKextLog(/* kext */ NULL,
3429 kOSKextLogErrorLevel |
3430 kOSKextLogArchiveFlag,
3431 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3432 result = kOSKextReturnUnsupported;
3433 }
3434
3435 finish:
3436 return result;
3437 }
3438
3439 /*********************************************************************
3440 * Assumes magic, signature, version, length have been checked.
3441 * xxx - need to add further bounds checking for each file entry
3442 *
3443 * Should keep track of all kexts created so far, and if we hit a
3444 * fatal error halfway through, remove those kexts. If we've dropped
3445 * an older version that had already been read, whoops! Might want to
3446 * add a level of buffering?
3447 *********************************************************************/
3448 /* static */
3449 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3450 OSKext::readMkext2Archive(
3451 OSData * mkextData,
3452 OSDictionary ** mkextPlistOut,
3453 uint32_t * checksumPtr)
3454 {
3455 OSReturn result = kOSReturnError;
3456 uint32_t mkextLength;
3457 mkext2_header * mkextHeader = NULL; // do not free
3458 void * mkextEnd = NULL; // do not free
3459 uint32_t mkextVersion;
3460 uint8_t * crc_address = NULL;
3461 size_t crc_buffer_size = 0;
3462 uint32_t checksum;
3463 uint32_t mkextPlistOffset;
3464 uint32_t mkextPlistCompressedSize;
3465 char * mkextPlistEnd = NULL; // do not free
3466 uint32_t mkextPlistFullSize;
3467 OSSharedPtr<OSString> errorString;
3468 OSSharedPtr<OSData> mkextPlistUncompressedData;
3469 const char * mkextPlistDataBuffer = NULL; // do not free
3470 OSSharedPtr<OSObject> parsedXML;
3471 OSDictionary * mkextPlist = NULL; // do not release
3472 OSArray * mkextInfoDictArray = NULL; // do not release
3473 uint32_t count, i;
3474 kc_format_t kc_format;
3475
3476 if (!PE_get_primary_kc_format(&kc_format)) {
3477 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3478 "Unable to determine primary KC format");
3479 goto finish;
3480 }
3481
3482 mkextLength = mkextData->getLength();
3483 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3484 mkextEnd = (char *)mkextHeader + mkextLength;
3485 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3486
3487 crc_address = (u_int8_t *)&mkextHeader->version;
3488 crc_buffer_size = (uintptr_t)mkextHeader +
3489 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3490 if (crc_buffer_size > INT32_MAX) {
3491 OSKextLog(/* kext */ NULL,
3492 kOSKextLogErrorLevel |
3493 kOSKextLogArchiveFlag,
3494 "Mkext archive size is too large (%lu > INT32_MAX).",
3495 crc_buffer_size);
3496 result = kOSKextReturnBadData;
3497 goto finish;
3498 }
3499 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3500
3501 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3502 OSKextLog(/* kext */ NULL,
3503 kOSKextLogErrorLevel |
3504 kOSKextLogArchiveFlag,
3505 "Mkext archive has bad checksum.");
3506 result = kOSKextReturnBadData;
3507 goto finish;
3508 }
3509
3510 if (checksumPtr) {
3511 *checksumPtr = checksum;
3512 }
3513
3514 /* Check that the CPU type & subtype match that of the running kernel. */
3515 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3516 OSKextLog(/* kext */ NULL,
3517 kOSKextLogErrorLevel |
3518 kOSKextLogArchiveFlag,
3519 "Mkext archive must have a specific CPU type.");
3520 result = kOSKextReturnBadData;
3521 goto finish;
3522 } else {
3523 if ((UInt32)_mh_execute_header.cputype !=
3524 MKEXT_GET_CPUTYPE(mkextHeader)) {
3525 OSKextLog(/* kext */ NULL,
3526 kOSKextLogErrorLevel |
3527 kOSKextLogArchiveFlag,
3528 "Mkext archive does not match the running kernel's CPU type.");
3529 result = kOSKextReturnArchNotFound;
3530 goto finish;
3531 }
3532 }
3533
3534 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3535 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3536 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3537 mkextPlistCompressedSize;
3538 if (mkextPlistEnd > mkextEnd) {
3539 OSKextLog(/* kext */ NULL,
3540 kOSKextLogErrorLevel |
3541 kOSKextLogArchiveFlag,
3542 "Mkext archive file overrun.");
3543 result = kOSKextReturnBadData;
3544 }
3545
3546 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3547 if (mkextPlistCompressedSize) {
3548 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3549 (UInt8 *)mkextHeader + mkextPlistOffset,
3550 "plist",
3551 mkextPlistCompressedSize, mkextPlistFullSize);
3552 if (!mkextPlistUncompressedData) {
3553 goto finish;
3554 }
3555 mkextPlistDataBuffer = (const char *)
3556 mkextPlistUncompressedData->getBytesNoCopy();
3557 } else {
3558 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3559 }
3560
3561 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3562 */
3563 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3564 if (parsedXML) {
3565 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3566 }
3567 if (!mkextPlist) {
3568 const char * errorCString = "(unknown error)";
3569
3570 if (errorString && errorString->getCStringNoCopy()) {
3571 errorCString = errorString->getCStringNoCopy();
3572 } else if (parsedXML) {
3573 errorCString = "not a dictionary";
3574 }
3575 OSKextLog(/* kext */ NULL,
3576 kOSKextLogErrorLevel |
3577 kOSKextLogArchiveFlag,
3578 "Error unserializing mkext plist: %s.", errorCString);
3579 goto finish;
3580 }
3581
3582 mkextInfoDictArray = OSDynamicCast(OSArray,
3583 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3584 if (!mkextInfoDictArray) {
3585 OSKextLog(/* kext */ NULL,
3586 kOSKextLogErrorLevel |
3587 kOSKextLogArchiveFlag,
3588 "Mkext archive contains no kext info dictionaries.");
3589 goto finish;
3590 }
3591
3592 count = mkextInfoDictArray->getCount();
3593 for (i = 0; i < count; i++) {
3594 OSDictionary * infoDict;
3595
3596
3597 infoDict = OSDynamicCast(OSDictionary,
3598 mkextInfoDictArray->getObject(i));
3599
3600 /* Create the kext for the entry, then release it, because the
3601 * kext system keeps them around until explicitly removed.
3602 * Any creation/registration failures are already logged for us.
3603 */
3604 if (infoDict) {
3605 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3606
3607 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3608 if (kc_format == KCFormatFileset &&
3609 newKext &&
3610 !(newKext->isPrelinked()) &&
3611 newKext->declaresExecutable()) {
3612 result = kOSReturnError;
3613 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3614 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3615
3616 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3617 "Dynamic loading of kext denied for kext %s\n",
3618 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3619 goto finish;
3620 }
3621 }
3622 }
3623
3624 /* If the caller needs the plist, hand them back our copy
3625 */
3626 if (mkextPlistOut) {
3627 *mkextPlistOut = mkextPlist;
3628 parsedXML.detach();
3629 }
3630
3631 /* Even if we didn't keep any kexts from the mkext, we may have a load
3632 * request to process, so we are successful (no errors occurred).
3633 */
3634 result = kOSReturnSuccess;
3635
3636 finish:
3637 return result;
3638 }
3639
3640 /* static */
3641 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3642 OSKext::readMkext2Archive(
3643 OSData * mkextData,
3644 OSSharedPtr<OSDictionary> &mkextPlistOut,
3645 uint32_t * checksumPtr)
3646 {
3647 OSDictionary * mkextPlist = NULL;
3648 OSReturn ret;
3649
3650 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3651 &mkextPlist,
3652 checksumPtr))) {
3653 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3654 }
3655 return ret;
3656 }
3657
3658 /*********************************************************************
3659 *********************************************************************/
3660 /* static */
3661 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3662 OSKext::withMkext2Info(
3663 OSDictionary * anInfoDict,
3664 OSData * mkextData)
3665 {
3666 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3667
3668 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3669 return NULL;
3670 }
3671
3672 return newKext;
3673 }
3674
3675 /*********************************************************************
3676 *********************************************************************/
3677 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3678 OSKext::initWithMkext2Info(
3679 OSDictionary * anInfoDict,
3680 OSData * mkextData)
3681 {
3682 bool result = false;
3683 OSString * kextPath = NULL; // do not release
3684 OSNumber * executableOffsetNum = NULL; // do not release
3685 OSSharedPtr<OSData> executable;
3686
3687 if (anInfoDict == NULL || !super::init()) {
3688 goto finish;
3689 }
3690
3691 /* Get the path. Don't look for an arch-specific path property.
3692 */
3693 kextPath = OSDynamicCast(OSString,
3694 anInfoDict->getObject(kMKEXTBundlePathKey));
3695
3696 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3697 goto finish;
3698 }
3699
3700 /* If we have a path to the executable, save it.
3701 */
3702 executableRelPath.reset(OSDynamicCast(OSString,
3703 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3704
3705 /* Don't need the paths to be in the info dictionary any more.
3706 */
3707 anInfoDict->removeObject(kMKEXTBundlePathKey);
3708 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3709
3710 executableOffsetNum = OSDynamicCast(OSNumber,
3711 infoDict->getObject(kMKEXTExecutableKey));
3712 if (executableOffsetNum) {
3713 executable = createMkext2FileEntry(mkextData,
3714 executableOffsetNum, "executable");
3715 infoDict->removeObject(kMKEXTExecutableKey);
3716 if (!executable) {
3717 goto finish;
3718 }
3719 if (!setExecutable(executable.get(), mkextData, true)) {
3720 goto finish;
3721 }
3722 }
3723
3724 result = (registerIdentifier() == kOSKextInitialized);
3725 finish:
3726 return result;
3727 }
3728
3729 /*********************************************************************
3730 *********************************************************************/
3731 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3732 OSKext::createMkext2FileEntry(
3733 OSData * mkextData,
3734 OSNumber * offsetNum,
3735 const char * name)
3736 {
3737 OSSharedPtr<OSData> result;
3738 MkextEntryRef entryRef;
3739 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3740 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3741
3742 result = OSData::withCapacity(sizeof(entryRef));
3743 if (!result) {
3744 goto finish;
3745 }
3746
3747 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3748 entryRef.fileinfo = mkextBuffer + entryOffset;
3749 if (!result->appendValue(entryRef)) {
3750 result.reset();
3751 goto finish;
3752 }
3753
3754 finish:
3755 if (!result) {
3756 OSKextLog(this,
3757 kOSKextLogErrorLevel |
3758 kOSKextLogArchiveFlag,
3759 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3760 name, getIdentifierCString());
3761 }
3762 return result;
3763 }
3764
3765 /*********************************************************************
3766 *********************************************************************/
3767 extern "C" {
3768 static void * z_alloc(void *, u_int items, u_int size);
3769 static void z_free(void *, void *ptr);
3770
3771 typedef struct z_mem {
3772 uint32_t alloc_size;
3773 uint8_t data[0];
3774 } z_mem;
3775
3776 /*
3777 * Space allocation and freeing routines for use by zlib routines.
3778 */
3779 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3780 z_alloc(void * notused __unused, u_int num_items, u_int size)
3781 {
3782 void * result = NULL;
3783 z_mem * zmem = NULL;
3784
3785 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3786 //Check for overflow due to multiplication
3787 if (total > UINT32_MAX) {
3788 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3789 notused, num_items, size, num_items, size);
3790 }
3791
3792 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3793 //Check for overflow due to addition
3794 if (allocSize64 > UINT32_MAX) {
3795 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3796 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3797 }
3798 uint32_t allocSize = (uint32_t)allocSize64;
3799
3800 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3801 VM_KERN_MEMORY_OSKEXT);
3802 if (!zmem) {
3803 goto finish;
3804 }
3805 zmem->alloc_size = allocSize;
3806 result = (void *)&(zmem->data);
3807 finish:
3808 return result;
3809 }
3810
3811 void
z_free(void * notused __unused,void * ptr)3812 z_free(void * notused __unused, void * ptr)
3813 {
3814 uint32_t * skipper = (uint32_t *)ptr - 1;
3815 z_mem * zmem = (z_mem *)skipper;
3816 kfree_data(zmem, zmem->alloc_size);
3817 }
3818 };
3819
3820 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3821 OSKext::extractMkext2FileData(
3822 UInt8 * data,
3823 const char * name,
3824 uint32_t compressedSize,
3825 uint32_t fullSize)
3826 {
3827 OSSharedPtr<OSData> result;
3828 OSSharedPtr<OSData> uncompressedData; // release on error
3829
3830 uint8_t * uncompressedDataBuffer = NULL; // do not free
3831 unsigned long uncompressedSize;
3832 z_stream zstream;
3833 bool zstream_inited = false;
3834 int zlib_result;
3835
3836 /* If the file isn't compressed, we want to make a copy
3837 * so that we don't have the tie to the larger mkext file buffer any more.
3838 */
3839 if (!compressedSize) {
3840 uncompressedData = OSData::withBytes(data, fullSize);
3841 // xxx - no check for failure?
3842 result = uncompressedData;
3843 goto finish;
3844 }
3845
3846 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3847 (vm_offset_t*)&uncompressedDataBuffer, fullSize,
3848 KMA_DATA_SHARED, VM_KERN_MEMORY_OSKEXT)) {
3849 /* How's this for cheesy? The kernel is only asked to extract
3850 * kext plists so we tailor the log messages.
3851 */
3852 if (isKernel()) {
3853 OSKextLog(this,
3854 kOSKextLogErrorLevel |
3855 kOSKextLogArchiveFlag,
3856 "Allocation failure extracting %s from mkext.", name);
3857 } else {
3858 OSKextLog(this,
3859 kOSKextLogErrorLevel |
3860 kOSKextLogArchiveFlag,
3861 "Allocation failure extracting %s from mkext for kext %s.",
3862 name, getIdentifierCString());
3863 }
3864
3865 goto finish;
3866 }
3867 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3868 if (!uncompressedData) {
3869 if (isKernel()) {
3870 OSKextLog(this,
3871 kOSKextLogErrorLevel |
3872 kOSKextLogArchiveFlag,
3873 "Allocation failure extracting %s from mkext.", name);
3874 } else {
3875 OSKextLog(this,
3876 kOSKextLogErrorLevel |
3877 kOSKextLogArchiveFlag,
3878 "Allocation failure extracting %s from mkext for kext %s.",
3879 name, getIdentifierCString());
3880 }
3881 goto finish;
3882 }
3883 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3884
3885 if (isKernel()) {
3886 OSKextLog(this,
3887 kOSKextLogDetailLevel |
3888 kOSKextLogArchiveFlag,
3889 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3890 name, compressedSize, fullSize);
3891 } else {
3892 OSKextLog(this,
3893 kOSKextLogDetailLevel |
3894 kOSKextLogArchiveFlag,
3895 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3896 getIdentifierCString(), name, compressedSize, fullSize);
3897 }
3898
3899 bzero(&zstream, sizeof(zstream));
3900 zstream.next_in = (UInt8 *)data;
3901 zstream.avail_in = compressedSize;
3902
3903 zstream.next_out = uncompressedDataBuffer;
3904 zstream.avail_out = fullSize;
3905
3906 zstream.zalloc = z_alloc;
3907 zstream.zfree = z_free;
3908
3909 zlib_result = inflateInit(&zstream);
3910 if (Z_OK != zlib_result) {
3911 if (isKernel()) {
3912 OSKextLog(this,
3913 kOSKextLogErrorLevel |
3914 kOSKextLogArchiveFlag,
3915 "Mkext error; zlib inflateInit failed (%d) for %s.",
3916 zlib_result, name);
3917 } else {
3918 OSKextLog(this,
3919 kOSKextLogErrorLevel |
3920 kOSKextLogArchiveFlag,
3921 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3922 getIdentifierCString(), zlib_result, name);
3923 }
3924 goto finish;
3925 } else {
3926 zstream_inited = true;
3927 }
3928
3929 zlib_result = inflate(&zstream, Z_FINISH);
3930
3931 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3932 uncompressedSize = zstream.total_out;
3933 } else {
3934 if (isKernel()) {
3935 OSKextLog(this,
3936 kOSKextLogErrorLevel |
3937 kOSKextLogArchiveFlag,
3938 "Mkext error; zlib inflate failed (%d) for %s.",
3939 zlib_result, name);
3940 } else {
3941 OSKextLog(this,
3942 kOSKextLogErrorLevel |
3943 kOSKextLogArchiveFlag,
3944 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3945 getIdentifierCString(), zlib_result, name);
3946 }
3947 if (zstream.msg) {
3948 OSKextLog(this,
3949 kOSKextLogErrorLevel |
3950 kOSKextLogArchiveFlag,
3951 "zlib error: %s.", zstream.msg);
3952 }
3953 goto finish;
3954 }
3955
3956 if (uncompressedSize != fullSize) {
3957 if (isKernel()) {
3958 OSKextLog(this,
3959 kOSKextLogErrorLevel |
3960 kOSKextLogArchiveFlag,
3961 "Mkext error; zlib inflate discrepancy for %s, "
3962 "uncompressed size != original size.", name);
3963 } else {
3964 OSKextLog(this,
3965 kOSKextLogErrorLevel |
3966 kOSKextLogArchiveFlag,
3967 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3968 "uncompressed size != original size.",
3969 getIdentifierCString(), name);
3970 }
3971 goto finish;
3972 }
3973
3974 result = os::move(uncompressedData);
3975
3976 finish:
3977 /* Don't bother checking return, nothing we can do on fail.
3978 */
3979 if (zstream_inited) {
3980 inflateEnd(&zstream);
3981 }
3982
3983 return result;
3984 }
3985
3986 /*********************************************************************
3987 *********************************************************************/
3988 /* static */
3989 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3990 OSKext::loadFromMkext(
3991 OSKextLogSpec clientLogFilter,
3992 char * mkextBuffer,
3993 uint32_t mkextBufferLength,
3994 char ** logInfoOut,
3995 uint32_t * logInfoLengthOut)
3996 {
3997 OSReturn result = kOSReturnError;
3998 OSReturn tempResult = kOSReturnError;
3999
4000 OSSharedPtr<OSData> mkextData;
4001 OSSharedPtr<OSDictionary> mkextPlist;
4002
4003 OSSharedPtr<OSArray> logInfoArray;
4004 OSSharedPtr<OSSerialize> serializer;
4005
4006 OSString * predicate = NULL; // do not release
4007 OSDictionary * requestArgs = NULL; // do not release
4008
4009 OSString * kextIdentifier = NULL; // do not release
4010 OSNumber * startKextExcludeNum = NULL; // do not release
4011 OSNumber * startMatchingExcludeNum = NULL; // do not release
4012 OSBoolean * delayAutounloadBool = NULL; // do not release
4013 OSArray * personalityNames = NULL; // do not release
4014
4015 /* Default values for these two options: regular autounload behavior,
4016 * load all kexts, send no personalities.
4017 */
4018 Boolean delayAutounload = false;
4019 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
4020 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
4021
4022 IORecursiveLockLock(sKextLock);
4023
4024 if (logInfoOut) {
4025 *logInfoOut = NULL;
4026 *logInfoLengthOut = 0;
4027 }
4028
4029 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
4030
4031 OSKextLog(/* kext */ NULL,
4032 kOSKextLogDebugLevel |
4033 kOSKextLogIPCFlag,
4034 "Received kext load request from user space.");
4035
4036 /* Regardless of processing, the fact that we have gotten here means some
4037 * user-space program is up and talking to us, so we'll switch our kext
4038 * registration to reflect that.
4039 */
4040 if (!sUserLoadsActive) {
4041 OSKextLog(/* kext */ NULL,
4042 kOSKextLogProgressLevel |
4043 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
4044 "Switching to late startup (user-space) kext loading policy.");
4045
4046 sUserLoadsActive = true;
4047 }
4048
4049 if (!sLoadEnabled) {
4050 OSKextLog(/* kext */ NULL,
4051 kOSKextLogErrorLevel |
4052 kOSKextLogLoadFlag,
4053 "Kext loading is disabled.");
4054 result = kOSKextReturnDisabled;
4055 goto finish;
4056 }
4057
4058 /* Note that we do not set a dealloc function on this OSData
4059 * object! No references to it can remain after the loadFromMkext()
4060 * call since we are in a MIG function, and will vm_deallocate()
4061 * the buffer.
4062 */
4063 mkextData = OSData::withBytesNoCopy(mkextBuffer,
4064 mkextBufferLength);
4065 if (!mkextData) {
4066 OSKextLog(/* kext */ NULL,
4067 kOSKextLogErrorLevel |
4068 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4069 "Failed to create wrapper for kext load request.");
4070 result = kOSKextReturnNoMemory;
4071 goto finish;
4072 }
4073
4074 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
4075 if (result != kOSReturnSuccess) {
4076 OSKextLog(/* kext */ NULL,
4077 kOSKextLogErrorLevel |
4078 kOSKextLogLoadFlag,
4079 "Failed to read kext load request.");
4080 goto finish;
4081 }
4082
4083 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
4084 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
4085 OSKextLog(/* kext */ NULL,
4086 kOSKextLogErrorLevel |
4087 kOSKextLogLoadFlag,
4088 "Received kext load request with no predicate; skipping.");
4089 result = kOSKextReturnInvalidArgument;
4090 goto finish;
4091 }
4092
4093 requestArgs = OSDynamicCast(OSDictionary,
4094 mkextPlist->getObject(kKextRequestArgumentsKey));
4095 if (!requestArgs || !requestArgs->getCount()) {
4096 OSKextLog(/* kext */ NULL,
4097 kOSKextLogErrorLevel |
4098 kOSKextLogLoadFlag,
4099 "Received kext load request with no arguments.");
4100 result = kOSKextReturnInvalidArgument;
4101 goto finish;
4102 }
4103
4104 kextIdentifier = OSDynamicCast(OSString,
4105 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
4106
4107 if (!kextIdentifier) {
4108 OSKextLog(/* kext */ NULL,
4109 kOSKextLogErrorLevel |
4110 kOSKextLogLoadFlag,
4111 "Received kext load request with no kext identifier.");
4112 result = kOSKextReturnInvalidArgument;
4113 goto finish;
4114 }
4115
4116 startKextExcludeNum = OSDynamicCast(OSNumber,
4117 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
4118 startMatchingExcludeNum = OSDynamicCast(OSNumber,
4119 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
4120 delayAutounloadBool = OSDynamicCast(OSBoolean,
4121 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
4122 personalityNames = OSDynamicCast(OSArray,
4123 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
4124
4125 if (delayAutounloadBool) {
4126 delayAutounload = delayAutounloadBool->getValue();
4127 }
4128 if (startKextExcludeNum) {
4129 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
4130 }
4131 if (startMatchingExcludeNum) {
4132 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
4133 }
4134
4135 OSKextLog(/* kext */ NULL,
4136 kOSKextLogProgressLevel |
4137 kOSKextLogIPCFlag,
4138 "Received request from user space to load kext %s.",
4139 kextIdentifier->getCStringNoCopy());
4140
4141 /* Load the kext, with no deferral, since this is a load from outside
4142 * the kernel.
4143 * xxx - Would like a better way to handle the default values for the
4144 * xxx - start/match opt args.
4145 */
4146 result = OSKext::loadKextWithIdentifier(
4147 kextIdentifier,
4148 /* kextRef */ NULL,
4149 /* allowDefer */ false,
4150 delayAutounload,
4151 startKextExcludeLevel,
4152 startMatchingExcludeLevel,
4153 personalityNames);
4154 if (result != kOSReturnSuccess) {
4155 goto finish;
4156 }
4157 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
4158 * for matching via a separate IOKit calldown.
4159 */
4160
4161 finish:
4162
4163 /* Gather up the collected log messages for user space. Any
4164 * error messages past this call will not make it up as log messages
4165 * but will be in the system log.
4166 */
4167 logInfoArray = OSKext::clearUserSpaceLogFilter();
4168
4169 if (logInfoArray && logInfoOut && logInfoLengthOut) {
4170 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
4171 logInfoOut, logInfoLengthOut);
4172 if (tempResult != kOSReturnSuccess) {
4173 result = tempResult;
4174 }
4175 }
4176
4177 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
4178
4179 IORecursiveLockUnlock(sKextLock);
4180
4181 /* Note: mkextDataObject will have been retained by every kext w/an
4182 * executable in it. That should all have been flushed out at the
4183 * and of the load operation, but you never know....
4184 */
4185 if (mkextData && mkextData->getRetainCount() > 1) {
4186 OSKextLog(/* kext */ NULL,
4187 kOSKextLogErrorLevel |
4188 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4189 "Kext load request buffer from user space still retained by a kext; "
4190 "probable memory leak.");
4191 }
4192
4193 return result;
4194 }
4195
4196 #endif // CONFIG_KXLD
4197
4198 /*********************************************************************
4199 *********************************************************************/
4200 /* static */
4201 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)4202 OSKext::serializeLogInfo(
4203 OSArray * logInfoArray,
4204 char ** logInfoOut,
4205 uint32_t * logInfoLengthOut)
4206 {
4207 OSReturn result = kOSReturnError;
4208 char * buffer = NULL;
4209 kern_return_t kmem_result = KERN_FAILURE;
4210 OSSharedPtr<OSSerialize> serializer;
4211 char * logInfo = NULL; // returned by reference
4212 uint32_t logInfoLength = 0;
4213
4214 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
4215 OSKextLog(/* kext */ NULL,
4216 kOSKextLogErrorLevel |
4217 kOSKextLogIPCFlag,
4218 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
4219 /* Bad programmer. */
4220 result = kOSKextReturnInvalidArgument;
4221 goto finish;
4222 }
4223
4224 serializer = OSSerialize::withCapacity(0);
4225 if (!serializer) {
4226 OSKextLog(/* kext */ NULL,
4227 kOSKextLogErrorLevel |
4228 kOSKextLogIPCFlag,
4229 "Failed to create serializer on log info for request from user space.");
4230 /* Incidental error; we're going to (try to) allow the request
4231 * itself to succeed. */
4232 } else {
4233 if (!logInfoArray->serialize(serializer.get())) {
4234 OSKextLog(/* kext */ NULL,
4235 kOSKextLogErrorLevel |
4236 kOSKextLogIPCFlag,
4237 "Failed to serialize log info for request from user space.");
4238 /* Incidental error; we're going to (try to) allow the request
4239 * itself to succeed. */
4240 } else {
4241 logInfo = serializer->text();
4242 logInfoLength = serializer->getLength();
4243
4244 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength),
4245 KMA_DATA_SHARED, VM_KERN_MEMORY_OSKEXT);
4246 if (kmem_result != KERN_SUCCESS) {
4247 OSKextLog(/* kext */ NULL,
4248 kOSKextLogErrorLevel |
4249 kOSKextLogIPCFlag,
4250 "Failed to copy log info for request from user space.");
4251 /* Incidental error; we're going to (try to) allow the request
4252 * to succeed. */
4253 } else {
4254 /* 11981737 - clear uninitialized data in last page */
4255 bzero((void *)(buffer + logInfoLength),
4256 (round_page(logInfoLength) - logInfoLength));
4257 memcpy(buffer, logInfo, logInfoLength);
4258 *logInfoOut = buffer;
4259 *logInfoLengthOut = logInfoLength;
4260 }
4261 }
4262 }
4263
4264 result = kOSReturnSuccess;
4265 finish:
4266 return result;
4267 }
4268
4269 #if PRAGMA_MARK
4270 #pragma mark Instance Management Methods
4271 #endif
4272 /*********************************************************************
4273 *********************************************************************/
4274 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)4275 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
4276 {
4277 OSSharedPtr<OSKext> foundKext;
4278
4279 IORecursiveLockLock(sKextLock);
4280 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
4281 IORecursiveLockUnlock(sKextLock);
4282
4283 return foundKext;
4284 }
4285
4286 /*********************************************************************
4287 *********************************************************************/
4288 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)4289 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
4290 {
4291 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
4292 }
4293
4294 /*********************************************************************
4295 *********************************************************************/
4296 OSSharedPtr<OSKext>
lookupDextWithIdentifier(OSString * dextIdentifier,OSData * dextUniqueIdentifier)4297 OSKext::lookupDextWithIdentifier(OSString * dextIdentifier, OSData *dextUniqueIdentifier)
4298 {
4299 OSSharedPtr<OSKext> foundDext;
4300 foundDext.reset();
4301
4302 IORecursiveLockLock(sKextLock);
4303 OSKext *dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIdentifier->getCStringNoCopy()));
4304 if (dext != NULL && dext->isDriverKit()) {
4305 if (dext->dextUniqueID == NULL || dext->dextUniqueID->isEqualTo(dextUniqueIdentifier)) {
4306 foundDext.reset(dext, OSRetain);
4307 }
4308 }
4309 IORecursiveLockUnlock(sKextLock);
4310
4311 return foundDext;
4312 }
4313
4314 /*********************************************************************
4315 *********************************************************************/
4316 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)4317 OSKext::lookupKextWithLoadTag(uint32_t aTag)
4318 {
4319 OSSharedPtr<OSKext> foundKext; // returned
4320 uint32_t i, j;
4321 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4322 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4323
4324 IORecursiveLockLock(sKextLock);
4325
4326 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4327 for (i = 0; i < count[j]; i++) {
4328 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4329 if (thisKext->getLoadTag() == aTag) {
4330 foundKext.reset(thisKext, OSRetain);
4331 goto finish;
4332 }
4333 }
4334 }
4335
4336 finish:
4337 IORecursiveLockUnlock(sKextLock);
4338
4339 return foundKext;
4340 }
4341
4342 /*********************************************************************
4343 *********************************************************************/
4344 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)4345 OSKext::lookupKextWithAddress(vm_address_t address)
4346 {
4347 OSSharedPtr<OSKext> foundKext; // returned
4348 uint32_t count, i;
4349 kmod_info_t *kmod_info;
4350 vm_address_t originalAddress;
4351 #if defined(__arm64__)
4352 uint64_t textExecBase;
4353 size_t textExecSize;
4354 #endif /* defined(__arm64__) */
4355
4356 originalAddress = address;
4357 #if __has_feature(ptrauth_calls)
4358 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
4359 #endif /* __has_feature(ptrauth_calls) */
4360
4361 IORecursiveLockLock(sKextLock);
4362
4363 count = sLoadedKexts->getCount();
4364 for (i = 0; i < count; i++) {
4365 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
4366 if (thisKext == sKernelKext) {
4367 continue;
4368 }
4369 if (thisKext->kmod_info && thisKext->kmod_info->address) {
4370 kmod_info = thisKext->kmod_info;
4371 vm_address_t kext_start = kmod_info->address;
4372 vm_address_t kext_end = kext_start + kmod_info->size;
4373 if ((kext_start <= address) && (address < kext_end)) {
4374 foundKext.reset(thisKext, OSRetain);
4375 goto finish;
4376 }
4377 #if defined(__arm64__)
4378 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
4379
4380 /**
4381 * If the addresses within the Mach-O are unslid, then manually
4382 * slide any addresses coming from the Mach-O before usage.
4383 */
4384 if (thisKext->flags.unslidMachO) {
4385 textExecBase = (uintptr_t) ml_static_slide((vm_offset_t) textExecBase);
4386 }
4387
4388 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4389 foundKext.reset(thisKext, OSRetain);
4390 goto finish;
4391 }
4392 #endif /* defined (__arm64__) */
4393 }
4394 }
4395 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4396 foundKext.reset(sKernelKext, OSRetain);
4397 goto finish;
4398 }
4399 /*
4400 * DriverKit userspace executables do not have a kernel linkedExecutable,
4401 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4402 * here, so use the original address passed to this method.
4403 *
4404 * This is supposed to be used for logging reasons only. When logd
4405 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4406 * remove it here before checking it against the LoadTag.
4407 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4408 */
4409
4410 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4411 count = sLoadedDriverKitKexts->getCount();
4412 for (i = 0; i < count; i++) {
4413 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4414 if (thisKext->getLoadTag() == address) {
4415 foundKext.reset(thisKext, OSRetain);
4416 }
4417 }
4418
4419 finish:
4420 IORecursiveLockUnlock(sKextLock);
4421
4422 return foundKext;
4423 }
4424
4425 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)4426 OSKext::copyKextUUIDForAddress(OSNumber *address)
4427 {
4428 OSSharedPtr<OSData> uuid;
4429 OSSharedPtr<OSKext> kext;
4430
4431 if (!address) {
4432 return NULL;
4433 }
4434
4435 #if CONFIG_MACF
4436 /* Is the calling process allowed to query kext info? */
4437 if (current_task() != kernel_task) {
4438 int macCheckResult = 0;
4439 kauth_cred_t cred = NULL;
4440
4441 cred = kauth_cred_get_with_ref();
4442 macCheckResult = mac_kext_check_query(cred);
4443 kauth_cred_unref(&cred);
4444
4445 if (macCheckResult != 0) {
4446 OSKextLog(/* kext */ NULL,
4447 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4448 "Failed to query kext UUID (MAC policy error 0x%x).",
4449 macCheckResult);
4450 return NULL;
4451 }
4452 }
4453 #endif
4454
4455 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4456 if (slidAddress != 0) {
4457 kext = lookupKextWithAddress(slidAddress);
4458 if (kext) {
4459 uuid = kext->copyTextUUID();
4460 }
4461 }
4462
4463 if (!uuid) {
4464 /*
4465 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4466 * a kext. This might have happened because the log message came from a dext.
4467 *
4468 * Try again with the original address.
4469 */
4470 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4471 if (kext && kext->isDriverKit()) {
4472 uuid = kext->copyTextUUID();
4473 }
4474 }
4475
4476 return uuid;
4477 }
4478
4479 /*********************************************************************
4480 *********************************************************************/
4481 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4482 OSKext::lookupKextWithUUID(uuid_t wanted)
4483 {
4484 OSSharedPtr<OSKext> foundKext; // returned
4485 uint32_t j, i;
4486 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4487 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4488
4489
4490 IORecursiveLockLock(sKextLock);
4491
4492 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4493 for (i = 0; i < count[j]; i++) {
4494 OSKext * thisKext = NULL;
4495
4496 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4497 if (!thisKext) {
4498 continue;
4499 }
4500
4501 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4502 if (!uuid_data) {
4503 continue;
4504 }
4505
4506 uuid_t uuid;
4507 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4508
4509 if (0 == uuid_compare(wanted, uuid)) {
4510 foundKext.reset(thisKext, OSRetain);
4511 goto finish;
4512 }
4513 }
4514 }
4515 finish:
4516 IORecursiveLockUnlock(sKextLock);
4517
4518 return foundKext;
4519 }
4520
4521
4522
4523
4524 /*********************************************************************
4525 *********************************************************************/
4526 /* static */
4527 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4528 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4529 {
4530 bool result = false;
4531 OSKext * foundKext = NULL; // returned
4532
4533 IORecursiveLockLock(sKextLock);
4534
4535 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4536 if (foundKext && foundKext->isLoaded()) {
4537 result = true;
4538 }
4539
4540 IORecursiveLockUnlock(sKextLock);
4541
4542 return result;
4543 }
4544
4545 /*********************************************************************
4546 * xxx - should spawn a separate thread so a kext can safely have
4547 * xxx - itself unloaded.
4548 *********************************************************************/
4549 /* static */
4550 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4551 OSKext::removeKext(
4552 OSKext * aKext,
4553 #if CONFIG_EMBEDDED
4554 __unused
4555 #endif
4556 bool terminateServicesAndRemovePersonalitiesFlag)
4557 {
4558 #if CONFIG_EMBEDDED
4559 if (!aKext->isDriverKit()) {
4560 OSKextLog(aKext,
4561 kOSKextLogErrorLevel |
4562 kOSKextLogKextBookkeepingFlag,
4563 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4564 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4565
4566 return kOSReturnSuccess;
4567 }
4568 #endif /* CONFIG_EMBEDDED */
4569 OSReturn result = kOSKextReturnInUse;
4570 OSKext * checkKext = NULL; // do not release
4571 #if CONFIG_MACF
4572 int macCheckResult = 0;
4573 kauth_cred_t cred = NULL;
4574 #endif
4575
4576 IORecursiveLockLock(sKextLock);
4577
4578 /* If the kext has no identifier, it failed to init
4579 * so isn't in sKextsByID and it isn't loaded.
4580 */
4581 if (!aKext->getIdentifier()) {
4582 result = kOSReturnSuccess;
4583 goto finish;
4584 }
4585
4586 checkKext = OSDynamicCast(OSKext,
4587 sKextsByID->getObject(aKext->getIdentifier()));
4588 if (checkKext != aKext) {
4589 result = kOSKextReturnNotFound;
4590 goto finish;
4591 }
4592
4593 if (aKext->isLoaded() || aKext->isDriverKit()) {
4594 #if CONFIG_MACF
4595 if (current_task() != kernel_task) {
4596 cred = kauth_cred_get_with_ref();
4597 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4598 kauth_cred_unref(&cred);
4599 }
4600
4601 if (macCheckResult != 0) {
4602 result = kOSReturnError;
4603 OSKextLog(aKext,
4604 kOSKextLogErrorLevel |
4605 kOSKextLogKextBookkeepingFlag,
4606 "Failed to remove kext %s (MAC policy error 0x%x).",
4607 aKext->getIdentifierCString(), macCheckResult);
4608 goto finish;
4609 }
4610 #endif
4611
4612 /* make sure there are no resource requests in flight - 17187548 */
4613 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4614 goto finish;
4615 }
4616 if (aKext->flags.unloadUnsupported) {
4617 result = kOSKextReturnInUse;
4618 OSKextLog(aKext,
4619 kOSKextLogErrorLevel |
4620 kOSKextLogKextBookkeepingFlag,
4621 "Can't remove kext %s; unsupported by cache.",
4622 aKext->getIdentifierCString());
4623 goto finish;
4624 }
4625
4626 /* If we are terminating, send the request to the IOCatalogue
4627 * (which will actually call us right back but that's ok we have
4628 * a recursive lock don't you know) but do not ask the IOCatalogue
4629 * to call back with an unload, we'll do that right here.
4630 */
4631 if (terminateServicesAndRemovePersonalitiesFlag) {
4632 result = gIOCatalogue->terminateDriversForModule(
4633 aKext->getIdentifierCString(), /* unload */ false);
4634 if (result != kOSReturnSuccess) {
4635 OSKextLog(aKext,
4636 kOSKextLogErrorLevel |
4637 kOSKextLogKextBookkeepingFlag,
4638 "Can't remove kext %s; services failed to terminate - 0x%x.",
4639 aKext->getIdentifierCString(), result);
4640 goto finish;
4641 }
4642 }
4643
4644 result = aKext->unload();
4645 if (result != kOSReturnSuccess) {
4646 OSKextLog(aKext,
4647 kOSKextLogErrorLevel |
4648 kOSKextLogKextBookkeepingFlag,
4649 "Can't remove kext %s; kext failed to unload - 0x%x.",
4650 aKext->getIdentifierCString(), result);
4651 goto finish;
4652 }
4653 }
4654
4655 /* Remove personalities as requested. This is a bit redundant for a loaded
4656 * kext as IOCatalogue::terminateDriversForModule() removes driver
4657 * personalities, but it doesn't restart matching, which we always want
4658 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4659 * that happens.
4660 */
4661 if (terminateServicesAndRemovePersonalitiesFlag) {
4662 aKext->removePersonalitiesFromCatalog();
4663 }
4664
4665 if (aKext->isInFileset()) {
4666 OSKextLog(aKext,
4667 kOSKextLogProgressLevel |
4668 kOSKextLogKextBookkeepingFlag,
4669 "Fileset kext %s unloaded.",
4670 aKext->getIdentifierCString());
4671 } else {
4672 OSKextLog(aKext,
4673 kOSKextLogProgressLevel |
4674 kOSKextLogKextBookkeepingFlag,
4675 "Removing kext %s.",
4676 aKext->getIdentifierCString());
4677
4678 sKextsByID->removeObject(aKext->getIdentifier());
4679 }
4680 result = kOSReturnSuccess;
4681
4682 finish:
4683 IORecursiveLockUnlock(sKextLock);
4684 return result;
4685 }
4686
4687 /*********************************************************************
4688 *********************************************************************/
4689 /* static */
4690 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4691 OSKext::removeKextWithIdentifier(
4692 const char * kextIdentifier,
4693 bool terminateServicesAndRemovePersonalitiesFlag)
4694 {
4695 OSReturn result = kOSReturnError;
4696
4697 IORecursiveLockLock(sKextLock);
4698
4699 OSKext * aKext = OSDynamicCast(OSKext,
4700 sKextsByID->getObject(kextIdentifier));
4701 if (!aKext) {
4702 result = kOSKextReturnNotFound;
4703 OSKextLog(/* kext */ NULL,
4704 kOSKextLogErrorLevel |
4705 kOSKextLogKextBookkeepingFlag,
4706 "Can't remove kext %s - not found.",
4707 kextIdentifier);
4708 goto finish;
4709 }
4710
4711 result = OSKext::removeKext(aKext,
4712 terminateServicesAndRemovePersonalitiesFlag);
4713
4714 finish:
4715 IORecursiveLockUnlock(sKextLock);
4716
4717 return result;
4718 }
4719
4720 /*********************************************************************
4721 *********************************************************************/
4722 /* static */
4723 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4724 OSKext::removeKextWithLoadTag(
4725 OSKextLoadTag loadTag,
4726 bool terminateServicesAndRemovePersonalitiesFlag)
4727 {
4728 OSReturn result = kOSReturnError;
4729 OSKext * foundKext = NULL;
4730 uint32_t i, j;
4731 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4732 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4733
4734
4735 IORecursiveLockLock(sKextLock);
4736
4737 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4738 for (i = 0; i < count[j]; i++) {
4739 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4740 if (thisKext->loadTag == loadTag) {
4741 foundKext = thisKext;
4742 break;
4743 }
4744 }
4745 }
4746
4747 if (!foundKext) {
4748 result = kOSKextReturnNotFound;
4749 OSKextLog(/* kext */ NULL,
4750 kOSKextLogErrorLevel |
4751 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4752 "Can't remove kext with load tag %d - not found.",
4753 loadTag);
4754 goto finish;
4755 }
4756
4757 result = OSKext::removeKext(foundKext,
4758 terminateServicesAndRemovePersonalitiesFlag);
4759
4760 finish:
4761 IORecursiveLockUnlock(sKextLock);
4762
4763 return result;
4764 }
4765
4766 /*********************************************************************
4767 *********************************************************************/
4768 OSSharedPtr<OSDictionary>
copyKexts(void)4769 OSKext::copyKexts(void)
4770 {
4771 OSSharedPtr<OSDictionary> result;
4772
4773 IORecursiveLockLock(sKextLock);
4774 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4775 IORecursiveLockUnlock(sKextLock);
4776
4777 return result;
4778 }
4779
4780 /*********************************************************************
4781 *********************************************************************/
4782 #define BOOTER_KEXT_PREFIX "Driver-"
4783
4784 typedef struct _DeviceTreeBuffer {
4785 uint32_t paddr;
4786 uint32_t length;
4787 } _DeviceTreeBuffer;
4788
4789 /*********************************************************************
4790 * Create a dictionary of excluded kexts from the given booter data.
4791 *********************************************************************/
4792 /* static */
4793 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4794 OSKext::createExcludeListFromBooterData(
4795 OSDictionary * theDictionary,
4796 OSCollectionIterator * theIterator )
4797 {
4798 OSString * deviceTreeName = NULL; // do not release
4799 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4800 char * booterDataPtr = NULL; // do not release
4801 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4802 char * infoDictAddr = NULL; // do not release
4803 OSSharedPtr<OSObject> parsedXML;
4804 OSDictionary * theInfoDict = NULL; // do not release
4805
4806 theIterator->reset();
4807
4808 /* look for AppleKextExcludeList.kext */
4809 while ((deviceTreeName =
4810 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4811 const char * devTreeNameCString;
4812 OSData * deviceTreeEntry; // do not release
4813 OSString * myBundleID; // do not release
4814
4815 deviceTreeEntry =
4816 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4817 if (!deviceTreeEntry) {
4818 continue;
4819 }
4820
4821 /* Make sure it is a kext */
4822 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4823 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4824 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4825 OSKextLog(NULL,
4826 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4827 "\"%s\" not a kext",
4828 devTreeNameCString);
4829 continue;
4830 }
4831
4832 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4833 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4834 if (!deviceTreeBuffer) {
4835 continue;
4836 }
4837
4838 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4839 if (!booterDataPtr) {
4840 continue;
4841 }
4842
4843 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4844 if (!kextFileInfo->infoDictPhysAddr ||
4845 !kextFileInfo->infoDictLength) {
4846 continue;
4847 }
4848
4849 infoDictAddr = (char *)
4850 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4851 if (!infoDictAddr) {
4852 continue;
4853 }
4854
4855 parsedXML = OSUnserializeXML(infoDictAddr);
4856 if (!parsedXML) {
4857 continue;
4858 }
4859
4860 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4861 if (!theInfoDict) {
4862 continue;
4863 }
4864
4865 myBundleID =
4866 OSDynamicCast(OSString,
4867 theInfoDict->getObject(kCFBundleIdentifierKey));
4868 if (myBundleID &&
4869 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4870 boolean_t updated = updateExcludeList(theInfoDict);
4871 if (!updated) {
4872 /* 25322874 */
4873 panic("Missing OSKextExcludeList dictionary");
4874 }
4875 break;
4876 }
4877 } // while ( (deviceTreeName = ...) )
4878
4879 return;
4880 }
4881
4882 /*********************************************************************
4883 * Create a dictionary of excluded kexts from the given prelink
4884 * info (kernelcache).
4885 *********************************************************************/
4886 /* static */
4887 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4888 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4889 {
4890 OSDictionary * myInfoDict = NULL; // do not release
4891 OSString * myBundleID; // do not release
4892 u_int i;
4893
4894 /* Find the Apple Kext Exclude List. */
4895 for (i = 0; i < theInfoArray->getCount(); i++) {
4896 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4897 if (!myInfoDict) {
4898 continue;
4899 }
4900 myBundleID =
4901 OSDynamicCast(OSString,
4902 myInfoDict->getObject(kCFBundleIdentifierKey));
4903 if (myBundleID &&
4904 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4905 boolean_t updated = updateExcludeList(myInfoDict);
4906 if (!updated) {
4907 /* 25322874 */
4908 panic("Missing OSKextExcludeList dictionary");
4909 }
4910 break;
4911 }
4912 } // for (i = 0; i < theInfoArray->getCount()...
4913
4914 return;
4915 }
4916
4917 /* static */
4918 boolean_t
updateExcludeList(OSDictionary * infoDict)4919 OSKext::updateExcludeList(OSDictionary *infoDict)
4920 {
4921 OSDictionary *myTempDict = NULL; // do not free
4922 OSString *myTempString = NULL; // do not free
4923 OSKextVersion newVersion = 0;
4924 boolean_t updated = false;
4925
4926 if (!infoDict) {
4927 return false;
4928 }
4929
4930 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4931 if (!myTempDict) {
4932 return false;
4933 }
4934
4935 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4936 if (!myTempString) {
4937 return false;
4938 }
4939
4940 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4941 if (newVersion == 0) {
4942 return false;
4943 }
4944
4945 IORecursiveLockLock(sKextLock);
4946
4947 if (newVersion > sExcludeListVersion) {
4948 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4949 sExcludeListVersion = newVersion;
4950 updated = true;
4951 }
4952
4953 IORecursiveLockUnlock(sKextLock);
4954 return updated;
4955 }
4956
4957 #if PRAGMA_MARK
4958 #pragma mark Accessors
4959 #endif
4960
4961 /*********************************************************************
4962 *********************************************************************/
4963 const OSObject *
getBundleExecutable(void)4964 OSKext::getBundleExecutable(void)
4965 {
4966 return infoDict->getObject(kCFBundleExecutableKey);
4967 }
4968
4969 /*********************************************************************
4970 *********************************************************************/
4971 const OSSymbol *
getIdentifier(void)4972 OSKext::getIdentifier(void)
4973 {
4974 return bundleID.get();
4975 }
4976
4977 /*********************************************************************
4978 * A kext must have a bundle identifier to even survive initialization;
4979 * this is guaranteed to exist past then.
4980 *********************************************************************/
4981 const char *
getIdentifierCString(void)4982 OSKext::getIdentifierCString(void)
4983 {
4984 return bundleID->getCStringNoCopy();
4985 }
4986
4987 /*********************************************************************
4988 *********************************************************************/
4989 OSKextVersion
getVersion(void)4990 OSKext::getVersion(void)
4991 {
4992 return version;
4993 }
4994
4995 /*********************************************************************
4996 *********************************************************************/
4997 OSKextVersion
getCompatibleVersion(void)4998 OSKext::getCompatibleVersion(void)
4999 {
5000 return compatibleVersion;
5001 }
5002
5003 /*********************************************************************
5004 *********************************************************************/
5005 bool
isLibrary(void)5006 OSKext::isLibrary(void)
5007 {
5008 return getCompatibleVersion() > 0;
5009 }
5010
5011 /*********************************************************************
5012 *********************************************************************/
5013 bool
isCompatibleWithVersion(OSKextVersion aVersion)5014 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
5015 {
5016 if ((compatibleVersion > -1 && version > -1) &&
5017 (compatibleVersion <= version && aVersion <= version)) {
5018 return true;
5019 }
5020 return false;
5021 }
5022
5023 /*********************************************************************
5024 *********************************************************************/
5025 bool
declaresExecutable(void)5026 OSKext::declaresExecutable(void)
5027 {
5028 if (isDriverKit()) {
5029 return false;
5030 }
5031 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
5032 }
5033
5034 /*********************************************************************
5035 *********************************************************************/
5036 OSData *
getExecutable(void)5037 OSKext::getExecutable(void)
5038 {
5039 OSData * result = NULL;
5040 OSSharedPtr<OSData> extractedExecutable;
5041
5042 if (flags.builtin) {
5043 return sKernelKext->linkedExecutable.get();
5044 }
5045
5046 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
5047 if (result) {
5048 return result;
5049 }
5050
5051 #if CONFIG_KXLD
5052 OSData * mkextExecutableRef = NULL; // do not release
5053 mkextExecutableRef = OSDynamicCast(OSData,
5054 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
5055
5056 if (mkextExecutableRef) {
5057 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
5058 mkextExecutableRef->getBytesNoCopy();
5059 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
5060 if (mkextVersion == MKEXT_VERS_2) {
5061 mkext2_file_entry * fileinfo =
5062 (mkext2_file_entry *)mkextEntryRef->fileinfo;
5063 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
5064 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
5065 extractedExecutable = extractMkext2FileData(
5066 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
5067 compressedSize, fullSize);
5068 } else {
5069 OSKextLog(this, kOSKextLogErrorLevel |
5070 kOSKextLogArchiveFlag,
5071 "Kext %s - unknown mkext version 0x%x for executable.",
5072 getIdentifierCString(), mkextVersion);
5073 }
5074
5075 /* Regardless of success, remove the mkext executable,
5076 * and drop one reference on the mkext. (setExecutable() does not
5077 * replace, it removes, or panics if asked to replace.)
5078 */
5079 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
5080 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
5081
5082 if (extractedExecutable && extractedExecutable->getLength()) {
5083 if (!setExecutable(extractedExecutable.get())) {
5084 goto finish;
5085 }
5086 result = extractedExecutable.get();
5087 } else {
5088 goto finish;
5089 }
5090 }
5091
5092 finish:
5093 #endif // CONFIG_KXLD
5094 return result;
5095 }
5096
5097 /*********************************************************************
5098 *********************************************************************/
5099 bool
isInterface(void)5100 OSKext::isInterface(void)
5101 {
5102 return flags.interface;
5103 }
5104
5105 /*********************************************************************
5106 *********************************************************************/
5107 bool
isKernel(void)5108 OSKext::isKernel(void)
5109 {
5110 return this == sKernelKext;
5111 }
5112
5113 /*********************************************************************
5114 *********************************************************************/
5115 bool
isKernelComponent(void)5116 OSKext::isKernelComponent(void)
5117 {
5118 return flags.kernelComponent ? true : false;
5119 }
5120
5121 /*********************************************************************
5122 *********************************************************************/
5123 bool
isExecutable(void)5124 OSKext::isExecutable(void)
5125 {
5126 return !isKernel() && !isInterface() && declaresExecutable();
5127 }
5128
5129 /*********************************************************************
5130 *********************************************************************/
5131 bool
isSpecialKernelBinary(void)5132 OSKext::isSpecialKernelBinary(void)
5133 {
5134 #if CONFIG_SPTM
5135 return (this->kmod_info) &&
5136 ((this->kmod_info->id == kOSKextSPTMLoadTag) ||
5137 (this->kmod_info->id == kOSKextTXMLoadTag));
5138 #else
5139 return false;
5140 #endif
5141 }
5142
5143 /*********************************************************************
5144 * We might want to check this recursively for all dependencies,
5145 * since a subtree of dependencies could get loaded before we hit
5146 * a dependency that isn't safe-boot-loadable.
5147 *
5148 * xxx - Might want to return false if OSBundleEnableKextLogging or
5149 * OSBundleDebugLevel
5150 * or IOKitDebug is nonzero too (we used to do that, but I don't see
5151 * the point except it's usually development drivers, which might
5152 * cause panics on startup, that have those properties). Heh; could
5153 * use a "kx" boot-arg!
5154 *********************************************************************/
5155 bool
isLoadableInSafeBoot(void)5156 OSKext::isLoadableInSafeBoot(void)
5157 {
5158 bool result = false;
5159 OSString * required = NULL; // do not release
5160
5161 if (isKernel()) {
5162 result = true;
5163 goto finish;
5164 }
5165
5166 if (isDriverKit()) {
5167 result = true;
5168 goto finish;
5169 }
5170
5171 required = OSDynamicCast(OSString,
5172 getPropertyForHostArch(kOSBundleRequiredKey));
5173 if (!required) {
5174 goto finish;
5175 }
5176 if (required->isEqualTo(kOSBundleRequiredRoot) ||
5177 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
5178 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
5179 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
5180 required->isEqualTo(kOSBundleRequiredConsole)) {
5181 result = true;
5182 }
5183
5184 finish:
5185 return result;
5186 }
5187
5188 /*********************************************************************
5189 *********************************************************************/
5190 bool
isPrelinked(void)5191 OSKext::isPrelinked(void)
5192 {
5193 return flags.prelinked ? true : false;
5194 }
5195
5196 /*********************************************************************
5197 *********************************************************************/
5198 bool
isLoaded(void)5199 OSKext::isLoaded(void)
5200 {
5201 return flags.loaded ? true : false;
5202 }
5203
5204 /*********************************************************************
5205 *********************************************************************/
5206 bool
isStarted(void)5207 OSKext::isStarted(void)
5208 {
5209 return flags.started ? true : false;
5210 }
5211
5212 /*********************************************************************
5213 *********************************************************************/
5214 bool
isCPPInitialized(void)5215 OSKext::isCPPInitialized(void)
5216 {
5217 return flags.CPPInitialized;
5218 }
5219
5220 /*********************************************************************
5221 *********************************************************************/
5222 void
setCPPInitialized(bool initialized)5223 OSKext::setCPPInitialized(bool initialized)
5224 {
5225 flags.CPPInitialized = initialized;
5226 }
5227
5228 /*********************************************************************
5229 *********************************************************************/
5230 uint32_t
getLoadTag(void)5231 OSKext::getLoadTag(void)
5232 {
5233 return loadTag;
5234 }
5235
5236 /*********************************************************************
5237 *********************************************************************/
5238 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)5239 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5240 {
5241 if (linkedExecutable) {
5242 *loadSize = linkedExecutable->getLength();
5243
5244 /* If we have a kmod_info struct, calculated the wired size
5245 * from that. Otherwise it's the full load size.
5246 */
5247 if (kmod_info) {
5248 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5249 } else {
5250 *wiredSize = *loadSize;
5251 }
5252 } else {
5253 *wiredSize = 0;
5254 *loadSize = 0;
5255 }
5256 }
5257
5258 /*********************************************************************
5259 *********************************************************************/
5260 OSSharedPtr<OSData>
copyUUID(void)5261 OSKext::copyUUID(void)
5262 {
5263 OSSharedPtr<OSData> result;
5264 OSData * theExecutable = NULL; // do not release
5265 const kernel_mach_header_t * header;
5266
5267 /* An interface kext doesn't have a linked executable with an LC_UUID,
5268 * we create one when it's linked.
5269 */
5270 if (interfaceUUID) {
5271 result = interfaceUUID;
5272 goto finish;
5273 }
5274
5275 if (flags.builtin || isInterface()) {
5276 return sKernelKext->copyUUID();
5277 }
5278
5279 if (isDriverKit() && infoDict) {
5280 return driverKitUUID;
5281 }
5282
5283 /* For real kexts, try to get the UUID from the linked executable,
5284 * or if is hasn't been linked yet, the unrelocated executable.
5285 */
5286 theExecutable = linkedExecutable.get();
5287 if (!theExecutable) {
5288 theExecutable = getExecutable();
5289 }
5290
5291 if (!theExecutable) {
5292 goto finish;
5293 }
5294
5295 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5296 result = copyMachoUUID(header);
5297
5298 finish:
5299 return result;
5300 }
5301
5302 /*********************************************************************
5303 *********************************************************************/
5304 OSSharedPtr<OSData>
copyTextUUID(void)5305 OSKext::copyTextUUID(void)
5306 {
5307 if (flags.builtin) {
5308 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
5309 }
5310 return copyUUID();
5311 }
5312
5313 /*********************************************************************
5314 *********************************************************************/
5315 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)5316 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5317 {
5318 OSSharedPtr<OSData> result;
5319 const struct load_command * load_cmd = NULL;
5320 const struct uuid_command * uuid_cmd = NULL;
5321 uint32_t i;
5322
5323 load_cmd = (const struct load_command *)&header[1];
5324
5325 if (header->magic != MH_MAGIC_KERNEL) {
5326 OSKextLog(NULL,
5327 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5328 "%s: bad header %p",
5329 __func__,
5330 header);
5331 goto finish;
5332 }
5333
5334 for (i = 0; i < header->ncmds; i++) {
5335 if (load_cmd->cmd == LC_UUID) {
5336 uuid_cmd = (struct uuid_command *)load_cmd;
5337 result = OSData::withValue(uuid_cmd->uuid);
5338 goto finish;
5339 }
5340 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5341 }
5342
5343 finish:
5344 return result;
5345 }
5346
5347 void
setDriverKitUUID(OSData * uuid)5348 OSKext::setDriverKitUUID(OSData *uuid)
5349 {
5350 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5351 OSSafeReleaseNULL(uuid);
5352 }
5353 }
5354
5355 OSData *
getDextUniqueID(void)5356 OSKext::getDextUniqueID(void)
5357 {
5358 if (isDriverKit() && dextUniqueID != NULL) {
5359 return dextUniqueID.get();
5360 }
5361
5362 return NULL;
5363 }
5364
5365 /*
5366 * In case a DextUniqueID exists this function returns
5367 * an allocated char* with the hexadecimal represantition of
5368 * DextUniqueID.
5369 * The returned pinter needs to be freed with kfree_data, the
5370 * size of the allocated buffer is returned in size.
5371 */
5372 static const char *
getDextUniqueIDCString(OSData * dextUniqueID,unsigned int * size)5373 getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5374 {
5375 if (dextUniqueID != NULL) {
5376 char *s_buffer = NULL;
5377 unsigned int d_length = dextUniqueID->getLength();
5378 /*
5379 * We are converting in hex, so for every byte we will have
5380 * 2 hex chars and one last \0.
5381 */
5382 unsigned int s_length = d_length * 2 + 1;
5383 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5384
5385 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5386 int cpos = 0;
5387 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5388 int ret = snprintf(s_buffer + cpos, s_length - cpos - 1, "%02X", uid[i]);
5389 if (ret <= 0) {
5390 break;
5391 }
5392 cpos += ret;
5393 }
5394 *size = s_length;
5395
5396 return s_buffer;
5397 }
5398
5399 return NULL;
5400 }
5401
5402 /*
5403 * Atomically swaps the olddext with newdext.
5404 * olddext will be unloaded, so it might be freed
5405 * after this call unless it was previously retained.
5406 *
5407 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5408 */
5409 void
replaceDextInternal(OSKext * olddext,OSKext * newdext)5410 OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5411 {
5412 OSReturn result;
5413 const OSSymbol * dextID = olddext->getIdentifier();
5414 OSData * oldDextUniqueIdentifier = olddext->getDextUniqueID();
5415 OSSharedPtr<OSArray> new_personalities;
5416 OSSharedPtr<OSString> kextIdentifier;
5417 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5418 assert(lock_held);
5419
5420 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5421 dextID->retain();
5422
5423 if (newdext != NULL) {
5424 __assert_only bool eq = dextID->isEqualTo(newdext->getIdentifier());
5425 assert(eq);
5426 }
5427
5428 if (newdext != NULL) {
5429 /*
5430 * Swap the catalog personalities.
5431 */
5432 new_personalities = newdext->copyPersonalitiesArray();
5433 olddext->updatePersonalitiesInCatalog(new_personalities.get());
5434 }
5435
5436 if (NULL != oldDextUniqueIdentifier) {
5437 oldDextUniqueIdentifier->retain();
5438 }
5439
5440 /*
5441 * Unload the dext.
5442 */
5443 result = olddext->unload();
5444 if (result != kOSReturnSuccess) {
5445 OSKextLog(NULL,
5446 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5447 "Cannot unload dext for upgrade %s: %d\n",
5448 dextID->getCStringNoCopy(), result);
5449 }
5450
5451 if (newdext != NULL) {
5452 /*
5453 * Swap the dexts on the OSKext dictionary.
5454 * This might free the dext.
5455 */
5456 sKextsByID->setObject(dextID, newdext);
5457 } else {
5458 /*
5459 * Remove the old dext
5460 */
5461 removeKext(olddext, true);
5462 }
5463
5464 /*
5465 * Inform userspace.
5466 */
5467 if (newdext != NULL) {
5468 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), newdext->getDextUniqueID());
5469 if (result != kOSReturnSuccess) {
5470 OSKextLog(NULL,
5471 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5472 "Cannot send upgrade notification for %s\n",
5473 dextID->getCStringNoCopy());
5474 }
5475 } else {
5476 // notify dext removal
5477 queueKextNotification(kKextRequestPredicateUnloadNotification,
5478 OSDynamicCast(OSString, dextID), oldDextUniqueIdentifier);
5479 }
5480
5481 OSSafeReleaseNULL(dextID);
5482 OSSafeReleaseNULL(oldDextUniqueIdentifier);
5483 }
5484
5485 /*
5486 * To be called with sKextLock held.
5487 * NOTE: this could unload the olddext.
5488 */
5489 bool
upgradeDext(OSKext * olddext,OSKext * newdext)5490 OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5491 {
5492 const char * dextIDCS = newdext->getIdentifierCString();
5493 __assert_only bool old_isDext = olddext->isDriverKit();
5494 __assert_only bool new_isDext = newdext->isDriverKit();
5495 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5496
5497 assert(old_isDext && new_isDext);
5498 assert(lock_held);
5499
5500 /*
5501 * New dext and old dext have the same ID.
5502 * We use this ID as key on the OSKext
5503 * dictionarys/arrays.
5504 */
5505 const OSSymbol * dextID = newdext->getIdentifier();
5506 __assert_only bool eq = dextID->isEqualTo(olddext->getIdentifier());
5507 assert(eq);
5508
5509 /*
5510 * Set this OSKect as to update.
5511 * Note that this flags will never be removed once set.
5512 * When a OSKext is marked, it will be substitued by a new
5513 * OSKext, and every subsystem having a reference on this
5514 * OSKext need to know they have check if they can use
5515 * this OSKext or look for a new one.
5516 */
5517 olddext->flags.dextToReplace = 1;
5518
5519 /*
5520 * Check if the current OSKext has any
5521 * userspace processes launched.
5522 * In this case we cannot upgrade and we have to
5523 * delay the upgrade until all processes
5524 * are done.
5525 */
5526 if (olddext->dextLaunchedCount == 0) {
5527 /*
5528 * Be sure that if there are no launched dexts, no
5529 * pending upgrades exist.
5530 * This is an error if it happens, as the decrement
5531 * should have removed the dext from sDriverKitToUpgradeByID
5532 * in case it reached 0.
5533 */
5534 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(dextID);
5535 if (pending_upgdare != NULL) {
5536 OSKextLog(NULL,
5537 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5538 "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5539 dextIDCS);
5540 goto out;
5541 }
5542
5543 replaceDextInternal(olddext, newdext);
5544 return true;
5545 }
5546
5547 out:
5548
5549 /*
5550 * Delay the upgrade.
5551 * Make the new dext available in sDriverKitToUpgradeByID.
5552 * In case there was already a pending upgrade, this will
5553 * overwrite it.
5554 */
5555 sDriverKitToUpgradeByID->setObject(dextID, newdext);
5556 return false;
5557 }
5558
5559 /*
5560 * To be called with sKextLock held.
5561 * NOTE: this could unload the dext.
5562 */
5563 bool
removeDext(OSKext * dext)5564 OSKext::removeDext(OSKext *dext)
5565 {
5566 __assert_only bool dext_isDext = dext->isDriverKit();
5567 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5568 IOReturn result;
5569
5570 assert(dext_isDext);
5571 assert(lock_held);
5572
5573 /*
5574 * Set this OSKext to be unloaded when all running instances exit.
5575 */
5576 dext->flags.dextToReplace = 1;
5577
5578 result = gIOCatalogue->terminateDriversForModule(
5579 dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5580 if (result != kOSReturnSuccess) {
5581 OSKextLog(dext,
5582 kOSKextLogErrorLevel |
5583 kOSKextLogKextBookkeepingFlag,
5584 "%s services failed to terminate - 0x%x.",
5585 dext->getIdentifierCString(), result);
5586 }
5587
5588 dext->removePersonalitiesFromCatalog();
5589 sDriverKitToUpgradeByID->removeObject(dext->getIdentifier());
5590
5591 /*
5592 * Check if the current OSKext has any
5593 * userspace processes launched.
5594 * In this case we cannot unload and we have to
5595 * delay the unload until all processes
5596 * are done.
5597 */
5598 if (dext->dextLaunchedCount == 0) {
5599 replaceDextInternal(dext, NULL);
5600 return true;
5601 }
5602
5603 return false;
5604 }
5605
5606 bool
incrementDextLaunchCount(OSKext * dext,OSData * dextUniqueIDToMatch)5607 OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5608 {
5609 bool ret = false;
5610 __assert_only bool isDext = dext->isDriverKit();
5611 assert(isDext);
5612
5613 const char * dextIDCS = dext->getIdentifierCString();
5614 OSData *myDextUniqueID = dext->getDextUniqueID();
5615
5616 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5617 OSKextLog(dext,
5618 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5619 "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5620 dextIDCS);
5621 return ret;
5622 }
5623
5624 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5625 const char *dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5626 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueIDToMatch, &dextUniqueIDToMatchCStringSize);
5627 assert(dextUniqueIDCString != NULL);
5628 assert(dextUniqueIDToMatchCString != NULL);
5629
5630 IORecursiveLockLock(sKextLock);
5631
5632 /*
5633 * Check that the dext we are referencing is the same
5634 * looked for the match.
5635 */
5636 if (myDextUniqueID->isEqualTo(dextUniqueIDToMatch)) {
5637 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5638 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5639 OSKextLog(dext,
5640 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5641 "Too many dexts launched for %s UniqueID %s\n",
5642 dextIDCS, dextUniqueIDCString);
5643 } else {
5644 dext->dextLaunchedCount++;
5645 ret = true;
5646
5647 OSKextLog(dext,
5648 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5649 "New dext launched for %s UniqueID %s",
5650 dextIDCS, dextUniqueIDCString);
5651 }
5652 } else {
5653 OSKextLog(dext,
5654 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5655 "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5656 dextIDCS, dextUniqueIDCString);
5657 }
5658 } else {
5659 OSKextLog(dext,
5660 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5661 "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5662 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5663 }
5664
5665 IORecursiveLockUnlock(sKextLock);
5666
5667 if (dextUniqueIDCString != NULL) {
5668 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5669 }
5670 if (dextUniqueIDToMatchCString != NULL) {
5671 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5672 }
5673 return ret;
5674 }
5675
5676 bool
decrementDextLaunchCount(OSString * bundleID)5677 OSKext::decrementDextLaunchCount(OSString *bundleID)
5678 {
5679 bool ret = false;
5680 const char * dextIDCS;
5681 OSData *myDextUniqueID;
5682 unsigned int dextUniqueIDCStringSize = 0;
5683 const char * dextUniqueIDCString = NULL;
5684 OSKext* dext = NULL;
5685
5686 if (!bundleID) {
5687 return ret;
5688 }
5689 dextIDCS = bundleID->getCStringNoCopy();
5690
5691 IORecursiveLockLock(sKextLock);
5692
5693 /*
5694 * Look for the dext with the bundle it. This
5695 * call is triggered only if a previous increment was
5696 * performed. It means that the dext could have not
5697 * been upgraded as its dextLaunchedCount was at least 1.
5698 * Because of this it still needs to be available
5699 * in sKextsByID.
5700 */
5701 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5702 if (!dext || !dext->isDriverKit()) {
5703 OSKextLog(NULL,
5704 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5705 "Cannot find dext for %s, cannot decrement dext launches\n",
5706 dextIDCS);
5707
5708 goto out_locked;
5709 }
5710
5711 myDextUniqueID = dext->getDextUniqueID();
5712 if (!myDextUniqueID) {
5713 OSKextLog(dext,
5714 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5715 "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5716 dextIDCS);
5717
5718 goto out_locked;
5719 }
5720 dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5721 assert(dextUniqueIDCString != NULL);
5722
5723 if (dext->dextLaunchedCount == 0) {
5724 OSKextLog(dext,
5725 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5726 "Over decrementing dext launch for %s UniqueID %s\n",
5727 dextIDCS, dextUniqueIDCString);
5728
5729 goto out_locked;
5730 }
5731
5732 dext->dextLaunchedCount--;
5733
5734 OSKextLog(dext,
5735 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5736 "Dext terminated for %s UniqueID %s",
5737 dextIDCS, dextUniqueIDCString);
5738
5739 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5740 /*
5741 * Find the upgraded dext.
5742 */
5743 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5744 if (newdext) {
5745 OSKextLog(dext,
5746 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5747 "Dext upgrade for %s UniqueID %s",
5748 dextIDCS, dextUniqueIDCString);
5749 replaceDextInternal(dext, newdext);
5750 /* NOTE dext could have been freed past this point */
5751
5752 sDriverKitToUpgradeByID->removeObject(dextIDCS);
5753 } else {
5754 OSKextLog(dext,
5755 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5756 "Dext unload for %s UniqueID %s",
5757 dextIDCS, dextUniqueIDCString);
5758 replaceDextInternal(dext, NULL);
5759 }
5760
5761 ret = true;
5762 }
5763 out_locked:
5764 IORecursiveLockUnlock(sKextLock);
5765
5766 if (dextUniqueIDCString != NULL) {
5767 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5768 }
5769
5770 return ret;
5771 }
5772
5773 /*********************************************************************
5774 *********************************************************************/
5775 #if defined (__arm__)
5776 #include <arm/arch.h>
5777 #endif
5778
5779 #if defined (__x86_64__)
5780 #define ARCHNAME "x86_64"
5781 #elif defined (__arm64__)
5782 #define ARCHNAME "arm64"
5783 #elif defined (__arm__)
5784
5785 #if defined (__ARM_ARCH_7S__)
5786 #define ARCHNAME "armv7s"
5787 #elif defined (__ARM_ARCH_7F__)
5788 #define ARCHNAME "armv7f"
5789 #elif defined (__ARM_ARCH_7K__)
5790 #define ARCHNAME "armv7k"
5791 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5792 #define ARCHNAME "armv7"
5793 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5794 #define ARCHNAME "armv6"
5795 #endif
5796
5797 #elif defined (__arm64__)
5798 #define ARCHNAME "arm64"
5799 #else
5800 #error architecture not supported
5801 #endif
5802
5803 #define ARCH_SEPARATOR_CHAR '_'
5804
5805 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)5806 makeHostArchKey(const char * key, size_t * keySizeOut)
5807 {
5808 char * result = NULL;
5809 size_t keyLength = strlen(key);
5810 size_t keySize;
5811
5812 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5813 */
5814 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5815 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5816
5817 if (!result) {
5818 goto finish;
5819 }
5820 strlcpy(result, key, keySize);
5821 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5822 result[keyLength] = '\0';
5823 strlcat(result, ARCHNAME, keySize);
5824 *keySizeOut = keySize;
5825
5826 finish:
5827 return result;
5828 }
5829
5830 /*********************************************************************
5831 *********************************************************************/
5832 OSObject *
getPropertyForHostArch(const char * key)5833 OSKext::getPropertyForHostArch(const char * key)
5834 {
5835 OSObject * result = NULL;// do not release
5836 size_t hostArchKeySize = 0;
5837 char * hostArchKey = NULL;// must kfree
5838
5839 if (!key || !infoDict) {
5840 goto finish;
5841 }
5842
5843 /* Some properties are not allowed to be arch-variant:
5844 * - Any CFBundle... property.
5845 * - OSBundleIsInterface.
5846 * - OSKernelResource.
5847 */
5848 if (STRING_HAS_PREFIX(key, "OS") ||
5849 STRING_HAS_PREFIX(key, "IO")) {
5850 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
5851 if (!hostArchKey) {
5852 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5853 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5854 "Allocation failure.");
5855 goto finish;
5856 }
5857 result = infoDict->getObject(hostArchKey);
5858 }
5859
5860 if (!result) {
5861 result = infoDict->getObject(key);
5862 }
5863
5864 finish:
5865 if (hostArchKey) {
5866 kfree_data(hostArchKey, hostArchKeySize);
5867 }
5868 return result;
5869 }
5870
5871 #if PRAGMA_MARK
5872 #pragma mark Load/Start/Stop/Unload
5873 #endif
5874
5875 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5876
5877 /*********************************************************************
5878 * sExcludeListByID is a dictionary with keys / values of:
5879 * key = bundleID string of kext we will not allow to load
5880 * value = version string(s) of the kext that is to be denied loading.
5881 * The version strings can be comma delimited. For example if kext
5882 * com.foocompany.fookext has two versions that we want to deny
5883 * loading then the version strings might look like:
5884 * 1.0.0, 1.0.1
5885 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5886 * not load the kext.
5887 *
5888 * Value may also be in the form of "LE 2.0.0" (version numbers
5889 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5890 * number less than 2.0.0 will not load)
5891 *
5892 * NOTE - we cannot use the characters "<=" or "<" because we have code
5893 * that serializes plists and treats '<' as a special character.
5894 *********************************************************************/
5895 bool
isInExcludeList(void)5896 OSKext::isInExcludeList(void)
5897 {
5898 OSString * versionString = NULL; // do not release
5899 char * versionCString = NULL; // do not free
5900 size_t i;
5901 boolean_t wantLessThan = false;
5902 boolean_t wantLessThanEqualTo = false;
5903 boolean_t isInExcludeList = true;
5904 char myBuffer[32];
5905
5906 IORecursiveLockLock(sKextLock);
5907
5908 if (!sExcludeListByID) {
5909 isInExcludeList = false;
5910 } else {
5911 /* look up by bundleID in our exclude list and if found get version
5912 * string (or strings) that we will not allow to load
5913 */
5914 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5915 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5916 isInExcludeList = false;
5917 }
5918 }
5919
5920 IORecursiveLockUnlock(sKextLock);
5921
5922 if (!isInExcludeList) {
5923 return false;
5924 }
5925
5926 /* parse version strings */
5927 versionCString = (char *) versionString->getCStringNoCopy();
5928
5929 /* look for "LT" or "LE" form of version string, must be in first two
5930 * positions.
5931 */
5932 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5933 wantLessThan = true;
5934 versionCString += 2;
5935 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5936 wantLessThanEqualTo = true;
5937 versionCString += 2;
5938 }
5939
5940 for (i = 0; *versionCString != 0x00; versionCString++) {
5941 /* skip whitespace */
5942 if (isWhiteSpace(*versionCString)) {
5943 continue;
5944 }
5945
5946 /* peek ahead for version string separator or null terminator */
5947 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5948 /* OK, we have a version string */
5949 myBuffer[i++] = *versionCString;
5950 myBuffer[i] = 0x00;
5951
5952 OSKextVersion excludeVers;
5953 excludeVers = OSKextParseVersionString(myBuffer);
5954
5955 if (wantLessThanEqualTo) {
5956 if (version <= excludeVers) {
5957 return true;
5958 }
5959 } else if (wantLessThan) {
5960 if (version < excludeVers) {
5961 return true;
5962 }
5963 } else if (version == excludeVers) {
5964 return true;
5965 }
5966
5967 /* reset for the next (if any) version string */
5968 i = 0;
5969 wantLessThan = false;
5970 wantLessThanEqualTo = false;
5971 } else {
5972 /* save valid version character */
5973 myBuffer[i++] = *versionCString;
5974
5975 /* make sure bogus version string doesn't overrun local buffer */
5976 if (i >= sizeof(myBuffer)) {
5977 break;
5978 }
5979 }
5980 }
5981
5982 return false;
5983 }
5984
5985 /*********************************************************************
5986 * sNonLoadableKextsByID is a dictionary with keys / values of:
5987 * key = bundleID string of kext we will not allow to load
5988 * value = boolean (true == loadable, false == not loadable)
5989 *
5990 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5991 * i.e., the value for the kext's bundleID will be false. All kexts in
5992 * the primary and system KCs will always be marked as "loadable."
5993 *
5994 * This list ultimately comes from kexts which have been uninstalled
5995 * in user space by deleting the kext from disk, but which have not
5996 * yet been removed from the AuxKC. Because the user could choose to
5997 * re-install the exact same version of the kext, we need to keep
5998 * a dictionary of boolean values so that user space only needs to
5999 * keep a simple list of "uninstalled" or "missing" bundles. When
6000 * a bundle is re-installed, the iokit daemon can use the
6001 * AucKCBundleAvailable predicate to set the individual kext's
6002 * availability to true.
6003 *********************************************************************/
6004 bool
isLoadable(void)6005 OSKext::isLoadable(void)
6006 {
6007 bool isLoadable = true;
6008
6009 if (kc_type != KCKindAuxiliary) {
6010 /* this filtering only applies to kexts in the auxkc */
6011 return true;
6012 }
6013
6014 IORecursiveLockLock(sKextLock);
6015
6016 if (sNonLoadableKextsByID) {
6017 /* look up by bundleID in our exclude list and if found get version
6018 * string (or strings) that we will not allow to load
6019 */
6020 OSBoolean *loadableVal;
6021 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
6022 if (loadableVal && !loadableVal->getValue()) {
6023 isLoadable = false;
6024 }
6025 }
6026 IORecursiveLockUnlock(sKextLock);
6027
6028 return isLoadable;
6029 }
6030
6031 /*********************************************************************
6032 *********************************************************************/
6033 /* static */
6034 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6035 OSKext::loadKextWithIdentifier(
6036 const char * kextIdentifierCString,
6037 Boolean allowDeferFlag,
6038 Boolean delayAutounloadFlag,
6039 OSKextExcludeLevel startOpt,
6040 OSKextExcludeLevel startMatchingOpt,
6041 OSArray * personalityNames)
6042 {
6043 OSReturn result = kOSReturnError;
6044 OSSharedPtr<OSString> kextIdentifier;
6045
6046 kextIdentifier = OSString::withCString(kextIdentifierCString);
6047 if (!kextIdentifier) {
6048 result = kOSKextReturnNoMemory;
6049 goto finish;
6050 }
6051 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
6052 NULL /* kextRef */,
6053 allowDeferFlag, delayAutounloadFlag,
6054 startOpt, startMatchingOpt, personalityNames);
6055
6056 finish:
6057 return result;
6058 }
6059
6060 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6061 OSKext::loadKextWithIdentifier(
6062 OSString * kextIdentifier,
6063 OSSharedPtr<OSObject> &kextRef,
6064 Boolean allowDeferFlag,
6065 Boolean delayAutounloadFlag,
6066 OSKextExcludeLevel startOpt,
6067 OSKextExcludeLevel startMatchingOpt,
6068 OSArray * personalityNames)
6069 {
6070 OSObject * kextRefRaw = NULL;
6071 OSReturn result;
6072
6073 result = loadKextWithIdentifier(kextIdentifier,
6074 &kextRefRaw,
6075 allowDeferFlag,
6076 delayAutounloadFlag,
6077 startOpt,
6078 startMatchingOpt,
6079 personalityNames);
6080 if ((kOSReturnSuccess == result) && kextRefRaw) {
6081 kextRef.reset(kextRefRaw, OSNoRetain);
6082 }
6083 return result;
6084 }
6085
6086 /*********************************************************************
6087 *********************************************************************/
6088 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6089 OSKext::loadKextWithIdentifier(
6090 OSString * kextIdentifier,
6091 OSObject ** kextRef,
6092 Boolean allowDeferFlag,
6093 Boolean delayAutounloadFlag,
6094 OSKextExcludeLevel startOpt,
6095 OSKextExcludeLevel startMatchingOpt,
6096 OSArray * personalityNames)
6097 {
6098 OSReturn result = kOSReturnError;
6099 OSReturn pingResult = kOSReturnError;
6100 OSKext * theKext = NULL; // do not release
6101 OSSharedPtr<OSDictionary> loadRequest;
6102 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6103
6104 if (kextRef) {
6105 *kextRef = NULL;
6106 }
6107
6108 IORecursiveLockLock(sKextLock);
6109
6110 if (!kextIdentifier) {
6111 result = kOSKextReturnInvalidArgument;
6112 goto finish;
6113 }
6114
6115 OSKext::recordIdentifierRequest(kextIdentifier);
6116
6117 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6118 if (!theKext) {
6119 if (!allowDeferFlag) {
6120 OSKextLog(/* kext */ NULL,
6121 kOSKextLogErrorLevel |
6122 kOSKextLogLoadFlag,
6123 "Can't load kext %s - not found.",
6124 kextIdentifier->getCStringNoCopy());
6125 goto finish;
6126 }
6127
6128 if (!sKernelRequestsEnabled) {
6129 OSKextLog(theKext,
6130 kOSKextLogErrorLevel |
6131 kOSKextLogLoadFlag,
6132 "Can't load kext %s - requests to user space are disabled.",
6133 kextIdentifier->getCStringNoCopy());
6134 result = kOSKextReturnDisabled;
6135 goto finish;
6136 }
6137
6138 /* Create a new request unless one is already sitting
6139 * in sKernelRequests for this bundle identifier
6140 */
6141 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6142 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6143 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
6144 loadRequest);
6145 if (result != kOSReturnSuccess) {
6146 goto finish;
6147 }
6148 if (!_OSKextSetRequestArgument(loadRequest.get(),
6149 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6150 result = kOSKextReturnNoMemory;
6151 goto finish;
6152 }
6153 if (!sKernelRequests->setObject(loadRequest.get())) {
6154 result = kOSKextReturnNoMemory;
6155 goto finish;
6156 }
6157
6158 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6159 result = kOSKextReturnNoMemory;
6160 goto finish;
6161 }
6162
6163 OSKextLog(theKext,
6164 kOSKextLogDebugLevel |
6165 kOSKextLogLoadFlag,
6166 "Kext %s not found; queued load request to user space.",
6167 kextIdentifier->getCStringNoCopy());
6168 }
6169
6170 pingResult = OSKext::pingIOKitDaemon();
6171 if (pingResult == kOSKextReturnDisabled) {
6172 OSKextLog(/* kext */ NULL,
6173 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
6174 kOSKextLogLoadFlag,
6175 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
6176 kextIdentifier->getCStringNoCopy());
6177 }
6178
6179 result = kOSKextReturnDeferred;
6180 goto finish;
6181 }
6182
6183 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
6184
6185 if (result != kOSReturnSuccess) {
6186 OSKextLog(theKext,
6187 kOSKextLogErrorLevel |
6188 kOSKextLogLoadFlag,
6189 "Failed to load kext %s (error 0x%x).",
6190 kextIdentifier->getCStringNoCopy(), (int)result);
6191
6192 if (theKext->kc_type == KCKindUnknown) {
6193 OSKext::removeKext(theKext,
6194 /* terminateService/removePersonalities */ true);
6195 }
6196 goto finish;
6197 }
6198
6199 if (delayAutounloadFlag) {
6200 OSKextLog(theKext,
6201 kOSKextLogProgressLevel |
6202 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6203 "Setting delayed autounload for %s.",
6204 kextIdentifier->getCStringNoCopy());
6205 theKext->flags.delayAutounload = 1;
6206 }
6207
6208 finish:
6209 if ((kOSReturnSuccess == result) && kextRef) {
6210 *kextRef = theKext;
6211 theKext->matchingRefCount++;
6212 theKext->retain();
6213 }
6214
6215 IORecursiveLockUnlock(sKextLock);
6216
6217 return result;
6218 }
6219
6220 /*********************************************************************
6221 *********************************************************************/
6222 /* static */
6223 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)6224 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
6225 {
6226 OSReturn result = kOSReturnError;
6227
6228 OSBoolean *delayAutounloadBool = NULL; // do not release
6229 OSNumber *startKextExcludeNum = NULL; // do not release
6230 OSNumber *startMatchingExcludeNum = NULL; // do not release
6231 OSArray *personalityNames = NULL; // do not release
6232
6233 /*
6234 * Default values for these options:
6235 * regular autounload behavior
6236 * start the kext
6237 * send all personalities to the catalog
6238 */
6239 Boolean delayAutounload = false;
6240 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
6241 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
6242
6243 IORecursiveLockLock(sKextLock);
6244
6245 OSKextLog(/* kext */ NULL,
6246 kOSKextLogDebugLevel |
6247 kOSKextLogIPCFlag,
6248 "Received kext KC load request from user space.");
6249
6250 /* Regardless of processing, the fact that we have gotten here means some
6251 * user-space program is up and talking to us, so we'll switch our kext
6252 * registration to reflect that.
6253 */
6254 if (!sUserLoadsActive) {
6255 OSKextLog(/* kext */ NULL,
6256 kOSKextLogProgressLevel |
6257 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6258 "Switching to late startup (user-space) kext loading policy.");
6259 sUserLoadsActive = true;
6260 }
6261
6262 delayAutounloadBool = OSDynamicCast(OSBoolean,
6263 _OSKextGetRequestArgument(requestDict,
6264 kKextRequestArgumentDelayAutounloadKey));
6265 startKextExcludeNum = OSDynamicCast(OSNumber,
6266 _OSKextGetRequestArgument(requestDict,
6267 kKextRequestArgumentStartExcludeKey));
6268 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6269 _OSKextGetRequestArgument(requestDict,
6270 kKextRequestArgumentStartMatchingExcludeKey));
6271 personalityNames = OSDynamicCast(OSArray,
6272 _OSKextGetRequestArgument(requestDict,
6273 kKextRequestArgumentPersonalityNamesKey));
6274
6275 if (delayAutounloadBool) {
6276 delayAutounload = delayAutounloadBool->getValue();
6277 }
6278 if (startKextExcludeNum) {
6279 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6280 }
6281 if (startMatchingExcludeNum) {
6282 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6283 }
6284
6285 OSKextLog(/* kext */ NULL,
6286 kOSKextLogProgressLevel |
6287 kOSKextLogIPCFlag,
6288 "Received request from user space to load KC kext %s.",
6289 theKext->getIdentifierCString());
6290
6291 /* this could be in the Auxiliary KC, so record the load request */
6292 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6293
6294 /*
6295 * Load the kext
6296 */
6297 result = theKext->load(startKextExcludeLevel,
6298 startMatchingExcludeLevel, personalityNames);
6299
6300 if (result != kOSReturnSuccess) {
6301 OSKextLog(theKext,
6302 kOSKextLogErrorLevel |
6303 kOSKextLogLoadFlag,
6304 "Failed to load kext %s (error 0x%x).",
6305 theKext->getIdentifierCString(), (int)result);
6306
6307 OSKext::removeKext(theKext,
6308 /* terminateService/removePersonalities */ true);
6309 goto finish;
6310 } else {
6311 OSKextLog(theKext,
6312 kOSKextLogProgressLevel |
6313 kOSKextLogLoadFlag,
6314 "Kext %s Loaded successfully from %s KC",
6315 theKext->getIdentifierCString(), theKext->getKCTypeString());
6316 }
6317
6318 if (delayAutounload) {
6319 OSKextLog(theKext,
6320 kOSKextLogProgressLevel |
6321 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6322 "Setting delayed autounload for %s.",
6323 theKext->getIdentifierCString());
6324 theKext->flags.delayAutounload = 1;
6325 }
6326
6327 finish:
6328 IORecursiveLockUnlock(sKextLock);
6329
6330 return result;
6331 }
6332
6333 /*********************************************************************
6334 *********************************************************************/
6335 /* static */
6336 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)6337 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6338 {
6339 OSReturn result = kOSReturnError;
6340 OSDictionary *anInfoDict = NULL; // do not release
6341
6342 anInfoDict = OSDynamicCast(OSDictionary,
6343 _OSKextGetRequestArgument(requestDict,
6344 kKextRequestArgumentCodelessInfoKey));
6345 if (anInfoDict == NULL) {
6346 OSKextLog(/* kext */ NULL,
6347 kOSKextLogErrorLevel |
6348 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6349 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6350 kextIdentifier->getCStringNoCopy());
6351 return kOSKextReturnInvalidArgument;
6352 }
6353
6354 IORecursiveLockLock(sKextLock);
6355
6356 OSKextLog(/* kext */ NULL,
6357 kOSKextLogProgressLevel |
6358 kOSKextLogIPCFlag,
6359 "Received request from user space to load codeless kext %s.",
6360 kextIdentifier->getCStringNoCopy());
6361
6362 {
6363 // instantiate a new kext, and don't hold a reference
6364 // (the kext subsystem will hold one implicitly)
6365 OSKextInitResult ret;
6366 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, &ret);
6367 if (!newKext) {
6368 /*
6369 * We might have failed to create a new OSKext
6370 * because the old one should still be used.
6371 * Check if that is the case.
6372 */
6373 if (ret != kOSKextInitFailure) {
6374 result = kOSReturnSuccess;
6375 goto finish;
6376 }
6377 OSKextLog(/* kext */ NULL,
6378 kOSKextLogErrorLevel |
6379 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6380 "Could not instantiate codeless kext.");
6381 result = kOSKextReturnNotLoadable;
6382 goto finish;
6383 }
6384 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
6385 OSKextLog(/* kext */ NULL,
6386 kOSKextLogErrorLevel |
6387 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6388 "Codeless kext identifiers don't match '%s' != '%s'",
6389 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6390
6391 OSKext::removeKext(newKext.get(), false);
6392 result = kOSKextReturnInvalidArgument;
6393 goto finish;
6394 }
6395
6396 /* Record the request for the codeless kext */
6397 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6398
6399 result = kOSReturnSuccess;
6400 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6401 result = newKext->sendPersonalitiesToCatalog(true, NULL);
6402 }
6403
6404 finish:
6405 IORecursiveLockUnlock(sKextLock);
6406
6407 return result;
6408 }
6409
6410 /*********************************************************************
6411 *********************************************************************/
6412 /* static */
6413 void
dropMatchingReferences(OSSet * kexts)6414 OSKext::dropMatchingReferences(
6415 OSSet * kexts)
6416 {
6417 IORecursiveLockLock(sKextLock);
6418 kexts->iterateObjects(^bool (OSObject * obj) {
6419 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6420 if (!thisKext) {
6421 return false;
6422 }
6423 thisKext->matchingRefCount--;
6424 return false;
6425 });
6426 IORecursiveLockUnlock(sKextLock);
6427 }
6428
6429 /*********************************************************************
6430 *********************************************************************/
6431 /* static */
6432 void
recordIdentifierRequest(OSString * kextIdentifier)6433 OSKext::recordIdentifierRequest(
6434 OSString * kextIdentifier)
6435 {
6436 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6437 bool fail = false;
6438
6439 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6440 goto finish;
6441 }
6442
6443 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6444 if (!kextIdentifierSymbol) {
6445 // xxx - this is really a basic alloc failure
6446 fail = true;
6447 goto finish;
6448 }
6449
6450 IORecursiveLockLock(sKextLock);
6451 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6452 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6453 fail = true;
6454 } else {
6455 // xxx - need to find a way to associate this whole func w/the kext
6456 OSKextLog(/* kext */ NULL,
6457 // xxx - check level
6458 kOSKextLogStepLevel |
6459 kOSKextLogArchiveFlag,
6460 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6461 kextIdentifier->getCStringNoCopy());
6462 }
6463 }
6464 IORecursiveLockUnlock(sKextLock);
6465
6466 finish:
6467
6468 if (fail) {
6469 OSKextLog(/* kext */ NULL,
6470 kOSKextLogErrorLevel |
6471 kOSKextLogArchiveFlag,
6472 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6473 kextIdentifier->getCStringNoCopy());
6474 }
6475 return;
6476 }
6477
6478 /*********************************************************************
6479 *********************************************************************/
6480 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6481 OSKext::load(
6482 OSKextExcludeLevel startOpt,
6483 OSKextExcludeLevel startMatchingOpt,
6484 OSArray * personalityNames)
6485 {
6486 OSReturn result = kOSReturnError;
6487 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6488 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6489 unsigned int i, count;
6490 Boolean alreadyLoaded = false;
6491 OSKext * lastLoadedKext = NULL; // do not release
6492
6493 if (isInExcludeList()) {
6494 OSKextLog(this,
6495 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6496 kOSKextLogLoadFlag,
6497 "Kext %s is in exclude list, not loadable",
6498 getIdentifierCString());
6499
6500 result = kOSKextReturnNotLoadable;
6501 goto finish;
6502 }
6503 if (!isLoadable()) {
6504 OSKextLog(this,
6505 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6506 kOSKextLogLoadFlag,
6507 "Kext %s is not loadable",
6508 getIdentifierCString());
6509
6510 result = kOSKextReturnNotLoadable;
6511 goto finish;
6512 }
6513
6514 if (isLoaded()) {
6515 alreadyLoaded = true;
6516 result = kOSReturnSuccess;
6517
6518 OSKextLog(this,
6519 kOSKextLogDebugLevel |
6520 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6521 "Kext %s is already loaded.",
6522 getIdentifierCString());
6523 goto loaded;
6524 }
6525
6526 #if CONFIG_MACF
6527 /*
6528 * On kxld and on embedded, only call into the MAC hook when on a
6529 * user thread, for access control over userspace kextloads.
6530 *
6531 * On non-kxld systems, additionally check the MAC hook for kexts in
6532 * the Pageable and Aux KCs, regardless of whether we are on a user
6533 * thread or not. This means on Apple silicon devices that the MAC
6534 * hook will only be useful to block 3rd party kexts loaded via
6535 * matching, and any kexts loaded from userspace kextloads.
6536 *
6537 * Note that this should _not_ be called on kexts loaded from the
6538 * kernel bootstrap thread as the kernel proc's cred struct is not
6539 * yet initialized! This won't happen on macOS because all the kexts
6540 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6541 */
6542 if (current_task() != kernel_task
6543 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6544 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6545 #endif
6546 ) {
6547 int macCheckResult = 0;
6548 kauth_cred_t cred = NULL;
6549
6550 cred = kauth_cred_get_with_ref();
6551 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
6552 kauth_cred_unref(&cred);
6553
6554 if (macCheckResult != 0) {
6555 result = kOSReturnError;
6556 OSKextLog(this,
6557 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6558 "Failed to load kext %s (MAC policy error 0x%x).",
6559 getIdentifierCString(), macCheckResult);
6560 goto finish;
6561 }
6562 }
6563 #endif /* CONFIG_MACF */
6564
6565 if (!sLoadEnabled) {
6566 OSKextLog(this,
6567 kOSKextLogErrorLevel |
6568 kOSKextLogLoadFlag,
6569 "Kext loading is disabled (attempt to load kext %s).",
6570 getIdentifierCString());
6571 result = kOSKextReturnDisabled;
6572 goto finish;
6573 }
6574
6575 /* If we've pushed the next available load tag to the invalid value,
6576 * we can't load any more kexts.
6577 */
6578 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6579 OSKextLog(this,
6580 kOSKextLogErrorLevel |
6581 kOSKextLogLoadFlag,
6582 "Can't load kext %s - no more load tags to assign.",
6583 getIdentifierCString());
6584 result = kOSKextReturnNoResources;
6585 goto finish;
6586 }
6587
6588 /* This is a bit of a hack, because we shouldn't be handling
6589 * personalities within the load function.
6590 */
6591 if (!declaresExecutable()) {
6592 /* There is a special case where a non-executable kext can be loaded: the
6593 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6594 * load its metadata into the global data structures, if appropriate
6595 */
6596 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6597 boolean_t updated = updateExcludeList(infoDict.get());
6598 if (updated) {
6599 OSKextLog(this,
6600 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6601 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6602 }
6603 }
6604
6605 if (isDriverKit()) {
6606 if (loadTag == 0) {
6607 sLoadedDriverKitKexts->setObject(this);
6608 loadTag = sNextLoadTag++;
6609 }
6610 }
6611 result = kOSReturnSuccess;
6612 goto loaded;
6613 }
6614
6615 /* Are we in safe boot?
6616 */
6617 if (sSafeBoot && !isLoadableInSafeBoot()) {
6618 OSKextLog(this,
6619 kOSKextLogErrorLevel |
6620 kOSKextLogLoadFlag,
6621 "Can't load kext %s - not loadable during safe boot.",
6622 getIdentifierCString());
6623 result = kOSKextReturnBootLevel;
6624 goto finish;
6625 }
6626
6627 OSKextLog(this,
6628 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6629 "Loading kext %s.",
6630 getIdentifierCString());
6631
6632 #if !VM_MAPPED_KEXTS
6633 if (isPrelinked() == false) {
6634 OSKextLog(this,
6635 kOSKextLogErrorLevel |
6636 kOSKextLogLoadFlag,
6637 "Can't load kext %s - not in a kext collection.",
6638 getIdentifierCString());
6639 result = kOSKextReturnDisabled;
6640 goto finish;
6641 }
6642 #endif /* defined(__x86_64__) */
6643
6644 #if CONFIG_KXLD
6645 if (!sKxldContext) {
6646 kern_return_t kxldResult;
6647 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6648 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6649 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6650 if (kxldResult) {
6651 OSKextLog(this,
6652 kOSKextLogErrorLevel |
6653 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6654 "Can't load kext %s - failed to create link context.",
6655 getIdentifierCString());
6656 result = kOSKextReturnNoMemory;
6657 goto finish;
6658 }
6659 }
6660 #endif // CONFIG_KXLD
6661
6662 /* We only need to resolve dependencies once for the whole graph, but
6663 * resolveDependencies will just return if there's no work to do, so it's
6664 * safe to call it more than once.
6665 */
6666 if (!resolveDependencies()) {
6667 // xxx - check resolveDependencies() for log msg
6668 OSKextLog(this,
6669 kOSKextLogErrorLevel |
6670 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6671 "Can't load kext %s - failed to resolve library dependencies.",
6672 getIdentifierCString());
6673 result = kOSKextReturnDependencies;
6674 goto finish;
6675 }
6676
6677 /* If we are excluding just the kext being loaded now (and not its
6678 * dependencies), drop the exclusion level to none so dependencies
6679 * start and/or add their personalities.
6680 */
6681 if (dependenciesStartOpt == kOSKextExcludeKext) {
6682 dependenciesStartOpt = kOSKextExcludeNone;
6683 }
6684
6685 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6686 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6687 }
6688
6689 /* Load the dependencies, recursively.
6690 */
6691 count = getNumDependencies();
6692 for (i = 0; i < count; i++) {
6693 OSKext * dependency = OSDynamicCast(OSKext,
6694 dependencies->getObject(i));
6695 if (dependency == NULL) {
6696 OSKextLog(this,
6697 kOSKextLogErrorLevel |
6698 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6699 "Internal error loading kext %s; dependency disappeared.",
6700 getIdentifierCString());
6701 result = kOSKextReturnInternalError;
6702 goto finish;
6703 }
6704
6705 /* Dependencies must be started accorting to the opt,
6706 * but not given the personality names of the main kext.
6707 */
6708 result = dependency->load(dependenciesStartOpt,
6709 dependenciesStartMatchingOpt,
6710 /* personalityNames */ NULL);
6711 if (result != KERN_SUCCESS) {
6712 OSKextLog(this,
6713 kOSKextLogErrorLevel |
6714 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6715 "Dependency %s of kext %s failed to load.",
6716 dependency->getIdentifierCString(),
6717 getIdentifierCString());
6718
6719 OSKext::removeKext(dependency,
6720 /* terminateService/removePersonalities */ true);
6721 result = kOSKextReturnDependencyLoadError;
6722
6723 goto finish;
6724 }
6725 }
6726
6727 result = loadExecutable();
6728 if (result != KERN_SUCCESS) {
6729 goto finish;
6730 }
6731
6732 pendingPgoHead.next = &pendingPgoHead;
6733 pendingPgoHead.prev = &pendingPgoHead;
6734
6735 // The kernel PRNG is not initialized when the first kext is
6736 // loaded, so use early random
6737 uuid_generate_early_random(instance_uuid);
6738 account = IOMallocType(OSKextAccount);
6739
6740 account->loadTag = kmod_info->id;
6741 account->site.refcount = 0;
6742 account->site.flags = VM_TAG_KMOD;
6743
6744 #if DEVELOPMENT || DEBUG
6745 /* Setup the task reference group. */
6746 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6747 "task_%s", getIdentifierCString());
6748 account->task_refgrp.grp_name = account->task_refgrp_name;
6749 account->task_refgrp.grp_parent = &task_external_refgrp;
6750 account->task_refgrp.grp_flags = OS_REFGRP_F_ALWAYS_ENABLED;
6751 os_ref_log_init(&account->task_refgrp);
6752 #endif /* DEVELOPMENT || DEBUG */
6753
6754 account->kext = this;
6755 if (gIOSurfaceIdentifier == bundleID) {
6756 vm_tag_alloc(&account->site);
6757 gIOSurfaceTag = account->site.tag;
6758 }
6759
6760 flags.loaded = true;
6761
6762 /* Add the kext to the list of loaded kexts and update the kmod_info
6763 * struct to point to that of the last loaded kext (which is the way
6764 * it's always been done, though I'd rather do them in order now).
6765 */
6766 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6767 sLoadedKexts->setObject(this);
6768
6769 /* Keep the kernel itself out of the kmod list.
6770 */
6771 if (lastLoadedKext->isKernel()) {
6772 lastLoadedKext = NULL;
6773 }
6774
6775 if (lastLoadedKext) {
6776 kmod_info->next = lastLoadedKext->kmod_info;
6777 }
6778
6779 notifyKextLoadObservers(this, kmod_info);
6780
6781 /* Make the global kmod list point at the just-loaded kext. Note that the
6782 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6783 * although we do report it in kextstat these days by using the newer
6784 * OSArray of loaded kexts, which does contain it.
6785 *
6786 * (The OSKext object representing the kernel doesn't even have a kmod_info
6787 * struct, though I suppose we could stick a pointer to it from the
6788 * static struct in OSRuntime.cpp.)
6789 */
6790 kmod = kmod_info;
6791
6792 /* Save the list of loaded kexts in case we panic.
6793 */
6794 OSKext::saveLoadedKextPanicList();
6795
6796 if (isExecutable()) {
6797 OSKext::updateLoadedKextSummaries();
6798 savePanicString(/* isLoading */ true);
6799
6800 #if CONFIG_DTRACE
6801 registerWithDTrace();
6802 #else
6803 jettisonLinkeditSegment();
6804 #endif /* CONFIG_DTRACE */
6805
6806 #if !VM_MAPPED_KEXTS
6807 /* If there is a page (or more) worth of padding after the end
6808 * of the last data section but before the end of the data segment
6809 * then free it in the same manner the LinkeditSegment is freed
6810 */
6811 jettisonDATASegmentPadding();
6812 #endif
6813 }
6814
6815 loaded:
6816 if (isExecutable() && !flags.started) {
6817 if (startOpt == kOSKextExcludeNone) {
6818 result = start();
6819 if (result != kOSReturnSuccess) {
6820 OSKextLog(this,
6821 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6822 "Kext %s start failed (result 0x%x).",
6823 getIdentifierCString(), result);
6824 result = kOSKextReturnStartStopError;
6825 }
6826 }
6827 }
6828
6829 /* If not excluding matching, send the personalities to the kernel.
6830 * This never affects the result of the load operation.
6831 * This is a bit of a hack, because we shouldn't be handling
6832 * personalities within the load function.
6833 */
6834 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6835 result = sendPersonalitiesToCatalog(true, personalityNames);
6836 }
6837
6838 finish:
6839
6840 if (result != kOSReturnSuccess) {
6841 OSKextLog(this,
6842 kOSKextLogErrorLevel |
6843 kOSKextLogLoadFlag,
6844 "Kext %s failed to load (0x%x).",
6845 getIdentifierCString(), (int)result);
6846 } else if (!alreadyLoaded) {
6847 OSKextLog(this,
6848 kOSKextLogProgressLevel |
6849 kOSKextLogLoadFlag,
6850 "Kext %s loaded.",
6851 getIdentifierCString());
6852
6853 queueKextNotification(kKextRequestPredicateLoadNotification,
6854 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
6855 }
6856 return result;
6857 }
6858
6859 #if CONFIG_KXLD
6860 /*********************************************************************
6861 *
6862 *********************************************************************/
6863 static char *
strdup(const char * string)6864 strdup(const char * string)
6865 {
6866 char * result = NULL;
6867 size_t size;
6868
6869 if (!string) {
6870 goto finish;
6871 }
6872
6873 size = 1 + strlen(string);
6874 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6875 if (!result) {
6876 goto finish;
6877 }
6878
6879 memcpy(result, string, size);
6880
6881 finish:
6882 return result;
6883 }
6884 #endif // CONFIG_KXLD
6885
6886 /*********************************************************************
6887 *
6888 *********************************************************************/
6889
6890 kernel_section_t *
lookupSection(const char * segname,const char * secname)6891 OSKext::lookupSection(const char *segname, const char *secname)
6892 {
6893 kernel_section_t * found_section = NULL;
6894 kernel_mach_header_t * mh = NULL;
6895 kernel_segment_command_t * seg = NULL;
6896 kernel_section_t * sec = NULL;
6897
6898 if (!linkedExecutable) {
6899 return NULL;
6900 }
6901
6902 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6903
6904 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6905 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
6906 continue;
6907 }
6908
6909 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6910 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
6911 found_section = sec;
6912 goto out;
6913 }
6914 }
6915 }
6916
6917 out:
6918 return found_section;
6919 }
6920
6921 /*********************************************************************
6922 *
6923 *********************************************************************/
6924
6925 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6926 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6927 {
6928 OSReturn result = kOSKextReturnBadData;
6929 kernel_mach_header_t * mh = NULL;
6930 kernel_segment_command_t * seg = NULL;
6931 kernel_segment_command_t * linkeditSeg = NULL;
6932 kernel_section_t * sec = NULL;
6933 char * linkeditBase = NULL;
6934 bool haveLinkeditBase = false;
6935 char * relocBase = NULL;
6936 bool haveRelocBase = false;
6937 struct dysymtab_command * dysymtab = NULL;
6938 struct linkedit_data_command * segmentSplitInfo = NULL;
6939 struct symtab_command * symtab = NULL;
6940 kernel_nlist_t * sym = NULL;
6941 struct relocation_info * reloc = NULL;
6942 uint32_t i = 0;
6943 int reloc_size;
6944 vm_offset_t new_kextsize;
6945 kc_format format = KCFormatUnknown;
6946
6947 if (linkedExecutable == NULL || flags.builtin) {
6948 result = kOSReturnSuccess;
6949 goto finish;
6950 }
6951
6952 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6953 if (kernel_mach_header_is_in_fileset(mh)) {
6954 // kexts in filesets are slid as part of collection sliding
6955 result = kOSReturnSuccess;
6956 goto finish;
6957 }
6958
6959 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6960
6961 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6962 if (!seg->vmaddr) {
6963 continue;
6964 }
6965
6966 seg->vmaddr = ml_static_slide(seg->vmaddr);
6967
6968 #if KASLR_KEXT_DEBUG
6969 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6970 seg->segname,
6971 (unsigned long)ml_static_unslide(seg->vmaddr),
6972 (unsigned long)seg->vmaddr);
6973 #endif
6974
6975 if (!haveRelocBase) {
6976 relocBase = (char *) seg->vmaddr;
6977 haveRelocBase = true;
6978 }
6979 if (!strcmp(seg->segname, "__LINKEDIT")) {
6980 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6981 haveLinkeditBase = true;
6982 linkeditSeg = seg;
6983 }
6984 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6985 sec->addr = ml_static_slide(sec->addr);
6986
6987 #if KASLR_KEXT_DEBUG
6988 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6989 sec->sectname,
6990 (unsigned long)ml_static_unslide(sec->addr),
6991 (unsigned long)sec->addr);
6992 #endif
6993 }
6994 }
6995
6996 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6997
6998 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6999
7000 if (symtab != NULL && doCoalescedSlides == false) {
7001 /* Some pseudo-kexts have symbol tables without segments.
7002 * Ignore them. */
7003 if (symtab->nsyms > 0 && haveLinkeditBase) {
7004 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
7005 for (i = 0; i < symtab->nsyms; i++) {
7006 if (sym[i].n_type & N_STAB) {
7007 continue;
7008 }
7009 sym[i].n_value = ml_static_slide(sym[i].n_value);
7010
7011 #if KASLR_KEXT_DEBUG
7012 #define MAX_SYMS_TO_LOG 5
7013 if (i < MAX_SYMS_TO_LOG) {
7014 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
7015 (unsigned long)ml_static_unslide(sym[i].n_value),
7016 (unsigned long)sym[i].n_value);
7017 }
7018 #endif
7019 }
7020 }
7021 }
7022
7023 if (dysymtab != NULL && doCoalescedSlides == false) {
7024 if (dysymtab->nextrel > 0) {
7025 OSKextLog(this,
7026 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7027 kOSKextLogLinkFlag,
7028 "Sliding kext %s: External relocations found.",
7029 getIdentifierCString());
7030 goto finish;
7031 }
7032
7033 if (dysymtab->nlocrel > 0) {
7034 if (!haveLinkeditBase) {
7035 OSKextLog(this,
7036 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7037 kOSKextLogLinkFlag,
7038 "Sliding kext %s: No linkedit segment.",
7039 getIdentifierCString());
7040 goto finish;
7041 }
7042
7043 if (!haveRelocBase) {
7044 OSKextLog(this,
7045 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7046 kOSKextLogLinkFlag,
7047 #if __x86_64__
7048 "Sliding kext %s: No writable segments.",
7049 #else
7050 "Sliding kext %s: No segments.",
7051 #endif
7052 getIdentifierCString());
7053 goto finish;
7054 }
7055
7056 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
7057 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
7058
7059 for (i = 0; i < dysymtab->nlocrel; i++) {
7060 if (reloc[i].r_extern != 0
7061 || reloc[i].r_type != 0
7062 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
7063 ) {
7064 OSKextLog(this,
7065 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7066 kOSKextLogLinkFlag,
7067 "Sliding kext %s: Unexpected relocation found.",
7068 getIdentifierCString());
7069 goto finish;
7070 }
7071 if (reloc[i].r_pcrel != 0) {
7072 continue;
7073 }
7074 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
7075 *relocAddr = ml_static_slide(*relocAddr);
7076
7077 #if KASLR_KEXT_DEBUG
7078 #define MAX_DYSYMS_TO_LOG 5
7079 if (i < MAX_DYSYMS_TO_LOG) {
7080 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
7081 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
7082 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
7083 }
7084 #endif
7085 }
7086
7087 /* We should free these relocations, not just delete the reference to them.
7088 * <rdar://problem/10535549> Free relocations from PIE kexts.
7089 *
7090 * For now, we do not free LINKEDIT for kexts with split segments.
7091 */
7092 new_kextsize = round_page(kmod_info->size - reloc_size);
7093 if (new_kextsize > UINT_MAX) {
7094 OSKextLog(this,
7095 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7096 kOSKextLogLinkFlag,
7097 "Kext %s: new kext size is too large.",
7098 getIdentifierCString());
7099 goto finish;
7100 }
7101 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
7102 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
7103 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
7104 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
7105 size_t bytes_remaining = endofkext - endofrelocInfo;
7106 OSSharedPtr<OSData> new_osdata;
7107
7108 /* fix up symbol offsets if they are after the dsymtab local relocs */
7109 if (symtab) {
7110 if (dysymtab->locreloff < symtab->symoff) {
7111 symtab->symoff -= reloc_size;
7112 }
7113 if (dysymtab->locreloff < symtab->stroff) {
7114 symtab->stroff -= reloc_size;
7115 }
7116 }
7117 if (dysymtab->locreloff < dysymtab->extreloff) {
7118 dysymtab->extreloff -= reloc_size;
7119 }
7120
7121 /* move data behind reloc info down to new offset */
7122 if (endofrelocInfo < endofkext) {
7123 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
7124 }
7125
7126 /* Create a new OSData for the smaller kext object and reflect
7127 * new linkedit segment size.
7128 */
7129 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
7130 linkeditSeg->filesize = linkeditSeg->vmsize;
7131
7132 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
7133 if (new_osdata) {
7134 /* Fix up kmod info and linkedExecutable.
7135 */
7136 kmod_info->size = new_kextsize;
7137 /*
7138 * Fileset KCs are mapped as a whole by iBoot.
7139 * Individual kext executables should not be unmapped
7140 * by xnu.
7141 * Doing so may result in panics like rdar://85419651
7142 */
7143 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7144 new_osdata->setDeallocFunction(NULL);
7145 } else { // Not from a Fileset KC
7146 #if VM_MAPPED_KEXTS
7147 new_osdata->setDeallocFunction(osdata_kext_free);
7148 #else
7149 new_osdata->setDeallocFunction(osdata_phys_free);
7150 #endif
7151 }
7152 linkedExecutable->setDeallocFunction(NULL);
7153 linkedExecutable = os::move(new_osdata);
7154
7155 #if VM_MAPPED_KEXTS
7156 kext_free(new_endofkext, (endofkext - new_endofkext));
7157 #else
7158 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
7159 #endif
7160 }
7161 }
7162 dysymtab->nlocrel = 0;
7163 dysymtab->locreloff = 0;
7164 }
7165 }
7166
7167 result = kOSReturnSuccess;
7168 finish:
7169 return result;
7170 }
7171
7172 /*********************************************************************
7173 * called only by load()
7174 *********************************************************************/
7175 OSReturn
loadExecutable()7176 OSKext::loadExecutable()
7177 {
7178 OSReturn result = kOSReturnError;
7179 OSSharedPtr<OSArray> linkDependencies;
7180 uint32_t num_kmod_refs = 0;
7181 OSData * theExecutable = NULL; // do not release
7182 OSString * versString = NULL; // do not release
7183 const char * versCString = NULL; // do not free
7184 const char * string = NULL; // do not free
7185
7186 #if CONFIG_KXLD
7187 unsigned int i;
7188 uint32_t numDirectDependencies = 0;
7189 kern_return_t kxldResult;
7190 KXLDDependency * kxlddeps = NULL; // must kfree
7191 uint32_t num_kxlddeps = 0;
7192 struct mach_header ** kxldHeaderPtr = NULL; // do not free
7193 struct mach_header * kxld_header = NULL; // xxx - need to free here?
7194 #endif // CONFIG_KXLD
7195
7196 /* We need the version string for a variety of bits below.
7197 */
7198 versString = OSDynamicCast(OSString,
7199 getPropertyForHostArch(kCFBundleVersionKey));
7200 if (!versString) {
7201 goto finish;
7202 }
7203 versCString = versString->getCStringNoCopy();
7204
7205 if (isKernelComponent()) {
7206 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
7207 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
7208 OSKextLog(this,
7209 kOSKextLogErrorLevel |
7210 kOSKextLogLoadFlag,
7211 "Kernel component %s has incorrect version %s; "
7212 "expected %s.",
7213 getIdentifierCString(),
7214 versCString, KERNEL6_VERSION);
7215 result = kOSKextReturnInternalError;
7216 goto finish;
7217 } else if (strcmp(versCString, osrelease)) {
7218 OSKextLog(this,
7219 kOSKextLogErrorLevel |
7220 kOSKextLogLoadFlag,
7221 "Kernel component %s has incorrect version %s; "
7222 "expected %s.",
7223 getIdentifierCString(),
7224 versCString, osrelease);
7225 result = kOSKextReturnInternalError;
7226 goto finish;
7227 }
7228 }
7229 }
7230
7231 #if defined(__x86_64__) || defined(__i386__)
7232 if (flags.resetSegmentsFromVnode) {
7233 /* Fixup the chains and slide the mach headers */
7234 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
7235
7236 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
7237 result = kOSKextReturnValidation;
7238 goto finish;
7239 }
7240 }
7241 #endif //(__x86_64__) || defined(__i386__)
7242
7243 if (isPrelinked()) {
7244 goto register_kmod;
7245 }
7246
7247 /* <rdar://problem/21444003> all callers must be entitled */
7248 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7249 OSKextLog(this,
7250 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7251 "Not entitled to link kext '%s'",
7252 getIdentifierCString());
7253 result = kOSKextReturnNotPrivileged;
7254 goto finish;
7255 }
7256
7257 theExecutable = getExecutable();
7258 if (!theExecutable) {
7259 if (declaresExecutable()) {
7260 OSKextLog(this,
7261 kOSKextLogErrorLevel |
7262 kOSKextLogLoadFlag,
7263 "Can't load kext %s - executable is missing.",
7264 getIdentifierCString());
7265 result = kOSKextReturnValidation;
7266 goto finish;
7267 }
7268 goto register_kmod;
7269 }
7270
7271 if (isInterface()) {
7272 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
7273 if (executableCopy) {
7274 setLinkedExecutable(executableCopy.get());
7275 }
7276 goto register_kmod;
7277 }
7278
7279 #if CONFIG_KXLD
7280 numDirectDependencies = getNumDependencies();
7281
7282 if (flags.hasBleedthrough) {
7283 linkDependencies = dependencies;
7284 } else {
7285 linkDependencies = OSArray::withArray(dependencies.get());
7286 if (!linkDependencies) {
7287 OSKextLog(this,
7288 kOSKextLogErrorLevel |
7289 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7290 "Can't allocate link dependencies to load kext %s.",
7291 getIdentifierCString());
7292 goto finish;
7293 }
7294
7295 for (i = 0; i < numDirectDependencies; ++i) {
7296 OSKext * dependencyKext = OSDynamicCast(OSKext,
7297 dependencies->getObject(i));
7298 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7299 }
7300 }
7301
7302 num_kxlddeps = linkDependencies->getCount();
7303 if (!num_kxlddeps) {
7304 OSKextLog(this,
7305 kOSKextLogErrorLevel |
7306 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7307 "Can't load kext %s - it has no library dependencies.",
7308 getIdentifierCString());
7309 goto finish;
7310 }
7311
7312 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7313 if (!kxlddeps) {
7314 OSKextLog(this,
7315 kOSKextLogErrorLevel |
7316 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7317 "Can't allocate link context to load kext %s.",
7318 getIdentifierCString());
7319 goto finish;
7320 }
7321 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7322
7323 for (i = 0; i < num_kxlddeps; ++i) {
7324 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7325
7326 if (dependency->isInterface()) {
7327 OSKext *interfaceTargetKext = NULL; //do not release
7328 OSData * interfaceTarget = NULL; //do not release
7329
7330 if (dependency->isKernelComponent()) {
7331 interfaceTargetKext = sKernelKext;
7332 interfaceTarget = sKernelKext->linkedExecutable.get();
7333 } else {
7334 interfaceTargetKext = OSDynamicCast(OSKext,
7335 dependency->dependencies->getObject(0));
7336
7337 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7338 }
7339
7340 if (!interfaceTarget) {
7341 // panic?
7342 goto finish;
7343 }
7344
7345 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7346 * it will be useful to have them in the debugger.
7347 * strdup() failing isn't critical right here so we don't check that.
7348 */
7349 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7350 kxlddeps[i].kext_size = interfaceTarget->getLength();
7351 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7352
7353 if (dependency->linkedExecutable != NULL) {
7354 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7355 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7356 } else {
7357 kxlddeps[i].interface = (u_char *) NULL;
7358 kxlddeps[i].interface_size = 0;
7359 }
7360 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7361 } else {
7362 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7363 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7364 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7365 }
7366
7367 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7368 }
7369
7370 kxldHeaderPtr = &kxld_header;
7371
7372 #if DEBUG
7373 OSKextLog(this,
7374 kOSKextLogExplicitLevel |
7375 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7376 "Kext %s - calling kxld_link_file:\n"
7377 " kxld_context: %p\n"
7378 " executable: %p executable_length: %d\n"
7379 " user_data: %p\n"
7380 " kxld_dependencies: %p num_dependencies: %d\n"
7381 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7382 getIdentifierCString(), sKxldContext,
7383 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7384 this, kxlddeps, num_kxlddeps,
7385 kxldHeaderPtr, &kmod_info);
7386 #endif
7387
7388 /* After this call, the linkedExecutable instance variable
7389 * should exist.
7390 */
7391 kxldResult = kxld_link_file(sKxldContext,
7392 (u_char *)theExecutable->getBytesNoCopy(),
7393 theExecutable->getLength(),
7394 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7395 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7396
7397 if (kxldResult != KERN_SUCCESS) {
7398 // xxx - add kxldResult here?
7399 OSKextLog(this,
7400 kOSKextLogErrorLevel |
7401 kOSKextLogLoadFlag,
7402 "Can't load kext %s - link failed.",
7403 getIdentifierCString());
7404 result = kOSKextReturnLinkError;
7405 goto finish;
7406 }
7407
7408 /* We've written data & instructions into kernel memory, so flush the data
7409 * cache and invalidate the instruction cache.
7410 * I/D caches are coherent on x86
7411 */
7412 #if !defined(__i386__) && !defined(__x86_64__)
7413 flush_dcache(kmod_info->address, kmod_info->size, false);
7414 invalidate_icache(kmod_info->address, kmod_info->size, false);
7415 #endif
7416
7417 #else // !CONFIG_KXLD
7418 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7419 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7420 result = kOSKextReturnLinkError;
7421 goto finish;
7422 #endif // CONFIG_KXLD
7423
7424 register_kmod:
7425
7426 if (isInterface()) {
7427 /* Whip up a fake kmod_info entry for the interface kext.
7428 */
7429 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7430 if (!kmod_info) {
7431 result = KERN_MEMORY_ERROR;
7432 goto finish;
7433 }
7434
7435 /* A pseudokext has almost nothing in its kmod_info struct.
7436 */
7437 kmod_info->info_version = KMOD_INFO_VERSION;
7438
7439 /* An interface kext doesn't have a linkedExecutable, so save a
7440 * copy of the UUID out of the original executable via copyUUID()
7441 * while we still have the original executable.
7442 */
7443 interfaceUUID = copyUUID();
7444 }
7445
7446 kmod_info->id = loadTag = sNextLoadTag++;
7447 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7448
7449 /* Stamp the bundle ID and version from the OSKext over anything
7450 * resident inside the kmod_info.
7451 */
7452 string = getIdentifierCString();
7453 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
7454
7455 string = versCString;
7456 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
7457
7458 /* Add the dependencies' kmod_info structs as kmod_references.
7459 */
7460 num_kmod_refs = getNumDependencies();
7461 if (num_kmod_refs) {
7462 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7463 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7464 if (!kmod_info->reference_list) {
7465 result = KERN_MEMORY_ERROR;
7466 goto finish;
7467 }
7468 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7469 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7470 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7471 ref->info = refKext->kmod_info;
7472 ref->info->reference_count++;
7473
7474 if (refIndex + 1 < num_kmod_refs) {
7475 ref->next = kmod_info->reference_list + refIndex + 1;
7476 }
7477 }
7478 }
7479
7480 if (kmod_info->hdr_size > UINT32_MAX) {
7481 OSKextLog(this,
7482 kOSKextLogErrorLevel |
7483 kOSKextLogLoadFlag,
7484 #if __LP64__
7485 "Kext %s header size is too large (%lu > UINT32_MAX).",
7486 #else
7487 "Kext %s header size is too large (%u > UINT32_MAX).",
7488 #endif
7489 kmod_info->name,
7490 kmod_info->hdr_size);
7491 result = KERN_FAILURE;
7492 goto finish;
7493 }
7494
7495 if (kmod_info->size > UINT32_MAX) {
7496 OSKextLog(this,
7497 kOSKextLogErrorLevel |
7498 kOSKextLogLoadFlag,
7499 #if __LP64__
7500 "Kext %s size is too large (%lu > UINT32_MAX).",
7501 #else
7502 "Kext %s size is too large (%u > UINT32_MAX).",
7503 #endif
7504 kmod_info->name,
7505 kmod_info->size);
7506 result = KERN_FAILURE;
7507 goto finish;
7508 }
7509
7510 if (!isInterface() && linkedExecutable) {
7511 OSKextLog(this,
7512 kOSKextLogProgressLevel |
7513 kOSKextLogLoadFlag,
7514 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7515 kmod_info->name,
7516 (unsigned)kmod_info->size / PAGE_SIZE,
7517 (unsigned long)ml_static_unslide(kmod_info->address),
7518 (unsigned)kmod_info->id);
7519 }
7520
7521 /* VM protections and wiring for the Aux KC are done at collection loading time */
7522 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7523 /* if prelinked and primary KC, VM protections are already set */
7524 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
7525 if (result != KERN_SUCCESS) {
7526 goto finish;
7527 }
7528 }
7529
7530 #if KASAN
7531 if (linkedExecutable) {
7532 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7533 linkedExecutable->getLength(), getIdentifierCString());
7534 }
7535 #else
7536 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7537 OSKextLog(this,
7538 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7539 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7540 getIdentifierCString()
7541 );
7542 result = KERN_FAILURE;
7543 goto finish;
7544 }
7545 #endif
7546
7547 result = kOSReturnSuccess;
7548
7549 finish:
7550
7551 #if CONFIG_KXLD
7552 /* Clear up locally allocated dependency info.
7553 */
7554 for (i = 0; i < num_kxlddeps; ++i) {
7555 size_t size;
7556
7557 if (kxlddeps[i].kext_name) {
7558 size = 1 + strlen(kxlddeps[i].kext_name);
7559 kfree_data(kxlddeps[i].kext_name, size);
7560 }
7561 if (kxlddeps[i].interface_name) {
7562 size = 1 + strlen(kxlddeps[i].interface_name);
7563 kfree_data(kxlddeps[i].interface_name, size);
7564 }
7565 }
7566 if (kxlddeps) {
7567 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7568 }
7569 #endif // CONFIG_KXLD
7570
7571 /* We no longer need the unrelocated executable (which the linker
7572 * has altered anyhow).
7573 */
7574 setExecutable(NULL);
7575
7576 if (result != kOSReturnSuccess) {
7577 OSKextLog(this,
7578 kOSKextLogErrorLevel |
7579 kOSKextLogLoadFlag,
7580 "Failed to load executable for kext %s.",
7581 getIdentifierCString());
7582
7583 if (kmod_info && kmod_info->reference_list) {
7584 kfree_type(kmod_reference_t, num_kmod_refs,
7585 kmod_info->reference_list);
7586 }
7587 if (isInterface()) {
7588 kfree_type(kmod_info_t, kmod_info);
7589 kmod_info = NULL;
7590 }
7591 if (kc_type == KCKindUnknown) {
7592 kmod_info = NULL;
7593 if (linkedExecutable) {
7594 linkedExecutable.reset();
7595 }
7596 }
7597 }
7598
7599 return result;
7600 }
7601
7602 /* static */
7603 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)7604 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7605 {
7606 kernel_segment_command_t *linkeditseg = NULL;
7607
7608 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
7609 if (linkeditseg == NULL) {
7610 panic("FileSet booted with no Linkedit segment");
7611 }
7612
7613 #if VM_MAPPED_KEXTS
7614 /* BootKC on x86_64 is not vm mapped */
7615 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7616
7617 OSKextLog(/* kext */ NULL,
7618 kOSKextLogProgressLevel |
7619 kOSKextLogGeneralFlag,
7620 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7621 linkeditseg->vmaddr, linkeditseg->vmsize);
7622 #else
7623 /* BootKC on arm64 is not vm mapped, but is slid */
7624 #if !CONFIG_SPTM
7625 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7626 #else
7627 vm_offset_t linkedit_vmaddr = linkeditseg->vmaddr;
7628 #endif
7629
7630 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7631
7632 OSKextLog(/* kext */ NULL,
7633 kOSKextLogProgressLevel |
7634 kOSKextLogGeneralFlag,
7635 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7636 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7637 #endif /* VM_MAPPED_KEXTS */
7638 }
7639
7640 /*********************************************************************
7641 * The linkedit segment is used by the kext linker for dependency
7642 * resolution, and by dtrace for probe initialization. We can free it
7643 * for non-library kexts, since no kexts depend on non-library kexts
7644 * by definition, once dtrace has been initialized.
7645 *********************************************************************/
7646 void
jettisonLinkeditSegment(void)7647 OSKext::jettisonLinkeditSegment(void)
7648 {
7649 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7650 kernel_segment_command_t * linkedit = NULL;
7651 vm_offset_t start;
7652 vm_size_t linkeditsize, kextsize;
7653 OSSharedPtr<OSData> data;
7654 kc_format format = KCFormatUnknown;
7655
7656 if (isInFileset()) {
7657 return;
7658 }
7659
7660 #if NO_KEXTD
7661 /* We can free symbol tables for all embedded kexts because we don't
7662 * support runtime kext linking.
7663 */
7664 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7665 #else
7666 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7667 #endif
7668 goto finish;
7669 }
7670
7671 /* Find the linkedit segment. If it's not the last segment, then freeing
7672 * it will fragment the kext into multiple VM regions, which OSKext is not
7673 * designed to handle, so we'll have to skip it.
7674 */
7675 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
7676 if (!linkedit) {
7677 goto finish;
7678 }
7679
7680 if (round_page(kmod_info->address + kmod_info->size) !=
7681 round_page(linkedit->vmaddr + linkedit->vmsize)) {
7682 goto finish;
7683 }
7684
7685 /* Create a new OSData for the smaller kext object.
7686 */
7687 linkeditsize = round_page(linkedit->vmsize);
7688 kextsize = kmod_info->size - linkeditsize;
7689 start = linkedit->vmaddr;
7690
7691 if (kextsize > UINT_MAX) {
7692 goto finish;
7693 }
7694 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
7695 if (!data) {
7696 goto finish;
7697 }
7698
7699 /* Fix the kmod info and linkedExecutable.
7700 */
7701 kmod_info->size = kextsize;
7702
7703 /*
7704 * Fileset KCs are mapped as a whole by iBoot.
7705 * Individual kext executables should not be unmapped by xnu
7706 * Doing so may result in panics like rdar://85419651
7707 */
7708 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7709 data->setDeallocFunction(NULL);
7710 } else { // Not from a Fileset KC
7711 #if VM_MAPPED_KEXTS
7712 data->setDeallocFunction(osdata_kext_free);
7713 #else
7714 data->setDeallocFunction(osdata_phys_free);
7715 #endif
7716 }
7717 linkedExecutable->setDeallocFunction(NULL);
7718 linkedExecutable = os::move(data);
7719 flags.jettisonLinkeditSeg = 1;
7720
7721 /* Free the linkedit segment.
7722 */
7723 #if VM_MAPPED_KEXTS
7724 kext_free(start, linkeditsize);
7725 #else
7726 ml_static_mfree(start, linkeditsize);
7727 #endif
7728
7729 finish:
7730 return;
7731 }
7732
7733 /*********************************************************************
7734 * If there are whole pages that are unused betweem the last section
7735 * of the DATA segment and the end of the DATA segment then we can free
7736 * them
7737 *********************************************************************/
7738 void
7739 OSKext::jettisonDATASegmentPadding(void)
7740 {
7741 kernel_mach_header_t * mh;
7742 kernel_segment_command_t * dataSeg;
7743 kernel_section_t * sec, * lastSec;
7744 vm_offset_t dataSegEnd, lastSecEnd;
7745 vm_size_t padSize;
7746
7747 if (flags.builtin) {
7748 return;
7749 }
7750 mh = (kernel_mach_header_t *)kmod_info->address;
7751
7752 if (isInFileset()) {
7753 return;
7754 }
7755
7756 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
7757 if (dataSeg == NULL) {
7758 return;
7759 }
7760
7761 lastSec = NULL;
7762 sec = firstsect(dataSeg);
7763 while (sec != NULL) {
7764 lastSec = sec;
7765 sec = nextsect(dataSeg, sec);
7766 }
7767
7768 if (lastSec == NULL) {
7769 return;
7770 }
7771
7772 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
7773 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
7774 return;
7775 }
7776
7777 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7778 lastSecEnd = round_page(lastSec->addr + lastSec->size);
7779
7780 if (dataSegEnd <= lastSecEnd) {
7781 return;
7782 }
7783
7784 padSize = dataSegEnd - lastSecEnd;
7785
7786 if (padSize >= PAGE_SIZE) {
7787 #if VM_MAPPED_KEXTS
7788 kext_free(lastSecEnd, padSize);
7789 #else
7790 ml_static_mfree(lastSecEnd, padSize);
7791 #endif
7792 }
7793 }
7794
7795 /*********************************************************************
7796 *********************************************************************/
7797 void
7798 OSKext::setLinkedExecutable(OSData * anExecutable)
7799 {
7800 if (linkedExecutable) {
7801 panic("Attempt to set linked executable on kext "
7802 "that already has one (%s).\n",
7803 getIdentifierCString());
7804 }
7805 linkedExecutable.reset(anExecutable, OSRetain);
7806 return;
7807 }
7808
7809 #if CONFIG_DTRACE
7810 /*********************************************************************
7811 * Go through all loaded kexts and tell them to register with dtrace.
7812 * The instance method only registers if necessary.
7813 *********************************************************************/
7814 /* static */
7815 void
7816 OSKext::registerKextsWithDTrace(void)
7817 {
7818 uint32_t count = sLoadedKexts->getCount();
7819 uint32_t i;
7820
7821 IORecursiveLockLock(sKextLock);
7822
7823 for (i = 0; i < count; i++) {
7824 OSKext * thisKext = NULL; // do not release
7825
7826 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7827 if (!thisKext || !thisKext->isExecutable()) {
7828 continue;
7829 }
7830
7831 thisKext->registerWithDTrace();
7832 }
7833
7834 IORecursiveLockUnlock(sKextLock);
7835
7836 return;
7837 }
7838
7839 extern "C" {
7840 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7841 extern int (*dtrace_modunload)(struct kmod_info *);
7842 };
7843
7844 /*********************************************************************
7845 *********************************************************************/
7846 void
7847 OSKext::registerWithDTrace(void)
7848 {
7849 /* Register kext with dtrace. A dtrace_modload failure should not
7850 * prevent a kext from loading, so we ignore the return code.
7851 */
7852 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7853 uint32_t modflag = 0;
7854 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
7855
7856 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7857 if (forceInit == kOSBooleanTrue) {
7858 OSKextLog(this,
7859 kOSKextLogBasicLevel |
7860 kOSKextLogGeneralFlag,
7861 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7862 getIdentifierCString());
7863 forceInit = kOSBooleanFalse;
7864 }
7865 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7866 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7867 }
7868
7869 if (forceInit == kOSBooleanTrue) {
7870 modflag |= KMOD_DTRACE_FORCE_INIT;
7871 }
7872 if (flags.builtin) {
7873 modflag |= KMOD_DTRACE_STATIC_KEXT;
7874 }
7875
7876 (void)(*dtrace_modload)(kmod_info, modflag);
7877 flags.dtraceInitialized = true;
7878 jettisonLinkeditSegment();
7879 }
7880 return;
7881 }
7882 /*********************************************************************
7883 *********************************************************************/
7884 void
7885 OSKext::unregisterWithDTrace(void)
7886 {
7887 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7888 * prevent a kext from loading, so we ignore the return code.
7889 */
7890 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7891 (void)(*dtrace_modunload)(kmod_info);
7892 flags.dtraceInitialized = false;
7893 }
7894 return;
7895 }
7896 #endif /* CONFIG_DTRACE */
7897
7898
7899 /*********************************************************************
7900 * called only by loadExecutable()
7901 *********************************************************************/
7902 #if !VM_MAPPED_KEXTS
7903 #if defined(__arm__) || defined(__arm64__)
7904 static inline kern_return_t
7905 OSKext_protect(
7906 kernel_mach_header_t *kext_mh,
7907 vm_map_t map,
7908 vm_map_offset_t start,
7909 vm_map_size_t size,
7910 vm_prot_t new_prot,
7911 boolean_t set_max,
7912 kc_kind_t kc_type)
7913 {
7914 vm_map_offset_t end = start + size;
7915
7916 #pragma unused(kext_mh,map,kc_type)
7917 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7918 assert(start <= end);
7919 if (start >= end) {
7920 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7921 } else if (set_max) {
7922 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7923 } else {
7924 return ml_static_protect(start, size, new_prot);
7925 }
7926 }
7927
7928 static inline kern_return_t
7929 OSKext_wire(
7930 kernel_mach_header_t *kext_mh,
7931 vm_map_t map,
7932 vm_map_offset_t start,
7933 vm_map_offset_t end,
7934 vm_prot_t access_type,
7935 boolean_t user_wire,
7936 kc_kind_t kc_type)
7937 {
7938 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7939 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7940 }
7941 #else
7942 #error Unrecognized architecture
7943 #endif
7944 #else
7945 static inline kern_return_t
7946 OSKext_protect(
7947 kernel_mach_header_t *kext_mh,
7948 vm_map_t map,
7949 vm_map_offset_t start,
7950 vm_map_size_t size,
7951 vm_prot_t new_prot,
7952 boolean_t set_max,
7953 kc_kind_t kc_type)
7954 {
7955 vm_map_offset_t end = start + size;
7956
7957 if (start == end) { // 10538581
7958 return KERN_SUCCESS;
7959 }
7960 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7961 /*
7962 * XXX: This will probably need to be different for AuxKC and
7963 * pageableKC!
7964 */
7965 return ml_static_protect(start, size, new_prot);
7966 }
7967 return mach_vm_protect(map, start, size, set_max, new_prot);
7968 }
7969
7970 static inline kern_return_t
7971 OSKext_wire(
7972 kernel_mach_header_t *kext_mh,
7973 vm_map_t map,
7974 vm_map_offset_t start,
7975 vm_map_offset_t end,
7976 vm_prot_t access_type,
7977 boolean_t user_wire,
7978 kc_kind_t kc_type)
7979 {
7980 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7981 /* TODO: we may need to hook this for the pageableKC */
7982 return KERN_SUCCESS;
7983 }
7984 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7985 }
7986 #endif
7987
7988 OSReturn
7989 OSKext::setVMAttributes(bool protect, bool wire)
7990 {
7991 vm_map_t kext_map = NULL;
7992 kernel_segment_command_t * seg = NULL;
7993 vm_map_offset_t start_protect = 0;
7994 vm_map_offset_t start_wire = 0;
7995 vm_map_offset_t end_protect = 0;
7996 vm_map_size_t size_protect = 0;
7997 vm_map_offset_t end_wire = 0;
7998 OSReturn result = kOSReturnError;
7999
8000 if (isInterface() || !declaresExecutable() || flags.builtin) {
8001 result = kOSReturnSuccess;
8002 goto finish;
8003 }
8004
8005 /* Get the kext's vm map */
8006 kext_map = kext_get_vm_map(kmod_info);
8007 if (!kext_map) {
8008 result = KERN_MEMORY_ERROR;
8009 goto finish;
8010 }
8011
8012 #if !VM_MAPPED_KEXTS
8013 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
8014 /* This is a split kext in a prelinked kernelcache; we'll let the
8015 * platform code take care of protecting it. It is already wired.
8016 */
8017 /* TODO: Should this still allow protections for the first segment
8018 * to go through, in the event that we have a mix of split and
8019 * unsplit kexts?
8020 */
8021 result = KERN_SUCCESS;
8022 goto finish;
8023 }
8024
8025 if (isInFileset() && kc_type != KCKindPageable) {
8026 // kexts in filesets have protections setup as part of collection loading
8027 result = KERN_SUCCESS;
8028 goto finish;
8029 }
8030 #endif
8031
8032 /* Protect the headers as read-only; they do not need to be wired */
8033 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8034 kext_map, kmod_info->address,
8035 kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
8036 : KERN_SUCCESS;
8037 if (result != KERN_SUCCESS) {
8038 goto finish;
8039 }
8040
8041 /* Set the VM protections and wire down each of the segments */
8042 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8043 while (seg) {
8044 #if __arm__
8045 /* We build all ARM kexts, so we can ensure they are aligned */
8046 assert((seg->vmaddr & PAGE_MASK) == 0);
8047 assert((seg->vmsize & PAGE_MASK) == 0);
8048 #endif
8049
8050 /*
8051 * For the non page aligned segments, the range calculation for protection
8052 * and wiring differ as follows:
8053 *
8054 * Protection: The non page aligned data at the start or at the end of the
8055 * segment is excluded from the protection. This exclusion is needed to make
8056 * sure OSKext_protect is not called twice on same page, if the page is shared
8057 * between two segments.
8058 *
8059 * Wiring: The non page aligned data at the start or at the end of the
8060 * segment is included in the wiring range, this inclusion is needed to make sure
8061 * all the data of the segment is wired.
8062 */
8063 start_protect = round_page(seg->vmaddr);
8064 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
8065 size_protect = end_protect - start_protect;
8066
8067 start_wire = trunc_page(seg->vmaddr);
8068 end_wire = round_page(seg->vmaddr + seg->vmsize);
8069
8070 /*
8071 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
8072 * across kexts and data from kexts is not page aligned
8073 */
8074 if (protect && (end_protect > start_protect) &&
8075 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
8076 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
8077 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
8078 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8079 kext_map, start_protect, size_protect, seg->maxprot, TRUE, kc_type);
8080 if (result != KERN_SUCCESS) {
8081 OSKextLog(this,
8082 kOSKextLogErrorLevel |
8083 kOSKextLogLoadFlag,
8084 "Kext %s failed to set maximum VM protections "
8085 "for segment %s - 0x%x.",
8086 getIdentifierCString(), seg->segname, (int)result);
8087 goto finish;
8088 }
8089
8090 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8091 kext_map, start_protect, size_protect, seg->initprot, FALSE, kc_type);
8092 if (result != KERN_SUCCESS) {
8093 OSKextLog(this,
8094 kOSKextLogErrorLevel |
8095 kOSKextLogLoadFlag,
8096 "Kext %s failed to set initial VM protections "
8097 "for segment %s - 0x%x.",
8098 getIdentifierCString(), seg->segname, (int)result);
8099 goto finish;
8100 }
8101 }
8102
8103 if (segmentShouldBeWired(seg) && wire) {
8104 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
8105 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
8106 if (result != KERN_SUCCESS) {
8107 goto finish;
8108 }
8109 }
8110
8111 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8112 }
8113
8114 finish:
8115 return result;
8116 }
8117
8118 /*********************************************************************
8119 *********************************************************************/
8120 boolean_t
8121 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
8122 {
8123 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
8124 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
8125 }
8126
8127 /*********************************************************************
8128 *********************************************************************/
8129 OSReturn
8130 OSKext::validateKextMapping(bool startFlag)
8131 {
8132 OSReturn result = kOSReturnError;
8133 const char * whichOp = startFlag ? "start" : "stop";
8134 kern_return_t kern_result = 0;
8135 vm_map_t kext_map = NULL;
8136 kernel_segment_command_t * seg = NULL;
8137 mach_vm_address_t address = 0;
8138 mach_vm_size_t size = 0;
8139 uint32_t depth = 0;
8140 uint64_t kext_segbase = 0;
8141 uint64_t kext_segsize = 0;
8142 mach_msg_type_number_t count;
8143 vm_region_submap_short_info_data_64_t info;
8144 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
8145
8146 if (flags.builtin) {
8147 return kOSReturnSuccess;
8148 }
8149
8150 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
8151 bzero(&info, sizeof(info));
8152
8153 // xxx - do we need a distinct OSReturn value for these or is "bad data"
8154 // xxx - sufficient?
8155
8156 /* Verify that the kmod_info and start/stop pointers are non-NULL.
8157 */
8158 if (!kmod_info) {
8159 OSKextLog(this,
8160 kOSKextLogErrorLevel |
8161 kOSKextLogLoadFlag,
8162 "Kext %s - NULL kmod_info pointer.",
8163 getIdentifierCString());
8164 result = kOSKextReturnBadData;
8165 goto finish;
8166 }
8167
8168 if (startFlag) {
8169 address = (mach_vm_address_t)kmod_info->start;
8170 } else {
8171 address = (mach_vm_address_t)kmod_info->stop;
8172 }
8173
8174 if (!address) {
8175 OSKextLog(this,
8176 kOSKextLogErrorLevel |
8177 kOSKextLogLoadFlag,
8178 "Kext %s - NULL module %s pointer.",
8179 getIdentifierCString(), whichOp);
8180 result = kOSKextReturnBadData;
8181 goto finish;
8182 }
8183
8184 kext_map = kext_get_vm_map(kmod_info);
8185 depth = (kernel_map == kext_map) ? 1 : 2;
8186 if (isInFileset()) {
8187 #if defined(HAS_APPLE_PAC)
8188 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
8189 #endif /* defined(HAS_APPLE_PAC) */
8190 }
8191
8192 /* Verify that the start/stop function lies within the kext's address range.
8193 */
8194 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
8195 isInFileset()) {
8196 /* This will likely be how we deal with split kexts; walk the segments to
8197 * check that the function lies inside one of the segments of this kext.
8198 */
8199 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8200 seg != NULL;
8201 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
8202 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
8203 kext_segbase = seg->vmaddr;
8204 kext_segsize = seg->vmsize;
8205 break;
8206 }
8207 }
8208
8209 if (!seg) {
8210 OSKextLog(this,
8211 kOSKextLogErrorLevel |
8212 kOSKextLogLoadFlag,
8213 "Kext %s module %s pointer is outside of kext range "
8214 "(%s %p - kext starts at %p).",
8215 getIdentifierCString(),
8216 whichOp,
8217 whichOp,
8218 (void *)(((uintptr_t)address) - kext_slide),
8219 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
8220 result = kOSKextReturnBadData;
8221 goto finish;
8222 }
8223
8224 seg = NULL;
8225 } else {
8226 if (address < kmod_info->address + kmod_info->hdr_size ||
8227 kmod_info->address + kmod_info->size <= address) {
8228 OSKextLog(this,
8229 kOSKextLogErrorLevel |
8230 kOSKextLogLoadFlag,
8231 "Kext %s module %s pointer is outside of kext range "
8232 "(%s %p - kext at %p-%p).",
8233 getIdentifierCString(),
8234 whichOp,
8235 whichOp,
8236 (void *)(((uintptr_t)address) - kext_slide),
8237 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
8238 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
8239 result = kOSKextReturnBadData;
8240 goto finish;
8241 }
8242 }
8243
8244 /* Only do these checks before calling the start function;
8245 * If anything goes wrong with the mapping while the kext is running,
8246 * we'll likely have panicked well before any attempt to stop the kext.
8247 */
8248 if (startFlag) {
8249 if (!isInFileset() || kc_type != KCKindPrimary) {
8250 /*
8251 * Verify that the start/stop function is executable.
8252 */
8253 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
8254 (vm_region_recurse_info_t)&info, &count);
8255 if (kern_result != KERN_SUCCESS) {
8256 OSKextLog(this,
8257 kOSKextLogErrorLevel |
8258 kOSKextLogLoadFlag,
8259 "Kext %s - bad %s pointer %p.",
8260 getIdentifierCString(),
8261 whichOp, (void *)ml_static_unslide(address));
8262 result = kOSKextReturnBadData;
8263 goto finish;
8264 }
8265 } else {
8266 /*
8267 * Since kexts loaded from the primary KC are held in memory
8268 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8269 * discover that memory's protection flags. Instead, we need to
8270 * get that information from the kernel pmap itself. Above, we
8271 * (potentially) saved the size of the segment in which the address
8272 * in question was located. If we have a non-zero size, verify
8273 * that all pages in the (address, address + kext_segsize) range
8274 * are marked executable. If we somehow did not record the size
8275 * (or the base) just verify the single page that includes the address.
8276 */
8277 if (kext_segbase == 0 || kext_segsize == 0) {
8278 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8279 kext_segsize = PAGE_SIZE;
8280 }
8281 }
8282
8283 #if VM_MAPPED_KEXTS
8284 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8285 ((isInFileset() && kc_type == KCKindPrimary) &&
8286 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8287 OSKextLog(this,
8288 kOSKextLogErrorLevel |
8289 kOSKextLogLoadFlag,
8290 "Kext %s - memory region containing module %s function "
8291 "is not executable.",
8292 getIdentifierCString(), whichOp);
8293 result = kOSKextReturnBadData;
8294 goto finish;
8295 }
8296 #endif
8297
8298 /* Verify that the kext's segments are backed by physical memory.
8299 */
8300 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8301 while (seg) {
8302 if (!verifySegmentMapping(seg)) {
8303 result = kOSKextReturnBadData;
8304 goto finish;
8305 }
8306
8307 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8308 }
8309 }
8310
8311 result = kOSReturnSuccess;
8312 finish:
8313 return result;
8314 }
8315
8316 /*********************************************************************
8317 *********************************************************************/
8318 boolean_t
8319 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8320 {
8321 mach_vm_address_t address = 0;
8322
8323 if (seg->vmsize > UINT32_MAX) {
8324 return false;
8325 }
8326
8327 if (!segmentShouldBeWired(seg)) {
8328 return true;
8329 }
8330
8331 for (address = seg->vmaddr;
8332 address < round_page(seg->vmaddr + seg->vmsize);
8333 address += PAGE_SIZE) {
8334 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
8335 OSKextLog(this,
8336 kOSKextLogErrorLevel |
8337 kOSKextLogLoadFlag,
8338 "Kext %s - page %p is not backed by physical memory.",
8339 getIdentifierCString(),
8340 (void *)address);
8341 return false;
8342 }
8343 }
8344
8345 return true;
8346 }
8347
8348 /*********************************************************************
8349 *********************************************************************/
8350 static void
8351 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8352 {
8353 uint64_t stamp = 0;
8354 firehose_tracepoint_id_u trace_id;
8355 struct firehose_trace_uuid_info_s uuid_info_s;
8356 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8357 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8358 OSSharedPtr<OSData> uuid_data;
8359
8360 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
8361 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8362
8363 uuid_data = aKext->copyTextUUID();
8364 if (uuid_data) {
8365 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
8366 }
8367
8368 uuid_info->ftui_size = size;
8369 if (aKext->isDriverKit()) {
8370 uuid_info->ftui_address = address;
8371 } else {
8372 uuid_info->ftui_address = ml_static_unslide(address);
8373 }
8374 os_log_encoded_metadata(trace_id, stamp, uuid_info, uuid_info_len);
8375 return;
8376 }
8377
8378 void
8379 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8380 {
8381 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
8382 }
8383
8384 /*********************************************************************
8385 *********************************************************************/
8386 OSReturn
8387 OSKext::start(bool startDependenciesFlag)
8388 {
8389 OSReturn result = kOSReturnError;
8390 kern_return_t (* startfunc)(kmod_info_t *, void *);
8391 unsigned int i, count;
8392 void * kmodStartData = NULL;
8393
8394 if (isStarted() || isInterface() || isKernelComponent()) {
8395 result = kOSReturnSuccess;
8396 goto finish;
8397 }
8398
8399 if (!isLoaded()) {
8400 OSKextLog(this,
8401 kOSKextLogErrorLevel |
8402 kOSKextLogLoadFlag,
8403 "Attempt to start nonloaded kext %s.",
8404 getIdentifierCString());
8405 result = kOSKextReturnInvalidArgument;
8406 goto finish;
8407 }
8408
8409 if (!sLoadEnabled) {
8410 OSKextLog(this,
8411 kOSKextLogErrorLevel |
8412 kOSKextLogLoadFlag,
8413 "Kext loading is disabled (attempt to start kext %s).",
8414 getIdentifierCString());
8415 result = kOSKextReturnDisabled;
8416 goto finish;
8417 }
8418
8419 result = validateKextMapping(/* start? */ true);
8420 if (result != kOSReturnSuccess) {
8421 goto finish;
8422 }
8423
8424 startfunc = kmod_info->start;
8425
8426 count = getNumDependencies();
8427 for (i = 0; i < count; i++) {
8428 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8429 if (dependency == NULL) {
8430 OSKextLog(this,
8431 kOSKextLogErrorLevel |
8432 kOSKextLogLoadFlag,
8433 "Kext %s start - internal error, dependency disappeared.",
8434 getIdentifierCString());
8435 goto finish;
8436 }
8437 if (!dependency->isStarted()) {
8438 if (startDependenciesFlag) {
8439 OSReturn dependencyResult =
8440 dependency->start(startDependenciesFlag);
8441 if (dependencyResult != KERN_SUCCESS) {
8442 OSKextLog(this,
8443 kOSKextLogErrorLevel |
8444 kOSKextLogLoadFlag,
8445 "Kext %s start - dependency %s failed to start (error 0x%x).",
8446 getIdentifierCString(),
8447 dependency->getIdentifierCString(),
8448 dependencyResult);
8449 goto finish;
8450 }
8451 } else {
8452 OSKextLog(this,
8453 kOSKextLogErrorLevel |
8454 kOSKextLogLoadFlag,
8455 "Not starting %s - dependency %s not started yet.",
8456 getIdentifierCString(),
8457 dependency->getIdentifierCString());
8458 result = kOSKextReturnStartStopError; // xxx - make new return?
8459 goto finish;
8460 }
8461 }
8462 }
8463
8464 OSKextLog(this,
8465 kOSKextLogDetailLevel |
8466 kOSKextLogLoadFlag,
8467 "Kext %s calling module start function.",
8468 getIdentifierCString());
8469
8470 flags.starting = 1;
8471
8472 // Drop a log message so logd can grab the needed information to decode this kext
8473 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
8474 result = OSRuntimeInitializeCPP(this);
8475 if (result == KERN_SUCCESS) {
8476 result = startfunc(kmod_info, kmodStartData);
8477 }
8478
8479 flags.starting = 0;
8480
8481 /* On success overlap the setting of started/starting. On failure just
8482 * clear starting.
8483 */
8484 if (result == KERN_SUCCESS) {
8485 flags.started = 1;
8486
8487 // xxx - log start error from kernel?
8488 OSKextLog(this,
8489 kOSKextLogProgressLevel |
8490 kOSKextLogLoadFlag,
8491 "Kext %s is now started.",
8492 getIdentifierCString());
8493 } else {
8494 invokeOrCancelRequestCallbacks(
8495 /* result not actually used */ kOSKextReturnStartStopError,
8496 /* invokeFlag */ false);
8497 OSKextLog(this,
8498 kOSKextLogWarningLevel |
8499 kOSKextLogLoadFlag,
8500 "Kext %s did not start (return code 0x%x).",
8501 getIdentifierCString(), result);
8502 }
8503
8504 finish:
8505 return result;
8506 }
8507
8508 /*********************************************************************
8509 *********************************************************************/
8510 /* static */
8511 bool
8512 OSKext::canUnloadKextWithIdentifier(
8513 OSString * kextIdentifier,
8514 bool checkClassesFlag)
8515 {
8516 bool result = false;
8517 OSKext * aKext = NULL; // do not release
8518
8519 IORecursiveLockLock(sKextLock);
8520
8521 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8522
8523 if (!aKext) {
8524 goto finish; // can't unload what's not loaded
8525 }
8526
8527 if (aKext->isLoaded()) {
8528 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8529 goto finish;
8530 }
8531 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8532 goto finish;
8533 }
8534 }
8535
8536 result = true;
8537
8538 finish:
8539 IORecursiveLockUnlock(sKextLock);
8540 return result;
8541 }
8542
8543 /*********************************************************************
8544 *********************************************************************/
8545 OSReturn
8546 OSKext::stop(void)
8547 {
8548 OSReturn result = kOSReturnError;
8549 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8550
8551 if (!isStarted() || isInterface()) {
8552 result = kOSReturnSuccess;
8553 goto finish;
8554 }
8555
8556 if (!isLoaded()) {
8557 OSKextLog(this,
8558 kOSKextLogErrorLevel |
8559 kOSKextLogLoadFlag,
8560 "Attempt to stop nonloaded kext %s.",
8561 getIdentifierCString());
8562 result = kOSKextReturnInvalidArgument;
8563 goto finish;
8564 }
8565
8566 /* Refuse to stop if we have clients or instances. It is up to
8567 * the caller to make sure those aren't true.
8568 */
8569 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8570 OSKextLog(this,
8571 kOSKextLogErrorLevel |
8572 kOSKextLogLoadFlag,
8573 "Kext %s - C++ instances; can't stop.",
8574 getIdentifierCString());
8575 result = kOSKextReturnInUse;
8576 goto finish;
8577 }
8578
8579 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8580 OSKextLog(this,
8581 kOSKextLogErrorLevel |
8582 kOSKextLogLoadFlag,
8583 "Kext %s - has references (linkage or tracking object); "
8584 "can't stop.",
8585 getIdentifierCString());
8586 result = kOSKextReturnInUse;
8587 goto finish;
8588 }
8589
8590 /* Note: If validateKextMapping fails on the stop & unload path,
8591 * we are in serious trouble and a kernel panic is likely whether
8592 * we stop & unload the kext or not.
8593 */
8594 result = validateKextMapping(/* start? */ false);
8595 if (result != kOSReturnSuccess) {
8596 goto finish;
8597 }
8598
8599 stopfunc = kmod_info->stop;
8600 if (stopfunc) {
8601 OSKextLog(this,
8602 kOSKextLogDetailLevel |
8603 kOSKextLogLoadFlag,
8604 "Kext %s calling module stop function.",
8605 getIdentifierCString());
8606
8607 flags.stopping = 1;
8608
8609 result = stopfunc(kmod_info, /* userData */ NULL);
8610 if (result == KERN_SUCCESS) {
8611 result = OSRuntimeFinalizeCPP(this);
8612 }
8613
8614 flags.stopping = 0;
8615
8616 if (result == KERN_SUCCESS) {
8617 flags.started = 0;
8618
8619 OSKextLog(this,
8620 kOSKextLogDetailLevel |
8621 kOSKextLogLoadFlag,
8622 "Kext %s is now stopped and ready to unload.",
8623 getIdentifierCString());
8624 } else {
8625 OSKextLog(this,
8626 kOSKextLogErrorLevel |
8627 kOSKextLogLoadFlag,
8628 "Kext %s did not stop (return code 0x%x).",
8629 getIdentifierCString(), result);
8630 result = kOSKextReturnStartStopError;
8631 }
8632 }
8633
8634 finish:
8635 // Drop a log message so logd can update this kext's metadata
8636 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
8637 return result;
8638 }
8639
8640 /*********************************************************************
8641 *********************************************************************/
8642 OSReturn
8643 OSKext::unload(void)
8644 {
8645 OSReturn result = kOSReturnError;
8646 unsigned int index;
8647 uint32_t num_kmod_refs = 0;
8648 OSKextAccount * freeAccount;
8649 bool in_fileset = false;
8650
8651 if (!sUnloadEnabled) {
8652 OSKextLog(this,
8653 kOSKextLogErrorLevel |
8654 kOSKextLogLoadFlag,
8655 "Kext unloading is disabled (%s).",
8656 this->getIdentifierCString());
8657
8658 result = kOSKextReturnDisabled;
8659 goto finish;
8660 }
8661
8662 // cache this result so we don't need to access the kmod_info after
8663 // it's been potentially free'd
8664 in_fileset = isInFileset();
8665
8666 /* Refuse to unload if we have clients or instances. It is up to
8667 * the caller to make sure those aren't true.
8668 */
8669 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8670 // xxx - Don't log under errors? this is more of an info thing
8671 OSKextLog(this,
8672 kOSKextLogErrorLevel |
8673 kOSKextLogKextBookkeepingFlag,
8674 "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8675 getIdentifierCString(), getRetainCount());
8676 result = kOSKextReturnInUse;
8677 goto finish;
8678 }
8679
8680 if (isDriverKit()) {
8681 index = sLoadedDriverKitKexts->getNextIndexOfObject(this, 0);
8682 if (index != (unsigned int)-1) {
8683 sLoadedDriverKitKexts->removeObject(index);
8684 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
8685 loadTag = 0;
8686 }
8687 }
8688
8689 if (!isLoaded()) {
8690 result = kOSReturnSuccess;
8691 goto finish;
8692 }
8693
8694 if (isKernelComponent()) {
8695 result = kOSKextReturnInvalidArgument;
8696 goto finish;
8697 }
8698
8699 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
8700 OSKextLog(this,
8701 kOSKextLogErrorLevel |
8702 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8703 "Can't unload kext %s; classes have instances:",
8704 getIdentifierCString());
8705 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8706 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8707 result = kOSKextReturnInUse;
8708 goto finish;
8709 }
8710
8711 /* Note that the kext is unloading before running any code that
8712 * might be in the kext (request callbacks, module stop function).
8713 * We will deny certain requests made against a kext in the process
8714 * of unloading.
8715 */
8716 flags.unloading = 1;
8717
8718 /* Update the string describing the last kext to unload in case we panic.
8719 */
8720 savePanicString(/* isLoading */ false);
8721
8722 if (isStarted()) {
8723 result = stop();
8724 if (result != KERN_SUCCESS) {
8725 OSKextLog(this,
8726 kOSKextLogErrorLevel |
8727 kOSKextLogLoadFlag,
8728 "Kext %s can't unload - module stop returned 0x%x.",
8729 getIdentifierCString(), (unsigned)result);
8730 result = kOSKextReturnStartStopError;
8731 goto finish;
8732 }
8733 }
8734
8735 OSKextLog(this,
8736 kOSKextLogProgressLevel |
8737 kOSKextLogLoadFlag,
8738 "Kext %s unloading.",
8739 getIdentifierCString());
8740
8741 {
8742 struct list_head *p;
8743 struct list_head *prev;
8744 struct list_head *next;
8745 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8746 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8747 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
8748 prev = p->prev;
8749 next = p->next;
8750 prev->next = next;
8751 next->prev = prev;
8752 p->prev = p;
8753 p->next = p;
8754 IORecursiveLockWakeup(sKextLock, s, false);
8755 }
8756 }
8757
8758
8759 /* Even if we don't call the stop function, we want to be sure we
8760 * have no OSMetaClass references before unloading the kext executable
8761 * from memory. OSMetaClasses may have pointers into the kext executable
8762 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8763 */
8764 if (metaClasses) {
8765 metaClasses->flushCollection();
8766 }
8767 (void) OSRuntimeFinalizeCPP(this);
8768
8769 /* Remove the kext from the list of loaded kexts, patch the gap
8770 * in the kmod_info_t linked list, and reset "kmod" to point to the
8771 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8772 */
8773 index = sLoadedKexts->getNextIndexOfObject(this, 0);
8774 if (index != (unsigned int)-1) {
8775 sLoadedKexts->removeObject(index);
8776
8777 OSKext * nextKext = OSDynamicCast(OSKext,
8778 sLoadedKexts->getObject(index));
8779
8780 if (nextKext) {
8781 if (index > 0) {
8782 OSKext * gapKext = OSDynamicCast(OSKext,
8783 sLoadedKexts->getObject(index - 1));
8784
8785 nextKext->kmod_info->next = gapKext->kmod_info;
8786 } else { /* index == 0 */
8787 nextKext->kmod_info->next = NULL;
8788 }
8789 }
8790
8791 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8792 if (lastKext && !lastKext->isKernel()) {
8793 kmod = lastKext->kmod_info;
8794 } else {
8795 kmod = NULL; // clear the global kmod variable
8796 }
8797 }
8798
8799 /* Clear out the kmod references that we're keeping for compatibility
8800 * with current panic backtrace code & kgmacros.
8801 * xxx - will want to update those bits sometime and remove this.
8802 */
8803 num_kmod_refs = getNumDependencies();
8804 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8805 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8806 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8807 ref->info->reference_count--;
8808 }
8809 kfree_type(kmod_reference_t, num_kmod_refs,
8810 kmod_info->reference_list);
8811 }
8812
8813 #if CONFIG_DTRACE
8814 unregisterWithDTrace();
8815 #endif /* CONFIG_DTRACE */
8816
8817 notifyKextUnloadObservers(this);
8818
8819 freeAccount = NULL;
8820 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
8821 account->kext = NULL;
8822 if (account->site.tag) {
8823 account->site.flags |= VM_TAG_UNLOAD;
8824 } else {
8825 freeAccount = account;
8826 }
8827
8828 #if DEVELOPMENT || DEBUG
8829 assertf(account->task_refgrp.grp_count == 0,
8830 "unloading a kext with active task references");
8831 #endif /* DEVELOPMENT || DEBUG */
8832
8833 lck_ticket_unlock(sKextAccountsLock);
8834 if (freeAccount) {
8835 IOFreeType(freeAccount, OSKextAccount);
8836 }
8837
8838 /* Unwire and free the linked executable.
8839 */
8840 if (linkedExecutable) {
8841 #if KASAN
8842 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8843 #endif
8844
8845 #if VM_MAPPED_KEXTS
8846 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8847 kernel_segment_command_t *seg = NULL;
8848 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8849
8850 if (!kext_map) {
8851 OSKextLog(this,
8852 kOSKextLogErrorLevel |
8853 kOSKextLogLoadFlag,
8854 "Failed to free kext %s; couldn't find the kext map.",
8855 getIdentifierCString());
8856 result = kOSKextReturnInternalError;
8857 goto finish;
8858 }
8859
8860 OSKextLog(this,
8861 kOSKextLogProgressLevel |
8862 kOSKextLogLoadFlag,
8863 "Kext %s unwiring and unmapping linked executable.",
8864 getIdentifierCString());
8865
8866 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8867 while (seg) {
8868 if (segmentShouldBeWired(seg)) {
8869 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8870 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8871
8872 result = vm_map_unwire(kext_map, start_wire,
8873 end_wire, FALSE);
8874 if (result != KERN_SUCCESS) {
8875 OSKextLog(this,
8876 kOSKextLogErrorLevel |
8877 kOSKextLogLoadFlag,
8878 "Failed to unwire kext %s.",
8879 getIdentifierCString());
8880 result = kOSKextReturnInternalError;
8881 goto finish;
8882 }
8883 }
8884
8885 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8886 }
8887 #if defined(__x86_64__) || defined(__i386__)
8888 if (in_fileset && flags.resetSegmentsFromVnode) {
8889 IORecursiveLockLock(sKextLock);
8890 resetKCFileSetSegments();
8891 IORecursiveLockUnlock(sKextLock);
8892 }
8893 #endif // (__x86_64__) || defined(__i386__)
8894 }
8895 #endif /* VM_MAPPED_KEXTS */
8896 if (flags.resetSegmentsFromImmutableCopy) {
8897 result = resetMutableSegments();
8898 if (result != kOSReturnSuccess) {
8899 OSKextLog(this,
8900 kOSKextLogErrorLevel |
8901 kOSKextLogLoadFlag,
8902 "Failed to reset kext %s.",
8903 getIdentifierCString());
8904 result = kOSKextReturnInternalError;
8905 goto finish;
8906 }
8907 }
8908 if (kc_type == KCKindUnknown) {
8909 linkedExecutable.reset();
8910 }
8911 }
8912
8913 /* An interface kext has a fake kmod_info that was allocated,
8914 * so we have to free it.
8915 */
8916 if (isInterface()) {
8917 kfree_type(kmod_info_t, kmod_info);
8918 kmod_info = NULL;
8919 }
8920
8921 if (!in_fileset) {
8922 kmod_info = NULL;
8923 }
8924
8925 flags.loaded = false;
8926 flushDependencies();
8927
8928 /* save a copy of the bundle ID for us to check when deciding to
8929 * rebuild the kernel cache file. If a kext was already in the kernel
8930 * cache and unloaded then later loaded we do not need to rebuild the
8931 * kernel cache. 9055303
8932 */
8933 if (isPrelinked()) {
8934 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
8935 IORecursiveLockLock(sKextLock);
8936 if (sUnloadedPrelinkedKexts) {
8937 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8938 }
8939 IORecursiveLockUnlock(sKextLock);
8940 }
8941 }
8942
8943 OSKextLog(this,
8944 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8945 "Kext %s unloaded.", getIdentifierCString());
8946
8947 queueKextNotification(kKextRequestPredicateUnloadNotification,
8948 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
8949
8950 finish:
8951 OSKext::saveLoadedKextPanicList();
8952 OSKext::updateLoadedKextSummaries();
8953
8954 flags.unloading = 0;
8955 return result;
8956 }
8957
8958 /*********************************************************************
8959 * Assumes sKextLock is held.
8960 *********************************************************************/
8961 /* static */
8962 OSReturn
8963 OSKext::queueKextNotification(
8964 const char * notificationName,
8965 OSString * kextIdentifier,
8966 OSData * dextUniqueIdentifier)
8967 {
8968 OSReturn result = kOSReturnError;
8969 OSSharedPtr<OSDictionary> loadRequest;
8970
8971 if (!kextIdentifier) {
8972 result = kOSKextReturnInvalidArgument;
8973 goto finish;
8974 }
8975
8976 /* Create a new request unless one is already sitting
8977 * in sKernelRequests for this bundle identifier
8978 */
8979 result = _OSKextCreateRequest(notificationName, loadRequest);
8980 if (result != kOSReturnSuccess) {
8981 goto finish;
8982 }
8983 if (!_OSKextSetRequestArgument(loadRequest.get(),
8984 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8985 result = kOSKextReturnNoMemory;
8986 goto finish;
8987 }
8988 if (NULL != dextUniqueIdentifier) {
8989 if (!_OSKextSetRequestArgument(loadRequest.get(),
8990 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
8991 result = kOSKextReturnNoMemory;
8992 goto finish;
8993 }
8994 }
8995 if (!sKernelRequests->setObject(loadRequest.get())) {
8996 result = kOSKextReturnNoMemory;
8997 goto finish;
8998 }
8999
9000 /* We might want to only queue the notification if the IOKit daemon is active,
9001 * but that wouldn't work for embedded. Note that we don't care if
9002 * the ping immediately succeeds here so don't do anything with the
9003 * result of this call.
9004 */
9005 OSKext::pingIOKitDaemon();
9006
9007 result = kOSReturnSuccess;
9008
9009 finish:
9010 return result;
9011 }
9012
9013
9014 #if CONFIG_KXLD
9015 /*********************************************************************
9016 *********************************************************************/
9017 static void
9018 _OSKextConsiderDestroyingLinkContext(
9019 __unused thread_call_param_t p0,
9020 __unused thread_call_param_t p1)
9021 {
9022 /* Take multiple locks in the correct order.
9023 */
9024 IORecursiveLockLock(sKextLock);
9025 IORecursiveLockLock(sKextInnerLock);
9026
9027 /* The first time we destroy the kxldContext is in the first
9028 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
9029 * before calling this function. Thereafter any call to this function
9030 * will actually destroy the context.
9031 */
9032 if (sConsiderUnloadsCalled && sKxldContext) {
9033 kxld_destroy_context(sKxldContext);
9034 sKxldContext = NULL;
9035 }
9036
9037 /* Free the thread_call that was allocated to execute this function.
9038 */
9039 if (sDestroyLinkContextThread) {
9040 if (!thread_call_free(sDestroyLinkContextThread)) {
9041 OSKextLog(/* kext */ NULL,
9042 kOSKextLogErrorLevel |
9043 kOSKextLogGeneralFlag,
9044 "thread_call_free() failed for kext link context.");
9045 }
9046 sDestroyLinkContextThread = NULL;
9047 }
9048
9049 IORecursiveLockUnlock(sKextInnerLock);
9050 IORecursiveLockUnlock(sKextLock);
9051
9052 return;
9053 }
9054
9055 /*********************************************************************
9056 * Destroying the kxldContext requires checking variables under both
9057 * sKextInnerLock and sKextLock, so we do it on a separate thread
9058 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
9059 * call relationship.
9060 *
9061 * This function must be invoked with sKextInnerLock held.
9062 * Do not call any function that takes sKextLock here!
9063 *********************************************************************/
9064 /* static */
9065 void
9066 OSKext::considerDestroyingLinkContext(void)
9067 {
9068 IORecursiveLockLock(sKextInnerLock);
9069
9070 /* If we have already queued a thread to destroy the link context,
9071 * don't bother resetting; that thread will take care of it.
9072 */
9073 if (sDestroyLinkContextThread) {
9074 goto finish;
9075 }
9076
9077 /* The function to be invoked in the thread will deallocate
9078 * this thread_call, so don't share it around.
9079 */
9080 sDestroyLinkContextThread = thread_call_allocate(
9081 &_OSKextConsiderDestroyingLinkContext, NULL);
9082 if (!sDestroyLinkContextThread) {
9083 OSKextLog(/* kext */ NULL,
9084 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
9085 "Can't create thread to destroy kext link context.");
9086 goto finish;
9087 }
9088
9089 thread_call_enter(sDestroyLinkContextThread);
9090
9091 finish:
9092 IORecursiveLockUnlock(sKextInnerLock);
9093 return;
9094 }
9095
9096 #else // !CONFIG_KXLD
9097
9098 /* static */
9099 void
9100 OSKext::considerDestroyingLinkContext(void)
9101 {
9102 return;
9103 }
9104
9105 #endif // CONFIG_KXLD
9106
9107 #if PRAGMA_MARK
9108 #pragma mark Autounload
9109 #endif
9110 /*********************************************************************
9111 * This is a static method because the kext will be deallocated if it
9112 * does unload!
9113 *********************************************************************/
9114 /* static */
9115 OSReturn
9116 OSKext::autounloadKext(OSKext * aKext)
9117 {
9118 OSReturn result = kOSKextReturnInUse;
9119
9120 #if NO_KEXTD
9121 /*
9122 * Do not unload prelinked kexts on platforms that do not have an
9123 * IOKit daemon as there is no way to reload the kext or restart
9124 * matching.
9125 */
9126 if (aKext->isPrelinked()) {
9127 goto finish;
9128 }
9129 #endif /* defined(__x86_64__) */
9130
9131 /* Check for external references to this kext (usu. dependents),
9132 * instances of defined classes (or classes derived from them),
9133 * outstanding requests.
9134 */
9135 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
9136 !aKext->flags.autounloadEnabled ||
9137 aKext->isKernelComponent()) {
9138 goto finish;
9139 }
9140
9141 /* Skip a delay-autounload kext, once.
9142 */
9143 if (aKext->flags.delayAutounload) {
9144 OSKextLog(aKext,
9145 kOSKextLogProgressLevel |
9146 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
9147 "Kext %s has delayed autounload set; skipping and clearing flag.",
9148 aKext->getIdentifierCString());
9149 aKext->flags.delayAutounload = 0;
9150 goto finish;
9151 }
9152
9153 if (aKext->hasOSMetaClassInstances() ||
9154 aKext->countRequestCallbacks()) {
9155 goto finish;
9156 }
9157
9158 result = OSKext::removeKext(aKext);
9159
9160 finish:
9161 return result;
9162 }
9163
9164 /*********************************************************************
9165 *********************************************************************/
9166 void
9167 _OSKextConsiderUnloads(
9168 __unused thread_call_param_t p0,
9169 __unused thread_call_param_t p1)
9170 {
9171 bool didUnload = false;
9172 unsigned int count, i;
9173
9174 /* Take multiple locks in the correct order
9175 * (note also sKextSummaries lock further down).
9176 */
9177 IORecursiveLockLock(sKextLock);
9178 IORecursiveLockLock(sKextInnerLock);
9179
9180 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
9181
9182 /* If the system is powering down, don't try to unload anything.
9183 */
9184 if (sSystemSleep) {
9185 goto finish;
9186 }
9187
9188 OSKextLog(/* kext */ NULL,
9189 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
9190 "Checking for unused kexts to autounload.");
9191
9192 /*****
9193 * Remove any request callbacks marked as stale,
9194 * and mark as stale any currently in flight.
9195 */
9196 count = sRequestCallbackRecords->getCount();
9197 if (count) {
9198 i = count - 1;
9199 do {
9200 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
9201 sRequestCallbackRecords->getObject(i));
9202 if (callbackRecord) {
9203 OSBoolean * stale = OSDynamicCast(OSBoolean,
9204 callbackRecord->getObject(kKextRequestStaleKey));
9205
9206 if (stale == kOSBooleanTrue) {
9207 OSKext::invokeRequestCallback(callbackRecord,
9208 kOSKextReturnTimeout);
9209 } else {
9210 callbackRecord->setObject(kKextRequestStaleKey,
9211 kOSBooleanTrue);
9212 }
9213 }
9214 } while (i--);
9215 }
9216
9217 /*****
9218 * Make multiple passes through the array of loaded kexts until
9219 * we don't unload any. This handles unwinding of dependency
9220 * chains. We have to go *backwards* through the array because
9221 * kexts are removed from it when unloaded, and we cannot make
9222 * a copy or we'll mess up the retain counts we rely on to
9223 * check whether a kext will unload. If only we could have
9224 * nonretaining collections like CF has....
9225 */
9226 do {
9227 didUnload = false;
9228
9229 count = sLoadedKexts->getCount();
9230 if (count) {
9231 i = count - 1;
9232 do {
9233 OSKext * thisKext = OSDynamicCast(OSKext,
9234 sLoadedKexts->getObject(i));
9235 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
9236 } while (i--);
9237 }
9238 } while (didUnload);
9239
9240 finish:
9241 sConsiderUnloadsPending = false;
9242 sConsiderUnloadsExecuted = true;
9243
9244 (void) OSKext::considerRebuildOfPrelinkedKernel();
9245
9246 IORecursiveLockUnlock(sKextInnerLock);
9247 IORecursiveLockUnlock(sKextLock);
9248
9249 return;
9250 }
9251
9252 /*********************************************************************
9253 * Do not call any function that takes sKextLock here!
9254 *********************************************************************/
9255 void
9256 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
9257 {
9258 AbsoluteTime when;
9259
9260 IORecursiveLockLock(sKextInnerLock);
9261
9262 if (!sUnloadCallout) {
9263 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
9264 }
9265
9266 /* we only reset delay value for unloading if we already have something
9267 * pending. rescheduleOnlyFlag should not start the count down.
9268 */
9269 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9270 goto finish;
9271 }
9272
9273 thread_call_cancel(sUnloadCallout);
9274 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9275 #if !NO_KEXTD
9276 && sIOKitDaemonActive
9277 #endif
9278 ) {
9279 clock_interval_to_deadline(sConsiderUnloadDelay,
9280 1000 * 1000 * 1000, &when);
9281
9282 OSKextLog(/* kext */ NULL,
9283 kOSKextLogProgressLevel |
9284 kOSKextLogLoadFlag,
9285 "%scheduling %sscan for unused kexts in %lu seconds.",
9286 sConsiderUnloadsPending ? "Res" : "S",
9287 sConsiderUnloadsCalled ? "" : "initial ",
9288 (unsigned long)sConsiderUnloadDelay);
9289
9290 sConsiderUnloadsPending = true;
9291 thread_call_enter_delayed(sUnloadCallout, when);
9292 }
9293
9294 finish:
9295 /* The kxld context should be reused throughout boot. We mark the end of
9296 * period as the first time considerUnloads() is called, and we destroy
9297 * the first kxld context in that function. Afterwards, it will be
9298 * destroyed in flushNonloadedKexts.
9299 */
9300 if (!sConsiderUnloadsCalled) {
9301 sConsiderUnloadsCalled = true;
9302 OSKext::considerDestroyingLinkContext();
9303 }
9304
9305 IORecursiveLockUnlock(sKextInnerLock);
9306 return;
9307 }
9308
9309 /*********************************************************************
9310 * Do not call any function that takes sKextLock here!
9311 *********************************************************************/
9312 extern "C" {
9313 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9314 IOReturn
9315 OSKextSystemSleepOrWake(UInt32 messageType)
9316 {
9317 IORecursiveLockLock(sKextInnerLock);
9318
9319 /* If the system is going to sleep, cancel the reaper thread timer,
9320 * and note that we're in a sleep state in case it just fired but hasn't
9321 * taken the lock yet. If we are coming back from sleep, just
9322 * clear the sleep flag; IOService's normal operation will cause
9323 * unloads to be considered soon enough.
9324 */
9325 if (messageType == kIOMessageSystemWillSleep) {
9326 if (sUnloadCallout) {
9327 thread_call_cancel(sUnloadCallout);
9328 }
9329 sSystemSleep = true;
9330 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9331 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9332 sSystemSleep = false;
9333 clock_get_uptime(&sLastWakeTime);
9334 }
9335 IORecursiveLockUnlock(sKextInnerLock);
9336
9337 return kIOReturnSuccess;
9338 }
9339 };
9340
9341
9342 #if PRAGMA_MARK
9343 #pragma mark Prelinked Kernel
9344 #endif
9345
9346 #ifdef CONFIG_KXLD
9347 /*********************************************************************
9348 * Do not access sConsiderUnloads... variables other than
9349 * sConsiderUnloadsExecuted in this function. They are guarded by a
9350 * different lock.
9351 *********************************************************************/
9352 /* static */
9353 void
9354 OSKext::considerRebuildOfPrelinkedKernel(void)
9355 {
9356 static bool requestedPrelink = false;
9357 OSReturn checkResult = kOSReturnError;
9358 OSSharedPtr<OSDictionary> prelinkRequest;
9359 OSSharedPtr<OSCollectionIterator> kextIterator;
9360 const OSSymbol * thisID = NULL; // do not release
9361 bool doRebuild = false;
9362 AbsoluteTime my_abstime;
9363 UInt64 my_ns;
9364 SInt32 delta_secs;
9365
9366 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9367 if (requestedPrelink || !sPrelinkBoot) {
9368 return;
9369 }
9370
9371 /* no direct return from this point */
9372 IORecursiveLockLock(sKextLock);
9373
9374 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9375 * and any new startup kexts loaded.
9376 */
9377 if (!sConsiderUnloadsExecuted ||
9378 !sDeferredLoadSucceeded) {
9379 goto finish;
9380 }
9381
9382 /* we really only care about boot / system start up related kexts so bail
9383 * if we're here after REBUILD_MAX_TIME.
9384 */
9385 if (!_OSKextInPrelinkRebuildWindow()) {
9386 OSKextLog(/* kext */ NULL,
9387 kOSKextLogArchiveFlag,
9388 "%s prebuild rebuild has expired",
9389 __FUNCTION__);
9390 requestedPrelink = true;
9391 goto finish;
9392 }
9393
9394 /* we do not want to trigger a rebuild if we get here too close to waking
9395 * up. (see radar 10233768)
9396 */
9397 IORecursiveLockLock(sKextInnerLock);
9398
9399 clock_get_uptime(&my_abstime);
9400 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9401 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9402 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9403 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9404 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9405 }
9406 IORecursiveLockUnlock(sKextInnerLock);
9407
9408 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9409 /* too close to time of last wake from sleep */
9410 goto finish;
9411 }
9412 requestedPrelink = true;
9413
9414 /* Now it's time to see if we have a reason to rebuild. We may have done
9415 * some loads and unloads but the kernel cache didn't actually change.
9416 * We will rebuild if any kext is not marked prelinked AND is not in our
9417 * list of prelinked kexts that got unloaded. (see radar 9055303)
9418 */
9419 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9420 if (!kextIterator) {
9421 goto finish;
9422 }
9423
9424 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9425 OSKext * thisKext; // do not release
9426
9427 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9428 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9429 continue;
9430 }
9431
9432 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9433 continue;
9434 }
9435 /* kext is loaded and was not in current kernel cache so let's rebuild
9436 */
9437 doRebuild = true;
9438 OSKextLog(/* kext */ NULL,
9439 kOSKextLogArchiveFlag,
9440 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9441 thisKext->bundleID->getCStringNoCopy());
9442 break;
9443 }
9444 sUnloadedPrelinkedKexts->flushCollection();
9445
9446 if (!doRebuild) {
9447 goto finish;
9448 }
9449
9450 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9451 prelinkRequest);
9452 if (checkResult != kOSReturnSuccess) {
9453 goto finish;
9454 }
9455
9456 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9457 goto finish;
9458 }
9459
9460 OSKext::pingIOKitDaemon();
9461
9462 finish:
9463 IORecursiveLockUnlock(sKextLock);
9464
9465 return;
9466 }
9467
9468 #else /* !CONFIG_KXLD */
9469
9470 void
9471 OSKext::considerRebuildOfPrelinkedKernel(void)
9472 {
9473 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9474 return;
9475 }
9476
9477 #endif /* CONFIG_KXLD */
9478
9479 #if PRAGMA_MARK
9480 #pragma mark Dependencies
9481 #endif
9482 /*********************************************************************
9483 *********************************************************************/
9484 bool
9485 OSKext::resolveDependencies(
9486 OSArray * loopStack)
9487 {
9488 bool result = false;
9489 OSSharedPtr<OSArray> localLoopStack;
9490 bool addedToLoopStack = false;
9491 OSDictionary * libraries = NULL; // do not release
9492 OSSharedPtr<OSCollectionIterator> libraryIterator;
9493 OSString * libraryID = NULL; // do not release
9494 OSKext * libraryKext = NULL; // do not release
9495 bool hasRawKernelDependency = false;
9496 bool hasKernelDependency = false;
9497 bool hasKPIDependency = false;
9498 bool hasPrivateKPIDependency = false;
9499 unsigned int count;
9500
9501 #if CONFIG_KXLD
9502 OSString * infoString = NULL; // do not release
9503 OSString * readableString = NULL; // do not release
9504 #endif // CONFIG_KXLD
9505
9506 /* A kernel component will automatically have this flag set,
9507 * and a loaded kext should also have it set (as should all its
9508 * loaded dependencies).
9509 */
9510 if (flags.hasAllDependencies) {
9511 result = true;
9512 goto finish;
9513 }
9514
9515 /* Check for loops in the dependency graph.
9516 */
9517 if (loopStack) {
9518 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
9519 OSKextLog(this,
9520 kOSKextLogErrorLevel |
9521 kOSKextLogDependenciesFlag,
9522 "Kext %s has a dependency loop; can't resolve dependencies.",
9523 getIdentifierCString());
9524 goto finish;
9525 }
9526 } else {
9527 OSKextLog(this,
9528 kOSKextLogStepLevel |
9529 kOSKextLogDependenciesFlag,
9530 "Kext %s resolving dependencies.",
9531 getIdentifierCString());
9532
9533 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
9534 if (!localLoopStack) {
9535 OSKextLog(this,
9536 kOSKextLogErrorLevel |
9537 kOSKextLogDependenciesFlag,
9538 "Kext %s can't create bookkeeping stack to resolve dependencies.",
9539 getIdentifierCString());
9540 goto finish;
9541 }
9542 loopStack = localLoopStack.get();
9543 }
9544 if (!loopStack->setObject(this)) {
9545 OSKextLog(this,
9546 kOSKextLogErrorLevel |
9547 kOSKextLogDependenciesFlag,
9548 "Kext %s - internal error resolving dependencies.",
9549 getIdentifierCString());
9550 goto finish;
9551 }
9552 addedToLoopStack = true;
9553
9554 /* Purge any existing kexts in the dependency list and start over.
9555 */
9556 flushDependencies();
9557 if (dependencies) {
9558 OSKextLog(this,
9559 kOSKextLogErrorLevel |
9560 kOSKextLogDependenciesFlag,
9561 "Kext %s - internal error resolving dependencies.",
9562 getIdentifierCString());
9563 }
9564
9565 libraries = OSDynamicCast(OSDictionary,
9566 getPropertyForHostArch(kOSBundleLibrariesKey));
9567 if (libraries == NULL || libraries->getCount() == 0) {
9568 OSKextLog(this,
9569 kOSKextLogErrorLevel |
9570 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9571 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9572 getIdentifierCString(), kOSBundleLibrariesKey);
9573 goto finish;
9574 }
9575
9576 /* Make a new array to hold the dependencies (flush freed the old one).
9577 */
9578 dependencies = OSArray::withCapacity(libraries->getCount());
9579 if (!dependencies) {
9580 OSKextLog(this,
9581 kOSKextLogErrorLevel |
9582 kOSKextLogDependenciesFlag,
9583 "Kext %s - can't allocate dependencies array.",
9584 getIdentifierCString());
9585 goto finish;
9586 }
9587
9588 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9589 // xxx - compat: if none were declared.
9590
9591 libraryIterator = OSCollectionIterator::withCollection(libraries);
9592 if (!libraryIterator) {
9593 OSKextLog(this,
9594 kOSKextLogErrorLevel |
9595 kOSKextLogDependenciesFlag,
9596 "Kext %s - can't allocate dependencies iterator.",
9597 getIdentifierCString());
9598 goto finish;
9599 }
9600
9601 while ((libraryID = OSDynamicCast(OSString,
9602 libraryIterator->getNextObject()))) {
9603 const char * library_id = libraryID->getCStringNoCopy();
9604
9605 OSString * libraryVersion = OSDynamicCast(OSString,
9606 libraries->getObject(libraryID));
9607 if (libraryVersion == NULL) {
9608 OSKextLog(this,
9609 kOSKextLogErrorLevel |
9610 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9611 "Kext %s - illegal type in OSBundleLibraries.",
9612 getIdentifierCString());
9613 goto finish;
9614 }
9615
9616 OSKextVersion libraryVers =
9617 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
9618 if (libraryVers == -1) {
9619 OSKextLog(this,
9620 kOSKextLogErrorLevel |
9621 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9622 "Kext %s - invalid library version %s.",
9623 getIdentifierCString(),
9624 libraryVersion->getCStringNoCopy());
9625 goto finish;
9626 }
9627
9628 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9629 if (libraryKext == NULL) {
9630 OSKextLog(this,
9631 kOSKextLogErrorLevel |
9632 kOSKextLogDependenciesFlag,
9633 "Kext %s - library kext %s not found.",
9634 getIdentifierCString(), library_id);
9635 goto finish;
9636 }
9637
9638 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
9639 OSKextLog(this,
9640 kOSKextLogErrorLevel |
9641 kOSKextLogDependenciesFlag,
9642 "Kext %s - library kext %s not compatible "
9643 "with requested version %s.",
9644 getIdentifierCString(), library_id,
9645 libraryVersion->getCStringNoCopy());
9646 goto finish;
9647 }
9648
9649 /* If a nonprelinked library somehow got into the mix for a
9650 * prelinked kext, at any point in the chain, we must fail
9651 * because the prelinked relocs for the library will be all wrong.
9652 */
9653 if (this->isPrelinked() &&
9654 libraryKext->declaresExecutable() &&
9655 !libraryKext->isPrelinked()) {
9656 OSKextLog(this,
9657 kOSKextLogErrorLevel |
9658 kOSKextLogDependenciesFlag,
9659 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9660 getIdentifierCString(), library_id,
9661 libraryVersion->getCStringNoCopy());
9662 goto finish;
9663 }
9664
9665 if (!libraryKext->resolveDependencies(loopStack)) {
9666 goto finish;
9667 }
9668
9669 /* Add the library directly only if it has an executable to link.
9670 * Otherwise it's just used to collect other dependencies, so put
9671 * *its* dependencies on the list for this kext.
9672 */
9673 // xxx - We are losing info here; would like to make fake entries or
9674 // xxx - keep these in the dependency graph for loaded kexts.
9675 // xxx - I really want to make kernel components not a special case!
9676 if (libraryKext->declaresExecutable() ||
9677 libraryKext->isInterface()) {
9678 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
9679 dependencies->setObject(libraryKext);
9680
9681 OSKextLog(this,
9682 kOSKextLogDetailLevel |
9683 kOSKextLogDependenciesFlag,
9684 "Kext %s added dependency %s.",
9685 getIdentifierCString(),
9686 libraryKext->getIdentifierCString());
9687 }
9688 } else {
9689 int numLibDependencies = libraryKext->getNumDependencies();
9690 OSArray * libraryDependencies = libraryKext->getDependencies();
9691 int index;
9692
9693 if (numLibDependencies) {
9694 // xxx - this msg level should be 1 lower than the per-kext one
9695 OSKextLog(this,
9696 kOSKextLogDetailLevel |
9697 kOSKextLogDependenciesFlag,
9698 "Kext %s pulling %d dependencies from codeless library %s.",
9699 getIdentifierCString(),
9700 numLibDependencies,
9701 libraryKext->getIdentifierCString());
9702 }
9703 for (index = 0; index < numLibDependencies; index++) {
9704 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9705 libraryDependencies->getObject(index));
9706 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
9707 dependencies->setObject(thisLibDependency);
9708 OSKextLog(this,
9709 kOSKextLogDetailLevel |
9710 kOSKextLogDependenciesFlag,
9711 "Kext %s added dependency %s from codeless library %s.",
9712 getIdentifierCString(),
9713 thisLibDependency->getIdentifierCString(),
9714 libraryKext->getIdentifierCString());
9715 }
9716 }
9717 }
9718
9719 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
9720 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
9721 hasRawKernelDependency = true;
9722 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9723 hasKernelDependency = true;
9724 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9725 hasKPIDependency = true;
9726 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
9727 hasPrivateKPIDependency = true;
9728 }
9729 }
9730 }
9731
9732 if (hasRawKernelDependency) {
9733 OSKextLog(this,
9734 kOSKextLogErrorLevel |
9735 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9736 "Error - kext %s declares a dependency on %s, which is not permitted.",
9737 getIdentifierCString(), KERNEL_LIB);
9738 goto finish;
9739 }
9740 #if __LP64__
9741 if (hasKernelDependency) {
9742 OSKextLog(this,
9743 kOSKextLogErrorLevel |
9744 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9745 "Error - kext %s declares %s dependencies. "
9746 "Only %s* dependencies are supported for 64-bit kexts.",
9747 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9748 goto finish;
9749 }
9750 if (!hasKPIDependency) {
9751 OSKextLog(this,
9752 kOSKextLogWarningLevel |
9753 kOSKextLogDependenciesFlag,
9754 "Warning - kext %s declares no %s* dependencies. "
9755 "If it uses any KPIs, the link may fail with undefined symbols.",
9756 getIdentifierCString(), KPI_LIB_PREFIX);
9757 }
9758 #else /* __LP64__ */
9759 // xxx - will change to flatly disallow "kernel" dependencies at some point
9760 // xxx - is it invalid to do both "com.apple.kernel" and any
9761 // xxx - "com.apple.kernel.*"?
9762
9763 if (hasKernelDependency && hasKPIDependency) {
9764 OSKextLog(this,
9765 kOSKextLogWarningLevel |
9766 kOSKextLogDependenciesFlag,
9767 "Warning - kext %s has immediate dependencies on both "
9768 "%s* and %s* components; use only one style.",
9769 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9770 }
9771
9772 if (!hasKernelDependency && !hasKPIDependency) {
9773 // xxx - do we want to use validation flag for these too?
9774 OSKextLog(this,
9775 kOSKextLogWarningLevel |
9776 kOSKextLogDependenciesFlag,
9777 "Warning - %s declares no kernel dependencies; using %s.",
9778 getIdentifierCString(), KERNEL6_LIB);
9779 OSKext * kernelKext = OSDynamicCast(OSKext,
9780 sKextsByID->getObject(KERNEL6_LIB));
9781 if (kernelKext) {
9782 dependencies->setObject(kernelKext);
9783 } else {
9784 OSKextLog(this,
9785 kOSKextLogErrorLevel |
9786 kOSKextLogDependenciesFlag,
9787 "Error - Library %s not found for %s.",
9788 KERNEL6_LIB, getIdentifierCString());
9789 }
9790 }
9791
9792 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9793 * its indirect dependencies to simulate old-style linking. XXX - Should
9794 * check for duplicates.
9795 */
9796 if (!hasKPIDependency) {
9797 unsigned int i;
9798
9799 flags.hasBleedthrough = true;
9800
9801 count = getNumDependencies();
9802
9803 /* We add to the dependencies array in this loop, but do not iterate
9804 * past its original count.
9805 */
9806 for (i = 0; i < count; i++) {
9807 OSKext * dependencyKext = OSDynamicCast(OSKext,
9808 dependencies->getObject(i));
9809 dependencyKext->addBleedthroughDependencies(dependencies.get());
9810 }
9811 }
9812 #endif /* __LP64__ */
9813
9814 #if CONFIG_KXLD
9815 /*
9816 * If we're not dynamically linking kexts, then we don't need to check
9817 * copyright strings. The linker in user space has already done this.
9818 */
9819 if (hasPrivateKPIDependency) {
9820 bool hasApplePrefix = false;
9821 bool infoCopyrightIsValid = false;
9822 bool readableCopyrightIsValid = false;
9823
9824 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9825 APPLE_KEXT_PREFIX);
9826
9827 infoString = OSDynamicCast(OSString,
9828 getPropertyForHostArch("CFBundleGetInfoString"));
9829 if (infoString) {
9830 infoCopyrightIsValid =
9831 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9832 }
9833
9834 readableString = OSDynamicCast(OSString,
9835 getPropertyForHostArch("NSHumanReadableCopyright"));
9836 if (readableString) {
9837 readableCopyrightIsValid =
9838 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9839 }
9840
9841 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9842 OSKextLog(this,
9843 kOSKextLogErrorLevel |
9844 kOSKextLogDependenciesFlag,
9845 "Error - kext %s declares a dependency on %s. "
9846 "Only Apple kexts may declare a dependency on %s.",
9847 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9848 goto finish;
9849 }
9850 }
9851 #endif // CONFIG_KXLD
9852
9853 result = true;
9854 flags.hasAllDependencies = 1;
9855
9856 finish:
9857
9858 if (addedToLoopStack) {
9859 count = loopStack->getCount();
9860 if (count > 0 && (this == loopStack->getObject(count - 1))) {
9861 loopStack->removeObject(count - 1);
9862 } else {
9863 OSKextLog(this,
9864 kOSKextLogErrorLevel |
9865 kOSKextLogDependenciesFlag,
9866 "Kext %s - internal error resolving dependencies.",
9867 getIdentifierCString());
9868 }
9869 }
9870
9871 if (result && localLoopStack) {
9872 OSKextLog(this,
9873 kOSKextLogStepLevel |
9874 kOSKextLogDependenciesFlag,
9875 "Kext %s successfully resolved dependencies.",
9876 getIdentifierCString());
9877 }
9878
9879 return result;
9880 }
9881
9882 /*********************************************************************
9883 *********************************************************************/
9884 bool
9885 OSKext::addBleedthroughDependencies(OSArray * anArray)
9886 {
9887 bool result = false;
9888 unsigned int dependencyIndex, dependencyCount;
9889
9890 dependencyCount = getNumDependencies();
9891
9892 for (dependencyIndex = 0;
9893 dependencyIndex < dependencyCount;
9894 dependencyIndex++) {
9895 OSKext * dependency = OSDynamicCast(OSKext,
9896 dependencies->getObject(dependencyIndex));
9897 if (!dependency) {
9898 OSKextLog(this,
9899 kOSKextLogErrorLevel |
9900 kOSKextLogDependenciesFlag,
9901 "Kext %s - internal error propagating compatibility dependencies.",
9902 getIdentifierCString());
9903 goto finish;
9904 }
9905 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
9906 anArray->setObject(dependency);
9907 }
9908 dependency->addBleedthroughDependencies(anArray);
9909 }
9910
9911 result = true;
9912
9913 finish:
9914 return result;
9915 }
9916
9917 /*********************************************************************
9918 *********************************************************************/
9919 bool
9920 OSKext::flushDependencies(bool forceFlag)
9921 {
9922 bool result = false;
9923
9924 /* Only clear the dependencies if the kext isn't loaded;
9925 * we need the info for loaded kexts to track references.
9926 */
9927 if (!isLoaded() || forceFlag) {
9928 if (dependencies) {
9929 // xxx - check level
9930 OSKextLog(this,
9931 kOSKextLogProgressLevel |
9932 kOSKextLogDependenciesFlag,
9933 "Kext %s flushing dependencies.",
9934 getIdentifierCString());
9935 dependencies.reset();
9936 }
9937 if (!isKernelComponent()) {
9938 flags.hasAllDependencies = 0;
9939 }
9940 result = true;
9941 }
9942
9943 return result;
9944 }
9945
9946 /*********************************************************************
9947 *********************************************************************/
9948 uint32_t
9949 OSKext::getNumDependencies(void)
9950 {
9951 if (!dependencies) {
9952 return 0;
9953 }
9954 return dependencies->getCount();
9955 }
9956
9957 /*********************************************************************
9958 *********************************************************************/
9959 OSArray *
9960 OSKext::getDependencies(void)
9961 {
9962 return dependencies.get();
9963 }
9964
9965 bool
9966 OSKext::hasDependency(const OSSymbol * depID)
9967 {
9968 bool result __block;
9969
9970 if (depID == getIdentifier()) {
9971 return true;
9972 }
9973 if (!dependencies) {
9974 return false;
9975 }
9976 result = false;
9977 dependencies->iterateObjects(^bool (OSObject * obj) {
9978 OSKext * kext;
9979 kext = OSDynamicCast(OSKext, obj);
9980 if (!kext) {
9981 return false;
9982 }
9983 result = (depID == kext->getIdentifier());
9984 return result;
9985 });
9986 return result;
9987 }
9988
9989 #if PRAGMA_MARK
9990 #pragma mark OSMetaClass Support
9991 #endif
9992 /*********************************************************************
9993 *********************************************************************/
9994 OSReturn
9995 OSKext::addClass(
9996 OSMetaClass * aClass,
9997 uint32_t numClasses)
9998 {
9999 OSReturn result = kOSMetaClassNoInsKModSet;
10000
10001 if (!metaClasses) {
10002 metaClasses = OSSet::withCapacity(numClasses);
10003 if (!metaClasses) {
10004 goto finish;
10005 }
10006 }
10007
10008 if (metaClasses->containsObject(aClass)) {
10009 OSKextLog(this,
10010 kOSKextLogWarningLevel |
10011 kOSKextLogLoadFlag,
10012 "Notice - kext %s has already registered class %s.",
10013 getIdentifierCString(),
10014 aClass->getClassName());
10015 result = kOSReturnSuccess;
10016 goto finish;
10017 }
10018
10019 if (!metaClasses->setObject(aClass)) {
10020 goto finish;
10021 } else {
10022 OSKextLog(this,
10023 kOSKextLogDetailLevel |
10024 kOSKextLogLoadFlag,
10025 "Kext %s registered class %s.",
10026 getIdentifierCString(),
10027 aClass->getClassName());
10028 }
10029
10030 if (!flags.autounloadEnabled) {
10031 const OSMetaClass * metaScan = NULL; // do not release
10032
10033 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
10034 if (metaScan == OSTypeID(IOService)) {
10035 OSKextLog(this,
10036 kOSKextLogProgressLevel |
10037 kOSKextLogLoadFlag,
10038 "Kext %s has IOService subclass %s; enabling autounload.",
10039 getIdentifierCString(),
10040 aClass->getClassName());
10041
10042 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
10043 break;
10044 }
10045 }
10046 }
10047
10048 notifyAddClassObservers(this, aClass, flags);
10049
10050 result = kOSReturnSuccess;
10051
10052 finish:
10053 if (result != kOSReturnSuccess) {
10054 OSKextLog(this,
10055 kOSKextLogErrorLevel |
10056 kOSKextLogLoadFlag,
10057 "Kext %s failed to register class %s.",
10058 getIdentifierCString(),
10059 aClass->getClassName());
10060 }
10061
10062 return result;
10063 }
10064
10065 /*********************************************************************
10066 *********************************************************************/
10067 OSReturn
10068 OSKext::removeClass(
10069 OSMetaClass * aClass)
10070 {
10071 OSReturn result = kOSMetaClassNoKModSet;
10072
10073 if (!metaClasses) {
10074 goto finish;
10075 }
10076
10077 if (!metaClasses->containsObject(aClass)) {
10078 OSKextLog(this,
10079 kOSKextLogWarningLevel |
10080 kOSKextLogLoadFlag,
10081 "Notice - kext %s asked to unregister unknown class %s.",
10082 getIdentifierCString(),
10083 aClass->getClassName());
10084 result = kOSReturnSuccess;
10085 goto finish;
10086 }
10087
10088 OSKextLog(this,
10089 kOSKextLogDetailLevel |
10090 kOSKextLogLoadFlag,
10091 "Kext %s unregistering class %s.",
10092 getIdentifierCString(),
10093 aClass->getClassName());
10094
10095 metaClasses->removeObject(aClass);
10096
10097 notifyRemoveClassObservers(this, aClass, flags);
10098
10099 result = kOSReturnSuccess;
10100
10101 finish:
10102 if (result != kOSReturnSuccess) {
10103 OSKextLog(this,
10104 kOSKextLogErrorLevel |
10105 kOSKextLogLoadFlag,
10106 "Failed to unregister kext %s class %s.",
10107 getIdentifierCString(),
10108 aClass->getClassName());
10109 }
10110 return result;
10111 }
10112
10113 /*********************************************************************
10114 *********************************************************************/
10115 OSSet *
10116 OSKext::getMetaClasses(void)
10117 {
10118 return metaClasses.get();
10119 }
10120
10121 /*********************************************************************
10122 *********************************************************************/
10123 bool
10124 OSKext::hasOSMetaClassInstances(void)
10125 {
10126 bool result = false;
10127 OSSharedPtr<OSCollectionIterator> classIterator;
10128 OSMetaClass * checkClass = NULL; // do not release
10129
10130 if (!metaClasses) {
10131 goto finish;
10132 }
10133
10134 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10135 if (!classIterator) {
10136 // xxx - log alloc failure?
10137 goto finish;
10138 }
10139 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10140 if (checkClass->getInstanceCount()) {
10141 result = true;
10142 goto finish;
10143 }
10144 }
10145
10146 finish:
10147 return result;
10148 }
10149
10150 /*********************************************************************
10151 *********************************************************************/
10152 /* static */
10153 void
10154 OSKext::reportOSMetaClassInstances(
10155 const char * kextIdentifier,
10156 OSKextLogSpec msgLogSpec)
10157 {
10158 OSSharedPtr<OSKext> theKext;
10159
10160 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
10161 if (!theKext) {
10162 goto finish;
10163 }
10164
10165 theKext->reportOSMetaClassInstances(msgLogSpec);
10166 finish:
10167 return;
10168 }
10169
10170 /*********************************************************************
10171 *********************************************************************/
10172 void
10173 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
10174 {
10175 OSSharedPtr<OSCollectionIterator> classIterator;
10176 OSMetaClass * checkClass = NULL; // do not release
10177
10178 if (!metaClasses) {
10179 goto finish;
10180 }
10181
10182 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10183 if (!classIterator) {
10184 goto finish;
10185 }
10186 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10187 if (checkClass->getInstanceCount()) {
10188 OSKextLog(this,
10189 msgLogSpec,
10190 " Kext %s class %s has %d instance%s.",
10191 getIdentifierCString(),
10192 checkClass->getClassName(),
10193 checkClass->getInstanceCount(),
10194 checkClass->getInstanceCount() == 1 ? "" : "s");
10195 }
10196 }
10197
10198 finish:
10199 return;
10200 }
10201
10202 #if PRAGMA_MARK
10203 #pragma mark User-Space Requests
10204 #endif
10205
10206 static kern_return_t
10207 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
10208 {
10209 OSReturn result = kOSReturnSuccess;
10210 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
10211 OSDictionary * request = NULL; //do not release
10212 IOUserServerCheckInToken * token = NULL; //do not release
10213 OSString * requestPredicate = NULL; //do not release
10214 OSSharedPtr<OSNumber> portNameNumber;
10215 mach_port_name_t portName = 0;
10216 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
10217 if (!request) {
10218 OSKextLog(/* kext */ NULL,
10219 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10220 "Elements of request should be of type OSDictionary");
10221 result = kOSKextReturnInternalError;
10222 goto finish;
10223 }
10224 requestPredicate = _OSKextGetRequestPredicate(request);
10225 if (!requestPredicate) {
10226 OSKextLog(/* kext */ NULL,
10227 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10228 "Failed to get request predicate");
10229 result = kOSKextReturnInternalError;
10230 goto finish;
10231 }
10232 // is this a dext launch?
10233 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
10234 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
10235 if (!token) {
10236 OSKextLog(/* kext */ NULL,
10237 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10238 "Could not find a IOUserServerCheckInToken in daemon launch request.");
10239 result = kOSKextReturnInternalError;
10240 goto finish;
10241 }
10242 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
10243 if (portName == 0 || portName == MACH_PORT_DEAD) {
10244 OSKextLog(/* kext */ NULL,
10245 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10246 "Could not create send right for object.");
10247 result = kOSKextReturnInternalError;
10248 goto finish;
10249 }
10250 // Store the mach port name as a OSNumber
10251 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
10252 if (!portNameNumber) {
10253 OSKextLog(/* kext */ NULL,
10254 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10255 "Could not create OSNumber object.");
10256 result = kOSKextReturnNoMemory;
10257 goto finish;
10258 }
10259 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
10260 OSKextLog(/* kext */ NULL,
10261 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10262 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
10263 result = kOSKextReturnNoMemory;
10264 goto finish;
10265 }
10266 }
10267 finish:
10268 if (result != kOSReturnSuccess) {
10269 break;
10270 }
10271 }
10272 return result;
10273 }
10274
10275 bool
10276 OSKext::iokitDaemonActive()
10277 {
10278 bool result;
10279 IORecursiveLockLock(sKextLock);
10280 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10281 IORecursiveLockUnlock(sKextLock);
10282 return result;
10283 }
10284
10285 /*********************************************************************
10286 * XXX - this function is a big ugly mess
10287 *********************************************************************/
10288 /* static */
10289 OSReturn
10290 OSKext::handleRequest(
10291 host_priv_t hostPriv,
10292 OSKextLogSpec clientLogFilter,
10293 char * requestBuffer,
10294 uint32_t requestLength,
10295 char ** responseOut,
10296 uint32_t * responseLengthOut,
10297 char ** logInfoOut,
10298 uint32_t * logInfoLengthOut)
10299 {
10300 OSReturn result = kOSReturnError;
10301 kern_return_t kmem_result = KERN_FAILURE;
10302
10303 char * response = NULL; // returned by reference
10304 uint32_t responseLength = 0;
10305
10306 bool taskCanManageAllKCs = false;
10307 bool taskOnlyManagesBootKC = false;
10308
10309 OSSharedPtr<OSObject> parsedXML;
10310 OSDictionary * requestDict = NULL; // do not release
10311 OSSharedPtr<OSString> errorString;
10312
10313 OSSharedPtr<OSObject> responseObject;
10314
10315 OSSharedPtr<OSSerialize> serializer;
10316
10317 OSSharedPtr<OSArray> logInfoArray;
10318
10319 OSString * predicate = NULL; // do not release
10320 OSString * kextIdentifier = NULL; // do not release
10321 OSArray * kextIdentifiers = NULL; // do not release
10322 OSKext * theKext = NULL; // do not release
10323 OSBoolean * boolArg = NULL; // do not release
10324
10325
10326 IORecursiveLockLock(sKextLock);
10327
10328 if (responseOut) {
10329 *responseOut = NULL;
10330 *responseLengthOut = 0;
10331 }
10332 if (logInfoOut) {
10333 *logInfoOut = NULL;
10334 *logInfoLengthOut = 0;
10335 }
10336
10337 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
10338
10339 /* XML must be nul-terminated.
10340 */
10341 if (requestBuffer[requestLength - 1] != '\0') {
10342 OSKextLog(/* kext */ NULL,
10343 kOSKextLogErrorLevel |
10344 kOSKextLogIPCFlag,
10345 "Invalid request from user space (not nul-terminated).");
10346 result = kOSKextReturnBadData;
10347 goto finish;
10348 }
10349 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
10350 if (parsedXML) {
10351 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10352 }
10353 if (!requestDict) {
10354 const char * errorCString = "(unknown error)";
10355
10356 if (errorString && errorString->getCStringNoCopy()) {
10357 errorCString = errorString->getCStringNoCopy();
10358 } else if (parsedXML) {
10359 errorCString = "not a dictionary";
10360 }
10361 OSKextLog(/* kext */ NULL,
10362 kOSKextLogErrorLevel |
10363 kOSKextLogIPCFlag,
10364 "Error unserializing request from user space: %s.",
10365 errorCString);
10366 result = kOSKextReturnSerialization;
10367 goto finish;
10368 }
10369
10370 predicate = _OSKextGetRequestPredicate(requestDict);
10371 if (!predicate) {
10372 OSKextLog(/* kext */ NULL,
10373 kOSKextLogErrorLevel |
10374 kOSKextLogIPCFlag,
10375 "Recieved kext request from user space with no predicate.");
10376 result = kOSKextReturnInvalidArgument;
10377 goto finish;
10378 }
10379 OSKextLog(/* kext */ NULL,
10380 kOSKextLogDebugLevel |
10381 kOSKextLogIPCFlag,
10382 "Received '%s' request from user space.",
10383 predicate->getCStringNoCopy());
10384
10385 /*
10386 * All management of file sets requires an entitlement
10387 */
10388 result = kOSKextReturnNotPrivileged;
10389 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10390 predicate->isEqualTo(kKextRequestPredicateStart) ||
10391 predicate->isEqualTo(kKextRequestPredicateStop) ||
10392 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10393 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10394 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10395 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10396 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10397 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10398 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10399 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10400 if (!iokitDaemonAvailable()) {
10401 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10402 }
10403 if (hostPriv == HOST_PRIV_NULL) {
10404 OSKextLog(/* kext */ NULL,
10405 kOSKextLogErrorLevel |
10406 kOSKextLogIPCFlag,
10407 "Access Failure - must be root user.");
10408 goto finish;
10409 }
10410 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10411 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10412
10413 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10414 OSKextLog(/* kext */ NULL,
10415 kOSKextLogErrorLevel |
10416 kOSKextLogIPCFlag,
10417 "Access Failure - client not entitled to manage file sets.");
10418 goto finish;
10419 }
10420
10421 /*
10422 * The OnlyBootKC entitlement restricts the
10423 * collection-management entitlement to only managing kexts in
10424 * the BootKC. All other predicates that alter global state or
10425 * add new KCs are disallowed.
10426 */
10427 if (taskOnlyManagesBootKC &&
10428 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10429 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10430 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10431 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10432 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10433 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10434 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10435 OSKextLog(/* kext */ NULL,
10436 kOSKextLogErrorLevel |
10437 kOSKextLogIPCFlag,
10438 "Access Failure - client not entitled to manage non-primary KCs");
10439 goto finish;
10440 }
10441
10442 /*
10443 * If we get here, then the process either has the full KC
10444 * management entitlement, or it has the BootKC-only
10445 * entitlement and the request is about the BootKC.
10446 */
10447 }
10448
10449 /* Get common args in anticipation of use.
10450 */
10451 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10452 requestDict, kKextRequestArgumentBundleIdentifierKey));
10453 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10454 requestDict, kKextRequestArgumentBundleIdentifierKey));
10455 if (kextIdentifier) {
10456 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10457 }
10458 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10459 requestDict, kKextRequestArgumentValueKey));
10460
10461 if (taskOnlyManagesBootKC &&
10462 theKext &&
10463 theKext->isInFileset() &&
10464 theKext->kc_type != KCKindPrimary) {
10465 OSKextLog(/* kext */ NULL,
10466 kOSKextLogErrorLevel |
10467 kOSKextLogIPCFlag,
10468 "Access Failure - client not entitled to manage kext in non-primary KC");
10469 result = kOSKextReturnNotPrivileged;
10470 goto finish;
10471 }
10472 result = kOSKextReturnInvalidArgument;
10473
10474 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10475 if (!kextIdentifier) {
10476 OSKextLog(/* kext */ NULL,
10477 kOSKextLogErrorLevel |
10478 kOSKextLogIPCFlag,
10479 "Invalid arguments to kext start request.");
10480 } else if (!theKext) {
10481 OSKextLog(/* kext */ NULL,
10482 kOSKextLogErrorLevel |
10483 kOSKextLogIPCFlag,
10484 "Kext %s not found for start request.",
10485 kextIdentifier->getCStringNoCopy());
10486 result = kOSKextReturnNotFound;
10487 } else {
10488 result = theKext->start();
10489 }
10490 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10491 if (!kextIdentifier) {
10492 OSKextLog(/* kext */ NULL,
10493 kOSKextLogErrorLevel |
10494 kOSKextLogIPCFlag,
10495 "Invalid arguments to kext stop request.");
10496 } else if (!theKext) {
10497 OSKextLog(/* kext */ NULL,
10498 kOSKextLogErrorLevel |
10499 kOSKextLogIPCFlag,
10500 "Kext %s not found for stop request.",
10501 kextIdentifier->getCStringNoCopy());
10502 result = kOSKextReturnNotFound;
10503 } else {
10504 result = theKext->stop();
10505 }
10506 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10507 result = OSKext::setMissingAuxKCBundles(requestDict);
10508 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10509 if (!kextIdentifier) {
10510 OSKextLog(/* kext */ NULL,
10511 kOSKextLogErrorLevel |
10512 kOSKextLogIPCFlag,
10513 "Invalid arguments to AuxKC Bundle Available request.");
10514 } else {
10515 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10516 }
10517 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10518 if (!kextIdentifier) {
10519 OSKextLog(/* kext */ NULL,
10520 kOSKextLogErrorLevel |
10521 kOSKextLogIPCFlag,
10522 "Invalid arguments to kext load from KC request.");
10523 } else if (!theKext) {
10524 OSKextLog(/* kext */ NULL,
10525 kOSKextLogErrorLevel |
10526 kOSKextLogIPCFlag,
10527 "Kext %s not found for load from KC request.",
10528 kextIdentifier->getCStringNoCopy());
10529 result = kOSKextReturnNotFound;
10530 } else if (!theKext->isInFileset()) {
10531 OSKextLog(/* kext */ NULL,
10532 kOSKextLogErrorLevel |
10533 kOSKextLogIPCFlag,
10534 "Kext %s does not exist in a KC: refusing to load.",
10535 kextIdentifier->getCStringNoCopy());
10536 result = kOSKextReturnNotLoadable;
10537 } else {
10538 result = OSKext::loadKextFromKC(theKext, requestDict);
10539 }
10540 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10541 if (!kextIdentifier) {
10542 OSKextLog(/* kext */ NULL,
10543 kOSKextLogErrorLevel |
10544 kOSKextLogIPCFlag,
10545 "Invalid arguments to codeless kext load interface (missing identifier).");
10546 } else {
10547 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10548 }
10549 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10550 if (!kextIdentifier) {
10551 OSKextLog(/* kext */ NULL,
10552 kOSKextLogErrorLevel |
10553 kOSKextLogIPCFlag,
10554 "Invalid arguments to kext unload request.");
10555 } else if (!theKext) {
10556 OSKextLog(/* kext */ NULL,
10557 kOSKextLogErrorLevel |
10558 kOSKextLogIPCFlag,
10559 "Kext %s not found for unload request.",
10560 kextIdentifier->getCStringNoCopy());
10561 result = kOSKextReturnNotFound;
10562 } else {
10563 if (theKext->isDriverKit()) {
10564 result = OSKext::removeDext(theKext);
10565 } else {
10566 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10567 _OSKextGetRequestArgument(requestDict,
10568 kKextRequestArgumentTerminateIOServicesKey));
10569 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
10570 }
10571 }
10572 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10573 result = OSKext::dispatchResource(requestDict);
10574 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10575 OSNumber *lookupNum = NULL;
10576 lookupNum = OSDynamicCast(OSNumber,
10577 _OSKextGetRequestArgument(requestDict,
10578 kKextRequestArgumentLookupAddressKey));
10579
10580 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
10581 if (responseObject) {
10582 result = kOSReturnSuccess;
10583 } else {
10584 goto finish;
10585 }
10586 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10587 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10588 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10589 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10590 OSBoolean * delayAutounloadBool = NULL;
10591 OSObject * infoKeysRaw = NULL;
10592 OSArray * infoKeys = NULL;
10593 uint32_t infoKeysCount = 0;
10594
10595 delayAutounloadBool = OSDynamicCast(OSBoolean,
10596 _OSKextGetRequestArgument(requestDict,
10597 kKextRequestArgumentDelayAutounloadKey));
10598
10599 /* If asked to delay autounload, reset the timer if it's currently set.
10600 * (That is, don't schedule an unload if one isn't already pending.
10601 */
10602 if (delayAutounloadBool == kOSBooleanTrue) {
10603 OSKext::considerUnloads(/* rescheduleOnly? */ true);
10604 }
10605
10606 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10607 kKextRequestArgumentInfoKeysKey);
10608 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10609 if (infoKeysRaw && !infoKeys) {
10610 OSKextLog(/* kext */ NULL,
10611 kOSKextLogErrorLevel |
10612 kOSKextLogIPCFlag,
10613 "Invalid arguments to kext info request.");
10614 goto finish;
10615 }
10616
10617 if (infoKeys) {
10618 infoKeysCount = infoKeys->getCount();
10619 for (uint32_t i = 0; i < infoKeysCount; i++) {
10620 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10621 OSKextLog(/* kext */ NULL,
10622 kOSKextLogErrorLevel |
10623 kOSKextLogIPCFlag,
10624 "Invalid arguments to kext info request.");
10625 goto finish;
10626 }
10627 }
10628 }
10629
10630 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10631 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
10632 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10633 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
10634 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10635 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10636 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10637 responseObject = OSKext::copyDextsInfo(kextIdentifiers, infoKeys);
10638 }
10639
10640 if (!responseObject) {
10641 result = kOSKextReturnInternalError;
10642 } else {
10643 OSKextLog(/* kext */ NULL,
10644 kOSKextLogDebugLevel |
10645 kOSKextLogIPCFlag,
10646 "Returning loaded kext info.");
10647 result = kOSReturnSuccess;
10648 }
10649 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10650 /* Hand the current sKernelRequests array to the caller
10651 * (who must release it), and make a new one.
10652 */
10653 responseObject = os::move(sKernelRequests);
10654 sKernelRequests = OSArray::withCapacity(0);
10655 sPostedKextLoadIdentifiers->flushCollection();
10656 OSKextLog(/* kext */ NULL,
10657 kOSKextLogDebugLevel |
10658 kOSKextLogIPCFlag,
10659 "Returning kernel requests.");
10660 result = kOSReturnSuccess;
10661 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10662 /* Return the set of all requested bundle identifiers */
10663 responseObject = sAllKextLoadIdentifiers;
10664 OSKextLog(/* kext */ NULL,
10665 kOSKextLogDebugLevel |
10666 kOSKextLogIPCFlag,
10667 "Returning load requests.");
10668 result = kOSReturnSuccess;
10669 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10670 printf("KextLog: Loading FileSet KC(s)\n");
10671 result = OSKext::loadFileSetKexts(requestDict);
10672 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10673 bool active = iokitDaemonActive();
10674 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10675 if (sOSKextWasResetAfterUserspaceReboot) {
10676 printf("KextLog: was reset after userspace reboot\n");
10677 }
10678 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10679 } else {
10680 OSKextLog(/* kext */ NULL,
10681 kOSKextLogDebugLevel |
10682 kOSKextLogIPCFlag,
10683 "Received '%s' invalid request from user space.",
10684 predicate->getCStringNoCopy());
10685 goto finish;
10686 }
10687
10688 /**********
10689 * Now we have handle the request, or not. Gather up the response & logging
10690 * info to ship to user space.
10691 *********/
10692
10693 /* Note: Nothing in OSKext is supposed to retain requestDict,
10694 * but you never know....
10695 */
10696 if (requestDict->getRetainCount() > 1) {
10697 OSKextLog(/* kext */ NULL,
10698 kOSKextLogWarningLevel |
10699 kOSKextLogIPCFlag,
10700 "Request from user space still retained by a kext; "
10701 "probable memory leak.");
10702 }
10703
10704 if (responseOut && responseObject) {
10705 serializer = OSSerialize::withCapacity(0);
10706 if (!serializer) {
10707 result = kOSKextReturnNoMemory;
10708 goto finish;
10709 }
10710 /*
10711 * Before serializing the kernel requests, patch the dext launch requests so
10712 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10713 * IOUserServerCheckInToken kernel object.
10714 */
10715 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10716 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10717 task_t calling_task = current_task();
10718 if (!requests) {
10719 OSKextLog(/* kext */ NULL,
10720 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10721 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10722 result = kOSKextReturnInternalError;
10723 goto finish;
10724 }
10725 result = patchDextLaunchRequests(calling_task, requests);
10726 if (result != kOSReturnSuccess) {
10727 OSKextLog(/* kext */ NULL,
10728 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10729 "Failed to patch dext launch requests.");
10730 goto finish;
10731 }
10732 }
10733
10734 if (!responseObject->serialize(serializer.get())) {
10735 OSKextLog(/* kext */ NULL,
10736 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10737 "Failed to serialize response to request from user space.");
10738 result = kOSKextReturnSerialization;
10739 goto finish;
10740 }
10741
10742 response = (char *)serializer->text();
10743 responseLength = serializer->getLength();
10744 }
10745
10746 if (responseOut && response) {
10747 char * buffer;
10748
10749 /* This kmem_alloc sets the return value of the function.
10750 */
10751 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
10752 round_page(responseLength), KMA_DATA_SHARED, VM_KERN_MEMORY_OSKEXT);
10753 if (kmem_result != KERN_SUCCESS) {
10754 OSKextLog(/* kext */ NULL,
10755 kOSKextLogErrorLevel |
10756 kOSKextLogIPCFlag,
10757 "Failed to copy response to request from user space.");
10758 result = kmem_result;
10759 goto finish;
10760 } else {
10761 /* 11981737 - clear uninitialized data in last page */
10762 bzero((void *)(buffer + responseLength),
10763 (round_page(responseLength) - responseLength));
10764 memcpy(buffer, response, responseLength);
10765 *responseOut = buffer;
10766 *responseLengthOut = responseLength;
10767 }
10768 }
10769
10770 finish:
10771
10772 /* Gather up the collected log messages for user space. Any messages
10773 * messages past this call will not make it up as log messages but
10774 * will be in the system log. Note that we ignore the return of the
10775 * serialize; it has no bearing on the operation at hand even if we
10776 * fail to get the log messages.
10777 */
10778 logInfoArray = OSKext::clearUserSpaceLogFilter();
10779
10780 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10781 (void)OSKext::serializeLogInfo(logInfoArray.get(),
10782 logInfoOut, logInfoLengthOut);
10783 }
10784
10785 IORecursiveLockUnlock(sKextLock);
10786
10787 return result;
10788 }
10789
10790 #if PRAGMA_MARK
10791 #pragma mark Linked Kext Collection Support
10792 #endif
10793
10794 static int
10795 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10796 {
10797 for (int i = 0; i < segCount; i++) {
10798 vm_offset_t segStart = segAddrs[i];
10799 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10800
10801 if (theAddr >= segStart && theAddr < segEnd) {
10802 return i;
10803 }
10804 }
10805 return -1;
10806 }
10807
10808 static void
10809 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
10810 kernel_segment_command_t *kextTextSeg,
10811 OSData *kaslrOffsets)
10812 {
10813 static const char *plk_segNames[] = {
10814 "__TEXT",
10815 "__TEXT_EXEC",
10816 "__DATA",
10817 "__DATA_CONST",
10818 "__LINKEDIT",
10819 "__PRELINK_TEXT",
10820 "__PLK_TEXT_EXEC",
10821 "__PRELINK_DATA",
10822 "__PLK_DATA_CONST",
10823 "__PLK_LLVM_COV",
10824 "__PLK_LINKEDIT",
10825 "__PRELINK_INFO"
10826 };
10827 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10828
10829 unsigned long plk_segSizes[num_plk_seg];
10830 vm_offset_t plk_segAddrs[num_plk_seg];
10831
10832 for (size_t i = 0; i < num_plk_seg; i++) {
10833 plk_segSizes[i] = 0;
10834 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10835 }
10836
10837 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10838
10839 int slidKextAddrCount = 0;
10840 int badSlideAddr = 0;
10841 int badSlideTarget = 0;
10842
10843 struct kaslrPackedOffsets {
10844 uint32_t count; /* number of offsets */
10845 uint32_t offsetsArray[]; /* offsets to slide */
10846 };
10847 const struct kaslrPackedOffsets *myOffsets = NULL;
10848 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10849
10850 for (uint32_t j = 0; j < myOffsets->count; j++) {
10851 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10852 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10853 int slideAddrSegIndex = -1;
10854 int addrToSlideSegIndex = -1;
10855
10856 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10857 if (slideAddrSegIndex >= 0) {
10858 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10859 if (addrToSlideSegIndex < 0) {
10860 badSlideTarget++;
10861 continue;
10862 }
10863 } else {
10864 badSlideAddr++;
10865 continue;
10866 }
10867
10868 slidKextAddrCount++;
10869 *slideAddr = ml_static_slide(*slideAddr);
10870 } // for ...
10871 }
10872
10873
10874
10875 /********************************************************************
10876 * addKextsFromKextCollection
10877 *
10878 * Input: MachO header of kext collection. The MachO is assumed to
10879 * have a section named 'info_seg_name,info_sect_name' that
10880 * contains a serialized XML info dictionary. This dictionary
10881 * contains a UUID, possibly a set of relocations (for older
10882 * kxld-built binaries), and an array of kext personalities.
10883 *
10884 ********************************************************************/
10885 bool
10886 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10887 OSDictionary *infoDict, const char *text_seg_name,
10888 OSData **kcUUID, kc_kind_t type)
10889 {
10890 bool result = false;
10891
10892 OSArray *kextArray = NULL; // do not release
10893 OSData *infoDictKCUUID = NULL; // do not release
10894 OSData *kaslrOffsets = NULL; // do not release
10895
10896 IORegistryEntry *registryRoot = NULL; // do not release
10897 OSSharedPtr<OSNumber> kcKextCount;
10898
10899 /* extract the KC UUID from the dictionary */
10900 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10901 if (infoDictKCUUID) {
10902 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10903 panic("kcUUID length is %d, expected %lu",
10904 infoDictKCUUID->getLength(), sizeof(uuid_t));
10905 }
10906 }
10907
10908 /* locate the array of kext dictionaries */
10909 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10910 if (!kextArray) {
10911 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10912 "The given KC has no kext info dictionaries");
10913 goto finish;
10914 }
10915
10916 /*
10917 * old-style KASLR offsets may be present in the info dictionary. If
10918 * we find them, use them and eventually slide them.
10919 */
10920 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10921
10922 /*
10923 * Before processing any kexts, locate the special kext bundle which
10924 * contains a list of kexts that we are to prevent from loading.
10925 */
10926 createExcludeListFromPrelinkInfo(kextArray);
10927
10928 /*
10929 * Create OSKext objects for each kext we find in the array of kext
10930 * info plist dictionaries.
10931 */
10932 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10933 OSDictionary *kextDict = NULL;
10934 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10935 if (!kextDict) {
10936 OSKextLog(/* kext */ NULL,
10937 kOSKextLogErrorLevel |
10938 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10939 "Kext info dictionary for kext #%d isn't a dictionary?", i);
10940 continue;
10941 }
10942
10943 /*
10944 * Create the kext for the entry, then release it, because the
10945 * kext system keeps a reference around until the kext is
10946 * explicitly removed. Any creation/registration failures are
10947 * already logged for us.
10948 */
10949 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
10950 }
10951
10952 /*
10953 * slide old-style kxld relocations
10954 * NOTE: this is still used on embedded KCs built with kcgen
10955 * TODO: Remove this once we use the new kext linker everywhere!
10956 */
10957 if (kaslrOffsets && vm_kernel_slide > 0) {
10958 kernel_segment_command_t *text_segment = NULL;
10959 text_segment = getsegbynamefromheader(mh, text_seg_name);
10960 if (!text_segment) {
10961 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10962 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10963 goto finish;
10964 }
10965
10966 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
10967 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10968 setAllVMAttributes();
10969 }
10970
10971 /* Store the number of prelinked kexts in the registry so we can tell
10972 * when the system has been started from a prelinked kernel.
10973 */
10974 registryRoot = IORegistryEntry::getRegistryRoot();
10975 assert(registryRoot);
10976
10977 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10978 assert(kcKextCount);
10979 if (kcKextCount) {
10980 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10981 OSNumber *num;
10982 num = OSDynamicCast(OSNumber, prop.get());
10983 if (num) {
10984 kcKextCount->addValue(num->unsigned64BitValue());
10985 }
10986 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10987 }
10988
10989 OSKextLog(/* kext */ NULL,
10990 kOSKextLogProgressLevel |
10991 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10992 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10993 "%u prelinked kexts", infoDict->getCount());
10994
10995
10996 if (kcUUID && infoDictKCUUID) {
10997 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10998 }
10999
11000 result = true;
11001
11002 finish:
11003 return result;
11004 }
11005
11006 bool
11007 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
11008 OSDictionary *infoDict, const char *text_seg_name,
11009 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
11010 {
11011 OSData *result = NULL;
11012 bool success = addKextsFromKextCollection(mh,
11013 infoDict,
11014 text_seg_name,
11015 &result,
11016 type);
11017 if (success) {
11018 kcUUID.reset(result, OSNoRetain);
11019 }
11020 return success;
11021 }
11022
11023 static OSSharedPtr<OSObject> deferredAuxKCXML;
11024 bool
11025 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
11026 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
11027 {
11028 if (type != KCKindAuxiliary) {
11029 return false;
11030 }
11031
11032 kernel_mach_header_t *_mh;
11033 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
11034 if (!_mh || _mh != mh) {
11035 return false;
11036 }
11037
11038 if (deferredAuxKCXML) {
11039 /* only allow this to be called once */
11040 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11041 "An Aux KC has already been registered for deferred processing.");
11042 return false;
11043 }
11044
11045 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11046 if (!infoDict) {
11047 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11048 "The Aux KC has info dictionary");
11049 return false;
11050 }
11051
11052 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
11053 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
11054 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11055 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
11056 return false;
11057 }
11058
11059 /*
11060 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
11061 * sysctl can return the UUID to user space which will check this
11062 * value for errors.
11063 */
11064 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
11065 kcUUID->getLength());
11066 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
11067 auxkc_uuid_valid = TRUE;
11068
11069 deferredAuxKCXML = parsedXML;
11070
11071 return true;
11072 }
11073
11074 OSSharedPtr<OSObject>
11075 OSKext::consumeDeferredKextCollection(kc_kind_t type)
11076 {
11077 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
11078 return NULL;
11079 }
11080
11081 return os::move(deferredAuxKCXML);
11082 }
11083
11084 #if PRAGMA_MARK
11085 #pragma mark Profile-Guided-Optimization Support
11086 #endif
11087
11088 // #include <InstrProfiling.h>
11089 extern "C" {
11090 uint64_t __llvm_profile_get_size_for_buffer_internal(
11091 const char *DataBegin,
11092 const char *DataEnd,
11093 const char *CountersBegin,
11094 const char *CountersEnd,
11095 const char *BitmapBegin,
11096 const char *BitmapEnd,
11097 const char *NamesBegin,
11098 const char *NamesEnd,
11099 const char *VTableBegin,
11100 const char *VTableEnd,
11101 const char *VNamesBegin,
11102 const char *VNamesEnd);
11103 int __llvm_profile_write_buffer_internal(
11104 char *Buffer,
11105 const char *DataBegin,
11106 const char *DataEnd,
11107 const char *CountersBegin,
11108 const char *CountersEnd,
11109 const char *BitmapBegin,
11110 const char *BitmapEnd,
11111 const char *NamesBegin,
11112 const char *NamesEnd);
11113 }
11114
11115 static
11116 void
11117 OSKextPgoMetadataPut(char *pBuffer,
11118 size_t *position,
11119 size_t bufferSize,
11120 uint32_t *num_pairs,
11121 const char *key,
11122 const char *value)
11123 {
11124 size_t strlen_key = strlen(key);
11125 size_t strlen_value = strlen(value);
11126 size_t len = strlen(key) + 1 + strlen(value) + 1;
11127 char *pos = pBuffer + *position;
11128 *position += len;
11129 if (pBuffer && bufferSize && *position <= bufferSize) {
11130 memcpy(pos, key, strlen_key); pos += strlen_key;
11131 *(pos++) = '=';
11132 memcpy(pos, value, strlen_value); pos += strlen_value;
11133 *(pos++) = 0;
11134 if (num_pairs) {
11135 (*num_pairs)++;
11136 }
11137 }
11138 }
11139
11140
11141 static
11142 void
11143 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
11144 {
11145 *position += strlen(key) + 1 + value_max + 1;
11146 }
11147
11148
11149 static
11150 void
11151 OSKextPgoMetadataPutAll(OSKext *kext,
11152 uuid_t instance_uuid,
11153 char *pBuffer,
11154 size_t *position,
11155 size_t bufferSize,
11156 uint32_t *num_pairs)
11157 {
11158 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
11159 //log_10 2^16 ≈ 4.82
11160 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
11161 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
11162
11163 if (!pBuffer) {
11164 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
11165 OSKextPgoMetadataPutMax(position, "UUID", 36);
11166 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
11167 } else {
11168 uuid_string_t instance_uuid_string;
11169 uuid_unparse(instance_uuid, instance_uuid_string);
11170 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11171 "INSTANCE", instance_uuid_string);
11172
11173 OSSharedPtr<OSData> uuid_data;
11174 uuid_t uuid;
11175 uuid_string_t uuid_string;
11176 uuid_data = kext->copyUUID();
11177 if (uuid_data) {
11178 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
11179 uuid_unparse(uuid, uuid_string);
11180 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11181 "UUID", uuid_string);
11182 }
11183
11184 clock_sec_t secs;
11185 clock_usec_t usecs;
11186 clock_get_calendar_microtime(&secs, &usecs);
11187 assert(usecs < 1000000);
11188 char timestamp[max_timestamp_string_size + 1];
11189 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
11190 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
11191 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11192 "TIMESTAMP", timestamp);
11193 }
11194
11195 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11196 "NAME", kext->getIdentifierCString());
11197
11198 char versionCString[kOSKextVersionMaxLength];
11199 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
11200 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11201 "VERSION", versionCString);
11202 }
11203
11204 static
11205 size_t
11206 OSKextPgoMetadataSize(OSKext *kext)
11207 {
11208 size_t position = 0;
11209 uuid_t fakeuuid = {};
11210 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
11211 return position;
11212 }
11213
11214 int
11215 OSKextGrabPgoDataLocked(OSKext *kext,
11216 bool metadata,
11217 uuid_t instance_uuid,
11218 uint64_t *pSize,
11219 char *pBuffer,
11220 uint64_t bufferSize)
11221 {
11222 int err = 0;
11223
11224 kernel_section_t *sect_prf_data = NULL;
11225 kernel_section_t *sect_prf_name = NULL;
11226 kernel_section_t *sect_prf_cnts = NULL;
11227 uint64_t size;
11228 size_t metadata_size = 0;
11229 size_t offset_to_pairs = 0;
11230
11231 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
11232 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
11233 if (!sect_prf_name) {
11234 // kextcache sometimes truncates the section name to 15 chars
11235 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
11236 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
11237 }
11238 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11239
11240 // Ignore some sections used by optional PGO variants.
11241 const char *unused_section = NULL;
11242
11243 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
11244 err = ENOTSUP;
11245 goto out;
11246 }
11247
11248 size = __llvm_profile_get_size_for_buffer_internal(
11249 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11250 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11251 unused_section /* bits */, unused_section /* bits end */,
11252 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size,
11253 unused_section /* vtab */, unused_section /* vtab end */,
11254 unused_section /* vnam */, unused_section /* vnam end */);
11255
11256 if (metadata) {
11257 metadata_size = OSKextPgoMetadataSize(kext);
11258 size += metadata_size;
11259 size += sizeof(pgo_metadata_footer);
11260 }
11261
11262
11263 if (pSize) {
11264 *pSize = size;
11265 }
11266
11267 if (pBuffer && bufferSize) {
11268 if (bufferSize < size) {
11269 err = ERANGE;
11270 goto out;
11271 }
11272
11273 err = __llvm_profile_write_buffer_internal(
11274 pBuffer,
11275 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11276 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11277 unused_section /* bits */, unused_section /* bits end */,
11278 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11279
11280 if (err) {
11281 err = EIO;
11282 goto out;
11283 }
11284
11285 if (metadata) {
11286 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11287 if (offset_to_pairs > UINT32_MAX) {
11288 err = E2BIG;
11289 goto out;
11290 }
11291
11292 char *end_of_buffer = pBuffer + size;
11293 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11294 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11295
11296 size_t metadata_position = 0;
11297 uint32_t num_pairs = 0;
11298 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
11299 while (metadata_position < metadata_size) {
11300 metadata_buffer[metadata_position++] = 0;
11301 }
11302
11303 struct pgo_metadata_footer footer;
11304 footer.magic = htonl(0x6d657461);
11305 footer.number_of_pairs = htonl( num_pairs );
11306 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11307 memcpy(footerp, &footer, sizeof(footer));
11308 }
11309 }
11310
11311 out:
11312 return err;
11313 }
11314
11315
11316 int
11317 OSKextGrabPgoData(uuid_t uuid,
11318 uint64_t *pSize,
11319 char *pBuffer,
11320 uint64_t bufferSize,
11321 int wait_for_unload,
11322 int metadata)
11323 {
11324 int err = 0;
11325 OSSharedPtr<OSKext> kext;
11326
11327
11328 IORecursiveLockLock(sKextLock);
11329
11330 kext = OSKext::lookupKextWithUUID(uuid);
11331 if (!kext) {
11332 err = ENOENT;
11333 goto out;
11334 }
11335
11336 if (wait_for_unload) {
11337 OSKextGrabPgoStruct s;
11338
11339 s.metadata = metadata;
11340 s.pSize = pSize;
11341 s.pBuffer = pBuffer;
11342 s.bufferSize = bufferSize;
11343 s.err = EINTR;
11344
11345 struct list_head *prev = &kext->pendingPgoHead;
11346 struct list_head *next = kext->pendingPgoHead.next;
11347
11348 s.list_head.prev = prev;
11349 s.list_head.next = next;
11350
11351 prev->next = &s.list_head;
11352 next->prev = &s.list_head;
11353
11354 kext.reset();
11355
11356 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
11357
11358 prev = s.list_head.prev;
11359 next = s.list_head.next;
11360
11361 prev->next = next;
11362 next->prev = prev;
11363
11364 err = s.err;
11365 } else {
11366 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
11367 }
11368
11369 out:
11370
11371 IORecursiveLockUnlock(sKextLock);
11372
11373 return err;
11374 }
11375
11376 void
11377 OSKextResetPgoCountersLock()
11378 {
11379 IORecursiveLockLock(sKextLock);
11380 }
11381
11382 void
11383 OSKextResetPgoCountersUnlock()
11384 {
11385 IORecursiveLockUnlock(sKextLock);
11386 }
11387
11388
11389 extern unsigned int not_in_kdp;
11390
11391 void
11392 OSKextResetPgoCounters()
11393 {
11394 assert(!not_in_kdp);
11395 uint32_t count = sLoadedKexts->getCount();
11396 for (uint32_t i = 0; i < count; i++) {
11397 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11398 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11399 if (!sect_prf_cnts) {
11400 continue;
11401 }
11402 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
11403 }
11404 }
11405
11406 OSSharedPtr<OSDictionary>
11407 OSKext::copyLoadedKextInfoByUUID(
11408 OSArray * kextIdentifiers,
11409 OSArray * infoKeys)
11410 {
11411 OSSharedPtr<OSDictionary> result;
11412 OSSharedPtr<OSDictionary> kextInfo;
11413 uint32_t max_count, i, j;
11414 uint32_t idCount = 0;
11415 uint32_t idIndex = 0;
11416 IORecursiveLockLock(sKextLock);
11417 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11418 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11419
11420 #if CONFIG_MACF
11421 /* Is the calling process allowed to query kext info? */
11422 if (current_task() != kernel_task) {
11423 int macCheckResult = 0;
11424 kauth_cred_t cred = NULL;
11425
11426 cred = kauth_cred_get_with_ref();
11427 macCheckResult = mac_kext_check_query(cred);
11428 kauth_cred_unref(&cred);
11429
11430 if (macCheckResult != 0) {
11431 OSKextLog(/* kext */ NULL,
11432 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11433 "Failed to query kext info (MAC policy error 0x%x).",
11434 macCheckResult);
11435 goto finish;
11436 }
11437 }
11438 #endif
11439
11440 /* Empty list of UUIDs is equivalent to no list (get all).
11441 */
11442 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11443 kextIdentifiers = NULL;
11444 } else if (kextIdentifiers) {
11445 idCount = kextIdentifiers->getCount();
11446 }
11447
11448 /* Same for keys.
11449 */
11450 if (infoKeys && !infoKeys->getCount()) {
11451 infoKeys = NULL;
11452 }
11453
11454 max_count = count[0] + count[1];
11455 result = OSDictionary::withCapacity(max_count);
11456 if (!result) {
11457 goto finish;
11458 }
11459
11460 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11461 for (i = 0; i < count[j]; i++) {
11462 OSKext *thisKext = NULL; // do not release
11463 Boolean includeThis = true;
11464 uuid_t thisKextUUID;
11465 uuid_t thisKextTextUUID;
11466 OSSharedPtr<OSData> uuid_data;
11467 uuid_string_t uuid_key;
11468
11469 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11470 if (!thisKext) {
11471 continue;
11472 }
11473
11474 uuid_data = thisKext->copyUUID();
11475 if (!uuid_data) {
11476 continue;
11477 }
11478
11479 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
11480
11481 uuid_unparse(thisKextUUID, uuid_key);
11482
11483 uuid_data = thisKext->copyTextUUID();
11484 if (!uuid_data) {
11485 continue;
11486 }
11487 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
11488
11489 /* Skip current kext if we have a list of UUIDs and
11490 * it isn't in the list.
11491 */
11492 if (kextIdentifiers) {
11493 includeThis = false;
11494
11495 for (idIndex = 0; idIndex < idCount; idIndex++) {
11496 const OSString* wantedUUID = OSDynamicCast(OSString,
11497 kextIdentifiers->getObject(idIndex));
11498
11499 uuid_t uuid;
11500 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
11501
11502 if ((0 == uuid_compare(uuid, thisKextUUID))
11503 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
11504 includeThis = true;
11505 /* Only need to find the first kext if multiple match,
11506 * ie. asking for the kernel uuid does not need to find
11507 * interface kexts or builtin static kexts.
11508 */
11509 kextIdentifiers->removeObject(idIndex);
11510 uuid_unparse(uuid, uuid_key);
11511 break;
11512 }
11513 }
11514 }
11515
11516 if (!includeThis) {
11517 continue;
11518 }
11519
11520 kextInfo = thisKext->copyInfo(infoKeys);
11521 if (kextInfo) {
11522 result->setObject(uuid_key, kextInfo.get());
11523 }
11524
11525 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11526 goto finish;
11527 }
11528 }
11529 }
11530
11531 finish:
11532 IORecursiveLockUnlock(sKextLock);
11533
11534 return result;
11535 }
11536
11537 /*********************************************************************
11538 *********************************************************************/
11539 /* static */
11540 OSSharedPtr<OSDictionary>
11541 OSKext::copyKextCollectionInfo(
11542 OSDictionary *requestDict,
11543 OSArray *infoKeys)
11544 {
11545 OSSharedPtr<OSDictionary> result;
11546 OSString *collectionType = NULL;
11547 OSObject *rawLoadedState = NULL;
11548 OSString *loadedState = NULL;
11549
11550 kc_kind_t kc_request_kind = KCKindUnknown;
11551 bool onlyLoaded = false;
11552 bool onlyUnloaded = false;
11553
11554 #if CONFIG_MACF
11555 /* Is the calling process allowed to query kext info? */
11556 if (current_task() != kernel_task) {
11557 int macCheckResult = 0;
11558 kauth_cred_t cred = NULL;
11559
11560 cred = kauth_cred_get_with_ref();
11561 macCheckResult = mac_kext_check_query(cred);
11562 kauth_cred_unref(&cred);
11563
11564 if (macCheckResult != 0) {
11565 OSKextLog(/* kext */ NULL,
11566 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11567 "Failed to query kext info (MAC policy error 0x%x).",
11568 macCheckResult);
11569 goto finish;
11570 }
11571 }
11572 #endif
11573
11574 if (infoKeys && !infoKeys->getCount()) {
11575 infoKeys = NULL;
11576 }
11577
11578 collectionType = OSDynamicCast(OSString,
11579 _OSKextGetRequestArgument(requestDict,
11580 kKextRequestArgumentCollectionTypeKey));
11581 if (!collectionType) {
11582 OSKextLog(/* kext */ NULL,
11583 kOSKextLogErrorLevel |
11584 kOSKextLogIPCFlag,
11585 "Invalid '%s' argument to kext collection info request.",
11586 kKextRequestArgumentCollectionTypeKey);
11587 goto finish;
11588 }
11589 if (collectionType->isEqualTo(kKCTypePrimary)) {
11590 kc_request_kind = KCKindPrimary;
11591 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11592 kc_request_kind = KCKindPageable;
11593 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11594 kc_request_kind = KCKindAuxiliary;
11595 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11596 kc_request_kind = KCKindNone;
11597 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11598 OSKextLog(/* kext */ NULL,
11599 kOSKextLogErrorLevel |
11600 kOSKextLogIPCFlag,
11601 "Invalid '%s' argument value '%s' to kext collection info request.",
11602 kKextRequestArgumentCollectionTypeKey,
11603 collectionType->getCStringNoCopy());
11604 goto finish;
11605 }
11606
11607 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11608 kKextRequestArgumentLoadedStateKey);
11609 if (rawLoadedState) {
11610 loadedState = OSDynamicCast(OSString, rawLoadedState);
11611 if (!loadedState) {
11612 OSKextLog(/* kext */ NULL,
11613 kOSKextLogErrorLevel |
11614 kOSKextLogIPCFlag,
11615 "Invalid '%s' argument to kext collection info request.",
11616 kKextRequestArgumentLoadedStateKey);
11617 goto finish;
11618 }
11619 }
11620 if (loadedState) {
11621 if (loadedState->isEqualTo("Loaded")) {
11622 onlyLoaded = true;
11623 } else if (loadedState->isEqualTo("Unloaded")) {
11624 onlyUnloaded = true;
11625 } else if (!loadedState->isEqualTo("Any")) {
11626 OSKextLog(/* kext */ NULL,
11627 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11628 "Invalid '%s' argument value '%s' for '%s' collection info",
11629 kKextRequestArgumentLoadedStateKey,
11630 loadedState->getCStringNoCopy(),
11631 collectionType->getCStringNoCopy());
11632 goto finish;
11633 }
11634 }
11635
11636 result = OSDictionary::withCapacity(sKextsByID->getCount());
11637 if (!result) {
11638 goto finish;
11639 }
11640
11641 IORecursiveLockLock(sKextLock);
11642 { // start block scope
11643 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11644 {
11645 OSKext *thisKext = NULL; // do not release
11646 OSSharedPtr<OSDictionary> kextInfo;
11647
11648 (void)thisKextID;
11649
11650 thisKext = OSDynamicCast(OSKext, obj);
11651 if (!thisKext) {
11652 return false;
11653 }
11654
11655 /*
11656 * skip the kext if it came from the wrong collection type
11657 * (and the caller requested a specific type)
11658 */
11659 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11660 return false;
11661 }
11662
11663 /*
11664 * respect the caller's desire to find only loaded or
11665 * unloaded kexts
11666 */
11667 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11668 return false;
11669 }
11670 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11671 return false;
11672 }
11673
11674 kextInfo = thisKext->copyInfo(infoKeys);
11675 if (kextInfo) {
11676 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11677 }
11678 return false;
11679 });
11680 } // end block scope
11681 IORecursiveLockUnlock(sKextLock);
11682
11683 finish:
11684 return result;
11685 }
11686
11687 /* static */
11688 OSSharedPtr<OSArray>
11689 OSKext::copyDextsInfo(
11690 OSArray *kextIdentifiers,
11691 OSArray *infoKeys)
11692 {
11693 OSSharedPtr<OSArray> result = NULL;
11694 uint32_t idCount = 0;
11695 bool getActive = false;
11696 bool getLoaded = false;
11697 bool getUnloaded = false;
11698 bool getPendingUpgrade = false;
11699 unsigned int avgDextCount = 0;
11700
11701 #if CONFIG_MACF
11702 /* Is the calling process allowed to query dext info? */
11703 if (current_task() != kernel_task) {
11704 int macCheckResult = 0;
11705 kauth_cred_t cred = NULL;
11706
11707 cred = kauth_cred_get_with_ref();
11708 macCheckResult = mac_kext_check_query(cred);
11709 kauth_cred_unref(&cred);
11710
11711 if (macCheckResult != 0) {
11712 OSKextLog(/* kext */ NULL,
11713 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11714 "Failed to query kext info (MAC policy error 0x%x).",
11715 macCheckResult);
11716 goto finish;
11717 }
11718 }
11719 #endif
11720 /*
11721 * No infoKeys means return everything we
11722 * know about the dexts.
11723 */
11724 if (infoKeys && !infoKeys->getCount()) {
11725 infoKeys = NULL;
11726 }
11727
11728 /*
11729 * Empty list of bundle ids is equivalent to
11730 * no list (get all).
11731 */
11732 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11733 kextIdentifiers = NULL;
11734 } else if (kextIdentifiers) {
11735 idCount = kextIdentifiers->getCount();
11736 }
11737
11738 /*
11739 * Caller can specify which state of dexts to query.
11740 */
11741 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveKey)) {
11742 getActive = true;
11743 }
11744 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11745 getLoaded = true;
11746 }
11747 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11748 getUnloaded = true;
11749 }
11750 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11751 getPendingUpgrade = true;
11752 }
11753
11754 /*
11755 * By default we are going to return all active and pendingUpgrade dexts
11756 * only.
11757 */
11758 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11759 getActive = true;
11760 getPendingUpgrade = true;
11761 }
11762
11763 /*
11764 * We return a dictionary of dexts
11765 * for every group requested.
11766 */
11767 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11768 result = OSArray::withCapacity(avgDextCount);
11769 if (!result) {
11770 goto finish;
11771 }
11772
11773 IORecursiveLockLock(sKextLock);
11774 { // start block scope
11775 if (getActive || getLoaded || getUnloaded) {
11776 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11777 {
11778 OSKext *thisKext = NULL; // do not release
11779 OSSharedPtr<OSDictionary> kextInfo;
11780 Boolean includeThis = true;
11781 (void)thisKextID;
11782
11783 thisKext = OSDynamicCast(OSKext, obj);
11784 if (!thisKext || !thisKext->isDriverKit()) {
11785 return false;
11786 }
11787
11788 /*
11789 * Skip current dext if we have a list of bundle IDs and
11790 * it isn't in the list.
11791 */
11792 if (kextIdentifiers) {
11793 includeThis = false;
11794
11795 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11796 const OSString * thisRequestID = OSDynamicCast(OSString,
11797 kextIdentifiers->getObject(idIndex));
11798 if (thisKextID->isEqualTo(thisRequestID)) {
11799 includeThis = true;
11800 break;
11801 }
11802 }
11803 }
11804
11805 if (!includeThis) {
11806 return false;
11807 }
11808
11809 OSSharedPtr<OSString> state;
11810 if (sLoadedDriverKitKexts->getNextIndexOfObject(thisKext, 0) == -1U) {
11811 if (!(getActive || getUnloaded)) {
11812 return false;
11813 }
11814 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11815 } else {
11816 if (!(getActive || getLoaded)) {
11817 return false;
11818 }
11819 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11820 }
11821
11822 kextInfo = thisKext->copyInfo(infoKeys);
11823 if (kextInfo) {
11824 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11825 result->setObject(kextInfo.get());
11826 }
11827
11828 return false;
11829 });
11830 }
11831
11832 if (getPendingUpgrade) {
11833 sDriverKitToUpgradeByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11834 {
11835 OSKext *thisKext = NULL; // do not release
11836 OSSharedPtr<OSDictionary> kextInfo;
11837 Boolean includeThis = true;
11838 (void)thisKextID;
11839
11840 thisKext = OSDynamicCast(OSKext, obj);
11841 if (!thisKext) {
11842 return false;
11843 }
11844 __assert_only bool isDext = thisKext->isDriverKit();
11845 assert(isDext == true);
11846
11847 /*
11848 * Skip current dext if we have a list of bundle IDs and
11849 * it isn't in the list.
11850 */
11851 if (kextIdentifiers) {
11852 includeThis = false;
11853
11854 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11855 const OSString * thisRequestID = OSDynamicCast(OSString,
11856 kextIdentifiers->getObject(idIndex));
11857 if (thisKextID->isEqualTo(thisRequestID)) {
11858 includeThis = true;
11859 break;
11860 }
11861 }
11862 }
11863
11864 if (!includeThis) {
11865 return false;
11866 }
11867
11868 kextInfo = thisKext->copyInfo(infoKeys);
11869 if (kextInfo) {
11870 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11871 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11872 result->setObject(kextInfo.get());
11873 }
11874 return false;
11875 });
11876 }
11877 } // end block scope
11878 IORecursiveLockUnlock(sKextLock);
11879 finish:
11880 return result;
11881 }
11882
11883 /*********************************************************************
11884 *********************************************************************/
11885 /* static */
11886 OSSharedPtr<OSDictionary>
11887 OSKext::copyLoadedKextInfo(
11888 OSArray * kextIdentifiers,
11889 OSArray * infoKeys)
11890 {
11891 OSSharedPtr<OSDictionary> result;
11892 uint32_t idCount = 0;
11893 bool onlyLoaded;
11894
11895 IORecursiveLockLock(sKextLock);
11896
11897 #if CONFIG_MACF
11898 /* Is the calling process allowed to query kext info? */
11899 if (current_task() != kernel_task) {
11900 int macCheckResult = 0;
11901 kauth_cred_t cred = NULL;
11902
11903 cred = kauth_cred_get_with_ref();
11904 macCheckResult = mac_kext_check_query(cred);
11905 kauth_cred_unref(&cred);
11906
11907 if (macCheckResult != 0) {
11908 OSKextLog(/* kext */ NULL,
11909 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11910 "Failed to query kext info (MAC policy error 0x%x).",
11911 macCheckResult);
11912 goto finish;
11913 }
11914 }
11915 #endif
11916
11917 /* Empty list of bundle ids is equivalent to no list (get all).
11918 */
11919 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11920 kextIdentifiers = NULL;
11921 } else if (kextIdentifiers) {
11922 idCount = kextIdentifiers->getCount();
11923 }
11924
11925 /* Same for keys.
11926 */
11927 if (infoKeys && !infoKeys->getCount()) {
11928 infoKeys = NULL;
11929 }
11930
11931 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
11932
11933 result = OSDictionary::withCapacity(128);
11934 if (!result) {
11935 goto finish;
11936 }
11937
11938 #if 0
11939 OSKextLog(/* kext */ NULL,
11940 kOSKextLogErrorLevel |
11941 kOSKextLogGeneralFlag,
11942 "kaslr: vm_kernel_slide 0x%lx \n",
11943 vm_kernel_slide);
11944 OSKextLog(/* kext */ NULL,
11945 kOSKextLogErrorLevel |
11946 kOSKextLogGeneralFlag,
11947 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11948 vm_kernel_stext, vm_kernel_etext);
11949 OSKextLog(/* kext */ NULL,
11950 kOSKextLogErrorLevel |
11951 kOSKextLogGeneralFlag,
11952 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11953 vm_kernel_base, vm_kernel_top);
11954 OSKextLog(/* kext */ NULL,
11955 kOSKextLogErrorLevel |
11956 kOSKextLogGeneralFlag,
11957 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11958 vm_kext_base, vm_kext_top);
11959 OSKextLog(/* kext */ NULL,
11960 kOSKextLogErrorLevel |
11961 kOSKextLogGeneralFlag,
11962 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11963 vm_prelink_stext, vm_prelink_etext);
11964 OSKextLog(/* kext */ NULL,
11965 kOSKextLogErrorLevel |
11966 kOSKextLogGeneralFlag,
11967 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11968 vm_prelink_sinfo, vm_prelink_einfo);
11969 OSKextLog(/* kext */ NULL,
11970 kOSKextLogErrorLevel |
11971 kOSKextLogGeneralFlag,
11972 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11973 vm_slinkedit, vm_elinkedit);
11974 #endif
11975 { // start block scope
11976 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
11977 {
11978 OSKext * thisKext = NULL; // do not release
11979 Boolean includeThis = true;
11980 OSSharedPtr<OSDictionary> kextInfo;
11981
11982 thisKext = OSDynamicCast(OSKext, obj);
11983 if (!thisKext) {
11984 return false;
11985 }
11986
11987 /* Skip current kext if not yet started and caller didn't request all.
11988 */
11989 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11990 return false;
11991 }
11992
11993 /* Skip current kext if we have a list of bundle IDs and
11994 * it isn't in the list.
11995 */
11996 if (kextIdentifiers) {
11997 includeThis = false;
11998
11999 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
12000 const OSString * thisRequestID = OSDynamicCast(OSString,
12001 kextIdentifiers->getObject(idIndex));
12002 if (thisKextID->isEqualTo(thisRequestID)) {
12003 includeThis = true;
12004 break;
12005 }
12006 }
12007 }
12008
12009 if (!includeThis) {
12010 return false;
12011 }
12012
12013 kextInfo = thisKext->copyInfo(infoKeys);
12014 if (kextInfo) {
12015 result->setObject(thisKext->getIdentifier(), kextInfo.get());
12016 }
12017 return false;
12018 });
12019 } // end block scope
12020
12021 finish:
12022 IORecursiveLockUnlock(sKextLock);
12023
12024 return result;
12025 }
12026
12027 /*********************************************************************
12028 * Any info that needs to do allocations must goto finish on alloc
12029 * failure. Info that is just a lookup should just not set the object
12030 * if the info does not exist.
12031 *********************************************************************/
12032 #define _OSKextLoadInfoDictCapacity (12)
12033
12034 OSSharedPtr<OSDictionary>
12035 OSKext::copyInfo(OSArray * infoKeys)
12036 {
12037 OSSharedPtr<OSDictionary> result;
12038 bool success = false;
12039 OSSharedPtr<OSData> headerData;
12040 OSSharedPtr<OSData> logData;
12041 OSSharedPtr<OSNumber> cpuTypeNumber;
12042 OSSharedPtr<OSNumber> cpuSubtypeNumber;
12043 OSString * versionString = NULL; // do not release
12044 OSString * bundleType = NULL; // do not release
12045 uint32_t executablePathCStringSize = 0;
12046 char * executablePathCString = NULL; // must kfree
12047 OSSharedPtr<OSString> executablePathString;
12048 OSSharedPtr<OSData> uuid;
12049 OSSharedPtr<OSArray> dependencyLoadTags;
12050 OSSharedPtr<OSCollectionIterator> metaClassIterator;
12051 OSSharedPtr<OSArray> metaClassInfo;
12052 OSSharedPtr<OSDictionary> metaClassDict;
12053 OSMetaClass * thisMetaClass = NULL; // do not release
12054 OSSharedPtr<OSString> metaClassName;
12055 OSSharedPtr<OSString> superclassName;
12056 kc_format_t kcformat;
12057 uint32_t count, i;
12058
12059 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
12060 if (!result) {
12061 goto finish;
12062 }
12063
12064
12065 /* Empty keys means no keys, but NULL is quicker to check.
12066 */
12067 if (infoKeys && !infoKeys->getCount()) {
12068 infoKeys = NULL;
12069 }
12070
12071 if (!PE_get_primary_kc_format(&kcformat)) {
12072 goto finish;
12073 }
12074
12075 /* Headers, CPU type, and CPU subtype.
12076 */
12077 if (!infoKeys ||
12078 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
12079 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
12080 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
12081 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12082 if (linkedExecutable && !isInterface()) {
12083 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
12084 linkedExecutable->getBytesNoCopy();
12085
12086 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
12087 // do not return macho header info on shipping embedded - 19095897
12088 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
12089 kernel_mach_header_t * temp_kext_mach_hdr;
12090 struct load_command * lcp;
12091
12092 headerData = OSData::withBytes(kext_mach_hdr,
12093 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
12094 if (!headerData) {
12095 goto finish;
12096 }
12097
12098 // unslide any vmaddrs we return to userspace - 10726716
12099 temp_kext_mach_hdr = (kernel_mach_header_t *)
12100 headerData->getBytesNoCopy();
12101 if (temp_kext_mach_hdr == NULL) {
12102 goto finish;
12103 }
12104
12105 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
12106 for (i = 0; (i < temp_kext_mach_hdr->ncmds) && !flags.unslidMachO; i++) {
12107 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12108 kernel_segment_command_t * segp;
12109 kernel_section_t * secp;
12110
12111 segp = (kernel_segment_command_t *) lcp;
12112 // 10543468 - if we jettisoned __LINKEDIT clear size info
12113 if (flags.jettisonLinkeditSeg) {
12114 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
12115 segp->vmsize = 0;
12116 segp->fileoff = 0;
12117 segp->filesize = 0;
12118 }
12119 }
12120
12121 #if __arm__ || __arm64__
12122 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
12123 // and unslide them to avoid vm assertion failures / kernel logging breakage.
12124 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
12125 segp->vmaddr = gVirtBase;
12126 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
12127 secp->size = 0; // paranoia :)
12128 secp->addr = gVirtBase;
12129 }
12130 }
12131 #endif
12132
12133 #if 0
12134 OSKextLog(/* kext */ NULL,
12135 kOSKextLogErrorLevel |
12136 kOSKextLogGeneralFlag,
12137 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
12138 __FUNCTION__, segp->segname, segp->vmaddr,
12139 VM_KERNEL_UNSLIDE(segp->vmaddr),
12140 segp->vmsize, segp->nsects);
12141 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
12142 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
12143 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
12144 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
12145 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
12146 OSKextLog(/* kext */ NULL,
12147 kOSKextLogErrorLevel |
12148 kOSKextLogGeneralFlag,
12149 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
12150 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
12151 }
12152 #endif
12153 segp->vmaddr = ml_static_unslide(segp->vmaddr);
12154
12155 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
12156 secp->addr = ml_static_unslide(secp->addr);
12157 }
12158 }
12159 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
12160 }
12161 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
12162 }
12163 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
12164
12165 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12166 osLogDataHeaderRef *header;
12167 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12168
12169 void *os_log_data = NULL;
12170 void *cstring_data = NULL;
12171 void *asan_cstring_data = NULL;
12172 unsigned long os_log_size = 0;
12173 unsigned long cstring_size = 0;
12174 unsigned long asan_cstring_size = 0;
12175 uint32_t os_log_offset = 0;
12176 uint32_t cstring_offset = 0;
12177 uint32_t asan_cstring_offset = 0;
12178 bool res;
12179
12180 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
12181 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
12182 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
12183
12184 /*
12185 * If the addresses in the Mach-O header are unslid, manually
12186 * slide them to allow for dereferencing.
12187 */
12188 if (flags.unslidMachO) {
12189 os_log_data = (os_log_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)os_log_data) : nullptr;
12190 cstring_data = (cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)cstring_data) : nullptr;
12191 asan_cstring_data = (asan_cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)asan_cstring_data) : nullptr;
12192 }
12193
12194 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
12195 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
12196 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
12197
12198 header = (osLogDataHeaderRef *) headerBytes;
12199 header->version = OS_LOG_HDR_VERSION;
12200 header->sect_count = NUM_OS_LOG_SECTIONS;
12201 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
12202 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
12203 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
12204 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
12205 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
12206 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
12207
12208
12209 logData = OSData::withValue(*header);
12210 if (!logData) {
12211 goto finish;
12212 }
12213 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12214 if (!res) {
12215 goto finish;
12216 }
12217 if (os_log_data) {
12218 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
12219 if (!res) {
12220 goto finish;
12221 }
12222 }
12223 if (cstring_data) {
12224 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
12225 if (!res) {
12226 goto finish;
12227 }
12228 }
12229 if (asan_cstring_data) {
12230 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
12231 if (!res) {
12232 goto finish;
12233 }
12234 }
12235 result->setObject(kOSBundleLogStringsKey, logData.get());
12236 }
12237
12238 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
12239 cpuTypeNumber = OSNumber::withNumber(
12240 (uint64_t) kext_mach_hdr->cputype,
12241 8 * sizeof(kext_mach_hdr->cputype));
12242 if (!cpuTypeNumber) {
12243 goto finish;
12244 }
12245 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
12246 }
12247
12248 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12249 cpuSubtypeNumber = OSNumber::withNumber(
12250 (uint64_t) kext_mach_hdr->cpusubtype,
12251 8 * sizeof(kext_mach_hdr->cpusubtype));
12252 if (!cpuSubtypeNumber) {
12253 goto finish;
12254 }
12255 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
12256 }
12257 } else {
12258 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12259 osLogDataHeaderRef *header;
12260 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12261 bool res;
12262
12263 header = (osLogDataHeaderRef *) headerBytes;
12264 header->version = OS_LOG_HDR_VERSION;
12265 header->sect_count = NUM_OS_LOG_SECTIONS;
12266 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
12267 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
12268 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
12269 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12270 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
12271 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12272
12273 logData = OSData::withValue(*header);
12274 if (!logData) {
12275 goto finish;
12276 }
12277 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12278 if (!res) {
12279 goto finish;
12280 }
12281 result->setObject(kOSBundleLogStringsKey, logData.get());
12282 }
12283 }
12284 }
12285
12286 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
12287 */
12288 result->setObject(kCFBundleIdentifierKey, bundleID.get());
12289
12290 /* kOSBundleDextUniqueIdentifierKey if present.
12291 */
12292 if (isDriverKit() && dextUniqueID != NULL) {
12293 result->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID.get());
12294 }
12295
12296 /* CFBundlePackageType
12297 */
12298 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12299 if (bundleType) {
12300 result->setObject(kCFBundlePackageTypeKey, bundleType);
12301 }
12302
12303 /* CFBundleVersion.
12304 */
12305 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
12306 versionString = OSDynamicCast(OSString,
12307 getPropertyForHostArch(kCFBundleVersionKey));
12308 if (versionString) {
12309 result->setObject(kCFBundleVersionKey, versionString);
12310 }
12311 }
12312
12313 /* OSBundleCompatibleVersion.
12314 */
12315 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
12316 versionString = OSDynamicCast(OSString,
12317 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12318 if (versionString) {
12319 result->setObject(kOSBundleCompatibleVersionKey, versionString);
12320 }
12321 }
12322
12323 /* Path.
12324 */
12325 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
12326 if (path) {
12327 result->setObject(kOSBundlePathKey, path.get());
12328 }
12329 }
12330
12331
12332 /* OSBundleExecutablePath.
12333 */
12334 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
12335 if (path && executableRelPath) {
12336 uint32_t pathLength = path->getLength(); // gets incremented below
12337
12338 // +1 for slash, +1 for \0
12339 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12340
12341 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12342 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12343 if (!executablePathCString) {
12344 goto finish;
12345 }
12346 strlcpy(executablePathCString, path->getCStringNoCopy(),
12347 executablePathCStringSize);
12348 executablePathCString[pathLength++] = '/';
12349 executablePathCString[pathLength++] = '\0';
12350 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
12351 executablePathCStringSize);
12352
12353 executablePathString = OSString::withCString(executablePathCString);
12354
12355 if (!executablePathString) {
12356 goto finish;
12357 }
12358
12359 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12360 } else if (flags.builtin) {
12361 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
12362 } else if (isDriverKit()) {
12363 if (path) {
12364 // +1 for slash, +1 for \0
12365 uint32_t pathLength = path->getLength();
12366 executablePathCStringSize = pathLength + 2;
12367
12368 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12369 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12370 if (!executablePathCString) {
12371 goto finish;
12372 }
12373 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
12374 executablePathCString[pathLength++] = '/';
12375 executablePathCString[pathLength++] = '\0';
12376
12377 executablePathString = OSString::withCString(executablePathCString);
12378
12379 if (!executablePathString) {
12380 goto finish;
12381 }
12382
12383 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12384 }
12385 }
12386 }
12387
12388 /* UUID, if the kext has one.
12389 */
12390 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
12391 uuid = copyUUID();
12392 if (uuid) {
12393 result->setObject(kOSBundleUUIDKey, uuid.get());
12394 }
12395 }
12396 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
12397 uuid = copyTextUUID();
12398 if (uuid) {
12399 result->setObject(kOSBundleTextUUIDKey, uuid.get());
12400 }
12401 }
12402
12403 /*
12404 * Info.plist digest
12405 */
12406 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
12407 OSData *digest;
12408 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12409 if (digest) {
12410 result->setObject(kOSKextInfoPlistDigestKey, digest);
12411 }
12412 }
12413
12414 /*
12415 * Collection type
12416 */
12417 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
12418 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
12419 }
12420
12421 /*
12422 * Collection availability
12423 */
12424 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
12425 result->setObject(kOSKextAuxKCAvailabilityKey,
12426 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12427 }
12428
12429 /*
12430 * Allows user load
12431 */
12432 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
12433 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12434 if (allowUserLoad) {
12435 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
12436 }
12437 }
12438
12439 /*
12440 * Bundle Dependencies (OSBundleLibraries)
12441 */
12442 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
12443 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12444 if (libraries) {
12445 result->setObject(kOSBundleLibrariesKey, libraries);
12446 }
12447 }
12448
12449 /*****
12450 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12451 */
12452 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
12453 result->setObject(kOSKernelResourceKey,
12454 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12455 }
12456
12457 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
12458 result->setObject(kOSBundleIsInterfaceKey,
12459 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12460 }
12461
12462 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
12463 result->setObject(kOSBundlePrelinkedKey,
12464 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12465 }
12466
12467 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
12468 result->setObject(kOSBundleStartedKey,
12469 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12470 }
12471
12472 /* LoadTag (Index).
12473 */
12474 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
12475 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
12476 /* numBits */ 8 * sizeof(loadTag));
12477 if (!scratchNumber) {
12478 goto finish;
12479 }
12480 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
12481 }
12482
12483 /* LoadAddress, LoadSize.
12484 */
12485 if (!infoKeys ||
12486 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
12487 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
12488 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
12489 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
12490 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12491 bool is_dext = isDriverKit();
12492 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12493 /* These go to userspace via serialization, so we don't want any doubts
12494 * about their size.
12495 */
12496 uint64_t loadAddress = 0;
12497 uint32_t loadSize = 0;
12498 uint32_t wiredSize = 0;
12499 uint64_t execLoadAddress = 0;
12500 uint32_t execLoadSize = 0;
12501
12502 /* Interfaces always report 0 load address & size.
12503 * Just the way they roll.
12504 *
12505 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12506 * xxx - shouldn't have one!
12507 */
12508
12509 if (flags.builtin || linkedExecutable) {
12510 kernel_mach_header_t *mh = NULL;
12511 kernel_segment_command_t *seg = NULL;
12512
12513 if (flags.builtin) {
12514 loadAddress = kmod_info->address;
12515 loadSize = (uint32_t)kmod_info->size;
12516 } else {
12517 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12518 loadSize = linkedExecutable->getLength();
12519 }
12520 mh = (kernel_mach_header_t *)loadAddress;
12521 loadAddress = ml_static_unslide(loadAddress);
12522
12523 /* Walk through the kext, looking for the first executable
12524 * segment in case we were asked for its size/address.
12525 */
12526 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
12527 if (seg->initprot & VM_PROT_EXECUTE) {
12528 execLoadAddress = (flags.unslidMachO) ? seg->vmaddr : ml_static_unslide(seg->vmaddr);
12529 execLoadSize = (uint32_t)seg->vmsize;
12530 break;
12531 }
12532 }
12533
12534 /* If we have a kmod_info struct, calculated the wired size
12535 * from that. Otherwise it's the full load size.
12536 */
12537 if (kmod_info) {
12538 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12539 } else {
12540 wiredSize = loadSize;
12541 }
12542 } else if (is_dext) {
12543 /*
12544 * DriverKit userspace executables do not have a kernel linkedExecutable,
12545 * so we "fake" their address range with the LoadTag.
12546 */
12547 if (loadTag) {
12548 loadAddress = execLoadAddress = loadTag;
12549 loadSize = execLoadSize = 1;
12550 }
12551 }
12552
12553 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
12554 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12555 (unsigned long long)(loadAddress),
12556 /* numBits */ 8 * sizeof(loadAddress));
12557 if (!scratchNumber) {
12558 goto finish;
12559 }
12560 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
12561 }
12562 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12563 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
12564 && loadAddress && loadSize) {
12565 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
12566 if (!baseAddress) {
12567 goto finish;
12568 }
12569
12570 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12571 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
12572 /* numBits */ 8 * sizeof(loadAddress));
12573 if (!scratchNumber) {
12574 goto finish;
12575 }
12576 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
12577 }
12578 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
12579 && (this == sKernelKext) && gBuiltinKmodsCount) {
12580 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
12581 }
12582 }
12583
12584 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
12585 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12586 (unsigned long long)(execLoadAddress),
12587 /* numBits */ 8 * sizeof(execLoadAddress));
12588 if (!scratchNumber) {
12589 goto finish;
12590 }
12591 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
12592 }
12593 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
12594 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12595 (unsigned long long)(loadSize),
12596 /* numBits */ 8 * sizeof(loadSize));
12597 if (!scratchNumber) {
12598 goto finish;
12599 }
12600 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
12601 }
12602 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
12603 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12604 (unsigned long long)(execLoadSize),
12605 /* numBits */ 8 * sizeof(execLoadSize));
12606 if (!scratchNumber) {
12607 goto finish;
12608 }
12609 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
12610 }
12611 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12612 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12613 (unsigned long long)(wiredSize),
12614 /* numBits */ 8 * sizeof(wiredSize));
12615 if (!scratchNumber) {
12616 goto finish;
12617 }
12618 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
12619 }
12620 }
12621 }
12622
12623 /* OSBundleDependencies. In descending order for
12624 * easy compatibility with kextstat(8).
12625 */
12626 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
12627 if ((count = getNumDependencies())) {
12628 dependencyLoadTags = OSArray::withCapacity(count);
12629 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
12630
12631 i = count - 1;
12632 do {
12633 OSKext * dependency = OSDynamicCast(OSKext,
12634 dependencies->getObject(i));
12635
12636 if (!dependency) {
12637 continue;
12638 }
12639 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12640 (unsigned long long)dependency->getLoadTag(),
12641 /* numBits*/ 8 * sizeof(loadTag));
12642 if (!scratchNumber) {
12643 goto finish;
12644 }
12645 dependencyLoadTags->setObject(scratchNumber.get());
12646 } while (i--);
12647 }
12648 }
12649
12650 /* OSBundleMetaClasses.
12651 */
12652 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
12653 if (metaClasses && metaClasses->getCount()) {
12654 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
12655 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
12656 if (!metaClassIterator || !metaClassInfo) {
12657 goto finish;
12658 }
12659 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
12660
12661 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12662 metaClassIterator->getNextObject()))) {
12663 metaClassDict = OSDictionary::withCapacity(3);
12664 if (!metaClassDict) {
12665 goto finish;
12666 }
12667
12668 metaClassName = OSString::withCString(thisMetaClass->getClassName());
12669 if (thisMetaClass->getSuperClass()) {
12670 superclassName = OSString::withCString(
12671 thisMetaClass->getSuperClass()->getClassName());
12672 }
12673 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
12674 8 * sizeof(unsigned int));
12675
12676 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12677 * of course.
12678 */
12679 if (!metaClassDict || !metaClassName || !scratchNumber) {
12680 goto finish;
12681 }
12682
12683 metaClassInfo->setObject(metaClassDict.get());
12684 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
12685 if (superclassName) {
12686 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
12687 }
12688 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
12689 }
12690 }
12691 }
12692
12693 /* OSBundleRetainCount.
12694 */
12695 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
12696 {
12697 int kextRetainCount = getRetainCount() - 1;
12698 if (isLoaded()) {
12699 kextRetainCount--;
12700 }
12701 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12702 (int)kextRetainCount,
12703 /* numBits*/ 8 * sizeof(int));
12704 if (scratchNumber) {
12705 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
12706 }
12707 }
12708 }
12709
12710 success = true;
12711
12712 finish:
12713 if (executablePathCString) {
12714 kfree_data(executablePathCString, executablePathCStringSize);
12715 }
12716 if (!success) {
12717 result.reset();
12718 }
12719 return result;
12720 }
12721
12722 /*********************************************************************
12723 *********************************************************************/
12724 /* static */
12725 bool
12726 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12727 {
12728 bool ok;
12729 OSSharedPtr<OSKext> kext;
12730
12731 IORecursiveLockLock(sKextLock);
12732 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12733 IORecursiveLockUnlock(sKextLock);
12734
12735 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12736 return false;
12737 }
12738 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
12739 kext->path->getCStringNoCopy(),
12740 kext->userExecutableRelPath->getCStringNoCopy());
12741 ok = true;
12742
12743 return ok;
12744 }
12745
12746 /*********************************************************************
12747 *********************************************************************/
12748 /* static */
12749 OSReturn
12750 OSKext::requestResource(
12751 const char * kextIdentifierCString,
12752 const char * resourceNameCString,
12753 OSKextRequestResourceCallback callback,
12754 void * context,
12755 OSKextRequestTag * requestTagOut)
12756 {
12757 OSReturn result = kOSReturnError;
12758 OSSharedPtr<OSKext> callbackKext; // looked up
12759
12760 OSKextRequestTag requestTag = -1;
12761 OSSharedPtr<OSNumber> requestTagNum;
12762 OSSharedPtr<OSDictionary> requestDict;
12763 OSSharedPtr<OSString> kextIdentifier;
12764 OSSharedPtr<OSString> resourceName;
12765
12766 OSSharedPtr<OSDictionary> callbackRecord;
12767 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12768
12769 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12770
12771 IORecursiveLockLock(sKextLock);
12772
12773 if (requestTagOut) {
12774 *requestTagOut = kOSKextRequestTagInvalid;
12775 }
12776
12777 /* If requests to user space are disabled, don't go any further */
12778 if (!sKernelRequestsEnabled) {
12779 OSKextLog(/* kext */ NULL,
12780 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12781 "Can't request resource %s for %s - requests to user space are disabled.",
12782 resourceNameCString,
12783 kextIdentifierCString);
12784 result = kOSKextReturnDisabled;
12785 goto finish;
12786 }
12787
12788 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12789 result = kOSKextReturnInvalidArgument;
12790 goto finish;
12791 }
12792
12793 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12794 if (!callbackKext) {
12795 OSKextLog(/* kext */ NULL,
12796 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12797 "Resource request has bad callback address.");
12798 result = kOSKextReturnInvalidArgument;
12799 goto finish;
12800 }
12801 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12802 OSKextLog(/* kext */ NULL,
12803 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12804 "Resource request callback is in a kext that is not started.");
12805 result = kOSKextReturnInvalidArgument;
12806 goto finish;
12807 }
12808
12809 /* Do not allow any new requests to be made on a kext that is unloading.
12810 */
12811 if (callbackKext->flags.stopping) {
12812 result = kOSKextReturnStopping;
12813 goto finish;
12814 }
12815
12816 /* If we're wrapped the next available request tag around to the negative
12817 * numbers, we can't service any more requests.
12818 */
12819 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12820 OSKextLog(/* kext */ NULL,
12821 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12822 "No more request tags available; restart required.");
12823 result = kOSKextReturnNoResources;
12824 goto finish;
12825 }
12826 requestTag = sNextRequestTag++;
12827
12828 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12829 requestDict);
12830 if (result != kOSReturnSuccess) {
12831 goto finish;
12832 }
12833
12834 kextIdentifier = OSString::withCString(kextIdentifierCString);
12835 resourceName = OSString::withCString(resourceNameCString);
12836 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12837 8 * sizeof(requestTag));
12838 if (!kextIdentifier ||
12839 !resourceName ||
12840 !requestTagNum ||
12841 !_OSKextSetRequestArgument(requestDict.get(),
12842 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
12843 !_OSKextSetRequestArgument(requestDict.get(),
12844 kKextRequestArgumentNameKey, resourceName.get()) ||
12845 !_OSKextSetRequestArgument(requestDict.get(),
12846 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
12847 result = kOSKextReturnNoMemory;
12848 goto finish;
12849 }
12850
12851 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
12852 if (!callbackRecord) {
12853 result = kOSKextReturnNoMemory;
12854 goto finish;
12855 }
12856 // we validate callback address at call time
12857 callbackWrapper = OSValueObjectWithValue(callback);
12858 if (context) {
12859 contextWrapper = OSValueObjectWithValue(context);
12860 }
12861 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12862 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
12863 result = kOSKextReturnNoMemory;
12864 goto finish;
12865 }
12866
12867 if (context) {
12868 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12869 kKextRequestArgumentContextKey, contextWrapper.get())) {
12870 result = kOSKextReturnNoMemory;
12871 goto finish;
12872 }
12873 }
12874
12875 /* Only post the requests after all the other potential failure points
12876 * have been passed.
12877 */
12878 if (!sKernelRequests->setObject(requestDict.get()) ||
12879 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12880 result = kOSKextReturnNoMemory;
12881 goto finish;
12882 }
12883
12884 OSKext::pingIOKitDaemon();
12885
12886 result = kOSReturnSuccess;
12887 if (requestTagOut) {
12888 *requestTagOut = requestTag;
12889 }
12890
12891 finish:
12892
12893 /* If we didn't succeed, yank the request & callback
12894 * from their holding arrays.
12895 */
12896 if (result != kOSReturnSuccess) {
12897 unsigned int index;
12898
12899 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
12900 if (index != (unsigned int)-1) {
12901 sKernelRequests->removeObject(index);
12902 }
12903 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
12904 if (index != (unsigned int)-1) {
12905 sRequestCallbackRecords->removeObject(index);
12906 }
12907 }
12908
12909 OSKext::considerUnloads(/* rescheduleOnly? */ true);
12910
12911 IORecursiveLockUnlock(sKextLock);
12912
12913 return result;
12914 }
12915
12916 OSReturn
12917 OSKext::requestDaemonLaunch(
12918 OSString *kextIdentifier,
12919 OSString *serverName,
12920 OSNumber *serverTag,
12921 OSBoolean *reslide,
12922 IOUserServerCheckInToken * checkInToken,
12923 OSData *serverDUI)
12924 {
12925 OSReturn result = kOSReturnError;
12926 OSSharedPtr<OSDictionary> requestDict;
12927 unsigned int size = 0;
12928 const char *dextUniqueIDCString = NULL;
12929
12930 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12931 return kOSKextReturnInvalidArgument;
12932 }
12933 if (!iokitDaemonAvailable()) {
12934 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
12935 }
12936
12937 if (serverDUI != NULL) {
12938 dextUniqueIDCString = getDextUniqueIDCString(serverDUI, &size);
12939 }
12940
12941 IORecursiveLockLock(sKextLock);
12942
12943 OSKextLog(/* kext */ NULL,
12944 kOSKextLogDebugLevel |
12945 kOSKextLogGeneralFlag,
12946 "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12947 kextIdentifier->getCStringNoCopy(),
12948 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12949 serverName->getCStringNoCopy(),
12950 serverTag->unsigned64BitValue(),
12951 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12952 );
12953
12954 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
12955 if (result != kOSReturnSuccess) {
12956 goto finish;
12957 }
12958
12959 if (!_OSKextSetRequestArgument(requestDict.get(),
12960 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12961 !_OSKextSetRequestArgument(requestDict.get(),
12962 kKextRequestArgumentDriverExtensionServerName, serverName) ||
12963 !_OSKextSetRequestArgument(requestDict.get(),
12964 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
12965 !_OSKextSetRequestArgument(requestDict.get(),
12966 kKextRequestArgumentDriverExtensionReslideSharedCache, reslide) ||
12967 !_OSKextSetRequestArgument(requestDict.get(),
12968 kKextRequestArgumentCheckInToken, checkInToken)) {
12969 result = kOSKextReturnNoMemory;
12970 goto finish;
12971 }
12972
12973 if (serverDUI) {
12974 if (!_OSKextSetRequestArgument(requestDict.get(),
12975 kOSBundleDextUniqueIdentifierKey, serverDUI)) {
12976 result = kOSKextReturnNoMemory;
12977 goto finish;
12978 }
12979 }
12980
12981 /* Only post the requests after all the other potential failure points
12982 * have been passed.
12983 */
12984 if (!sKernelRequests->setObject(requestDict.get())) {
12985 result = kOSKextReturnNoMemory;
12986 goto finish;
12987 }
12988 result = OSKext::pingIOKitDaemon();
12989 if (result != kOSReturnSuccess) {
12990 goto finish;
12991 }
12992
12993 result = kOSReturnSuccess;
12994 finish:
12995 IORecursiveLockUnlock(sKextLock);
12996 if (dextUniqueIDCString) {
12997 kfree_data(dextUniqueIDCString, size);
12998 }
12999 return result;
13000 }
13001
13002 OSReturn
13003 OSKext::notifyDextUpgrade(
13004 OSString *kextIdentifier,
13005 OSData *dextUniqueIdentifier)
13006 {
13007 OSReturn result = kOSReturnError;
13008 OSSharedPtr<OSDictionary> requestDict;
13009 unsigned int size = 0;
13010 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueIdentifier, &size);
13011 assert(dextUniqueIDCString != NULL);
13012
13013 IORecursiveLockLock(sKextLock);
13014
13015 OSKextLog(NULL,
13016 kOSKextLogDebugLevel |
13017 kOSKextLogGeneralFlag,
13018 "Notifying of dext upgrade for %s with UniqueID %s",
13019 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
13020
13021 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestDict);
13022 if (result != kOSReturnSuccess) {
13023 goto finish;
13024 }
13025
13026 if (!_OSKextSetRequestArgument(requestDict.get(),
13027 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
13028 !_OSKextSetRequestArgument(requestDict.get(),
13029 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
13030 result = kOSKextReturnNoMemory;
13031 goto finish;
13032 }
13033
13034 /* Only post the requests after all the other potential failure points
13035 * have been passed.
13036 */
13037 if (!sKernelRequests->setObject(requestDict.get())) {
13038 result = kOSKextReturnNoMemory;
13039 goto finish;
13040 }
13041 OSKext::pingIOKitDaemon();
13042
13043 result = kOSReturnSuccess;
13044 finish:
13045 IORecursiveLockUnlock(sKextLock);
13046
13047 if (dextUniqueIDCString != NULL) {
13048 kfree_data(dextUniqueIDCString, size);
13049 }
13050 return result;
13051 }
13052
13053 /*********************************************************************
13054 * Assumes sKextLock is held.
13055 *********************************************************************/
13056 /* static */
13057 OSReturn
13058 OSKext::dequeueCallbackForRequestTag(
13059 OSKextRequestTag requestTag,
13060 OSSharedPtr<OSDictionary> &callbackRecordOut)
13061 {
13062 OSDictionary * callbackRecordOutRaw = NULL;
13063 OSReturn result;
13064
13065 result = dequeueCallbackForRequestTag(requestTag,
13066 &callbackRecordOutRaw);
13067
13068 if (kOSReturnSuccess == result) {
13069 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
13070 }
13071
13072 return result;
13073 }
13074 OSReturn
13075 OSKext::dequeueCallbackForRequestTag(
13076 OSKextRequestTag requestTag,
13077 OSDictionary ** callbackRecordOut)
13078 {
13079 OSReturn result = kOSReturnError;
13080 OSSharedPtr<OSNumber> requestTagNum;
13081
13082 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
13083 8 * sizeof(requestTag));
13084 if (!requestTagNum) {
13085 goto finish;
13086 }
13087
13088 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
13089 callbackRecordOut);
13090
13091 finish:
13092 return result;
13093 }
13094
13095 /*********************************************************************
13096 * Assumes sKextLock is held.
13097 *********************************************************************/
13098 /* static */
13099 OSReturn
13100 OSKext::dequeueCallbackForRequestTag(
13101 OSNumber * requestTagNum,
13102 OSSharedPtr<OSDictionary> &callbackRecordOut)
13103 {
13104 OSDictionary * callbackRecordOutRaw = NULL;
13105 OSReturn result;
13106
13107 result = dequeueCallbackForRequestTag(requestTagNum,
13108 &callbackRecordOutRaw);
13109
13110 if (kOSReturnSuccess == result) {
13111 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
13112 }
13113
13114 return result;
13115 }
13116 OSReturn
13117 OSKext::dequeueCallbackForRequestTag(
13118 OSNumber * requestTagNum,
13119 OSDictionary ** callbackRecordOut)
13120 {
13121 OSReturn result = kOSKextReturnInvalidArgument;
13122 OSDictionary * callbackRecord = NULL; // retain if matched!
13123 OSNumber * callbackTagNum = NULL; // do not release
13124 unsigned int count, i;
13125
13126 result = kOSReturnError;
13127 count = sRequestCallbackRecords->getCount();
13128 for (i = 0; i < count; i++) {
13129 callbackRecord = OSDynamicCast(OSDictionary,
13130 sRequestCallbackRecords->getObject(i));
13131 if (!callbackRecord) {
13132 goto finish;
13133 }
13134
13135 /* If we don't find a tag, we basically have a leak here. Maybe
13136 * we should just remove it.
13137 */
13138 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
13139 callbackRecord, kKextRequestArgumentRequestTagKey));
13140 if (!callbackTagNum) {
13141 goto finish;
13142 }
13143
13144 /* We could be even more paranoid and check that all the incoming
13145 * args match what's in the callback record.
13146 */
13147 if (callbackTagNum->isEqualTo(requestTagNum)) {
13148 if (callbackRecordOut) {
13149 *callbackRecordOut = callbackRecord;
13150 callbackRecord->retain();
13151 }
13152 sRequestCallbackRecords->removeObject(i);
13153 result = kOSReturnSuccess;
13154 goto finish;
13155 }
13156 }
13157 result = kOSKextReturnNotFound;
13158
13159 finish:
13160 return result;
13161 }
13162
13163
13164 /*********************************************************************
13165 * Busy timeout triage
13166 *********************************************************************/
13167 /* static */
13168 bool
13169 OSKext::pendingIOKitDaemonRequests(void)
13170 {
13171 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
13172 }
13173
13174 /*********************************************************************
13175 * Acquires and releases sKextLock
13176 *
13177 * This function is designed to be called by kernelmanagerd and driverkitd
13178 * and it gathers all codeless kext and dext personalities, and then attempts
13179 * to map a System (pageable) KC and an Auxiliary (aux) KC.
13180 *
13181 * The pageable and aux KC can be loaded only once at boot time.
13182 * Even if the pageable or aux KC fail to load - this function will
13183 * not allow a new pageable or aux KC to be installed by subsequent calls.
13184 * This is done to avoid security issues where userspace has been compromised
13185 * or the pageable kc has been tampered with and the attacker
13186 * attempts to re-load a malicious variant.
13187 * However dexts can be dynamically loaded, so this function can be used
13188 * to request the installation of a new set of dexts even after boot time.
13189 *
13190 *
13191 *
13192 * Return: if a KC fails to load the return value will contain:
13193 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
13194 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
13195 * Similarly, if the aux kc load fails, the return value will
13196 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
13197 * compose with each other and with kOSKextReturnKCLoadFailure.
13198 *********************************************************************/
13199 /* static */
13200 OSReturn
13201 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
13202 {
13203 static bool daemon_ready = false;
13204
13205 OSReturn ret = kOSKextReturnInvalidArgument;
13206 OSReturn kcerr = 0;
13207 bool start_matching = false;
13208
13209 bool allow_fileset_load = !daemon_ready;
13210 #if !(defined(__x86_64__) || defined(__i386__))
13211 /* never allow KCs full of kexts on non-x86 machines */
13212 allow_fileset_load = false;
13213 #endif
13214
13215 /*
13216 * Change with 70582300
13217 */
13218 #if 0 || !defined(VM_MAPPED_KEXTS)
13219 /*
13220 * On platforms that don't support the SystemKC or a file-backed
13221 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
13222 * needs to be queried before we load any codeless kexts or release
13223 * any 3rd party kexts to run. On platforms that support a file-backed
13224 * AuxKC, this process is done via the kext audit mechanism.
13225 */
13226
13227 printf("KextLog: waiting for kext receipt to be queried.\n");
13228 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
13229 IOSleep(30);
13230 }
13231 #endif /* !VM_MAPPED_KEXTS */
13232
13233 /*
13234 * Get the args from the request. Right now we need the file
13235 * name for the pageable and the aux kext collection file sets.
13236 */
13237 OSDictionary * requestArgs = NULL; // do not release
13238 OSString * pageable_filepath = NULL; // do not release
13239 OSString * aux_filepath = NULL; // do not release
13240 OSArray * codeless_kexts = NULL; // do not release
13241
13242 kernel_mach_header_t *akc_mh = NULL;
13243
13244 requestArgs = OSDynamicCast(OSDictionary,
13245 requestDict->getObject(kKextRequestArgumentsKey));
13246
13247 if (requestArgs == NULL) {
13248 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13249 "KextLog: No arguments in plist for loading fileset kext\n");
13250 printf("KextLog: No arguments in plist for loading fileset kext\n");
13251 return ret;
13252 }
13253
13254 ret = kOSKextReturnDisabled;
13255
13256 IORecursiveLockLock(sKextLock);
13257
13258 if (!sLoadEnabled) {
13259 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13260 "KextLog: Kext loading is disabled (attempt to load KCs).");
13261 IORecursiveLockUnlock(sKextLock);
13262 return ret;
13263 }
13264
13265 pageable_filepath = OSDynamicCast(OSString,
13266 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
13267
13268 if (allow_fileset_load && pageable_filepath != NULL) {
13269 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
13270
13271 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
13272 if (ret) {
13273 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13274 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13275
13276 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13277 ret = kOSKextReturnKCLoadFailure;
13278 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
13279 goto try_auxkc;
13280 }
13281 /*
13282 * Even if the AuxKC fails to load, we still want to send
13283 * the System KC personalities to the catalog for matching
13284 */
13285 start_matching = true;
13286 } else if (pageable_filepath != NULL) {
13287 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13288 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
13289 ret = kOSKextReturnUnsupported;
13290 }
13291
13292 try_auxkc:
13293 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
13294 if (akc_mh) {
13295 /*
13296 * If we try to load a deferred AuxKC, then don't ever attempt
13297 * a filesystem map of a file
13298 */
13299 allow_fileset_load = false;
13300
13301 /*
13302 * This function is only called once per boot, so we haven't
13303 * yet loaded an AuxKC. If we have registered the AuxKC mach
13304 * header, that means that the kext collection has been placed
13305 * in memory for us by the booter, and is waiting for us to
13306 * process it. Grab the deferred XML plist of info
13307 * dictionaries and add all the kexts.
13308 */
13309 OSSharedPtr<OSObject> parsedXML;
13310 OSSharedPtr<OSData> loaded_kcUUID;
13311 OSDictionary *infoDict;
13312 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
13313 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13314 #if !defined(VM_MAPPED_KEXTS)
13315 /*
13316 * On platforms where we don't dynamically wire-down / page-in
13317 * kext memory, we need to maintain the invariant that if the
13318 * AuxKC in memory does not contain a kext receipt, then we
13319 * should not load any of the kexts.
13320 */
13321 size_t receipt_sz = 0;
13322 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13323 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13324 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13325 ret = kOSKextReturnKCLoadFailure;
13326 goto try_codeless;
13327 }
13328 #endif
13329 if (infoDict) {
13330 bool added;
13331 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13332 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
13333 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
13334 if (!loaded_kcUUID) {
13335 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13336 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13337 } else if (!added) {
13338 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13339 "KextLog: WARNING: Failed to load AuxKC from memory.");
13340 }
13341 /* only return success if the pageable load (above) was successful */
13342 if (ret != kOSKextReturnKCLoadFailure) {
13343 ret = kOSReturnSuccess;
13344 }
13345 /* the registration of the AuxKC parsed out the KC's UUID already */
13346 } else {
13347 if (daemon_ready) {
13348 /*
13349 * Complain, but don't return an error if this isn't the first time the
13350 * IOKit daemon is checking in. If the daemon ever restarts, we will
13351 * hit this case because we've already consumed the deferred personalities.
13352 * We return success here so that a call to this function from a restarted
13353 * daemon with no codeless kexts will succeed.
13354 */
13355 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13356 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13357 if (ret != kOSKextReturnKCLoadFailure) {
13358 ret = kOSReturnSuccess;
13359 }
13360 } else {
13361 /* this is a real error case */
13362 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13363 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13364 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13365 ret = kOSKextReturnKCLoadFailure;
13366 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13367 }
13368 }
13369 }
13370
13371 aux_filepath = OSDynamicCast(OSString,
13372 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13373 if (allow_fileset_load && aux_filepath != NULL) {
13374 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13375
13376 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
13377 if (ret) {
13378 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13379 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13380
13381 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13382 ret = kOSKextReturnKCLoadFailure;
13383 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13384 goto try_codeless;
13385 }
13386 start_matching = true;
13387 } else if (aux_filepath != NULL) {
13388 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13389 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13390 if (ret != kOSKextReturnKCLoadFailure) {
13391 ret = kOSKextReturnUnsupported;
13392 }
13393 }
13394
13395 try_codeless:
13396 /*
13397 * Load codeless kexts last so that there is no possibilty of a
13398 * codeless kext bundle ID preventing a kext in the system KC from
13399 * loading
13400 */
13401 codeless_kexts = OSDynamicCast(OSArray,
13402 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13403 if (codeless_kexts != NULL) {
13404 uint32_t count = codeless_kexts->getCount();
13405 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13406 "KextLog: loading %d codeless kexts/dexts", count);
13407 for (uint32_t i = 0; i < count; i++) {
13408 OSDictionary *infoDict;
13409 infoDict = OSDynamicCast(OSDictionary,
13410 codeless_kexts->getObject(i));
13411 if (!infoDict) {
13412 continue;
13413 }
13414 // instantiate a new kext, and don't hold a reference
13415 // (the kext subsystem will hold one implicitly)
13416 OSKext::withCodelessInfo(infoDict, NULL);
13417 }
13418 /* ignore errors that are not KC load failures */
13419 if (ret != kOSKextReturnKCLoadFailure) {
13420 ret = kOSReturnSuccess;
13421 }
13422 start_matching = true;
13423 }
13424
13425 /* send personalities to the IOCatalog once */
13426 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13427 OSKext::sendAllKextPersonalitiesToCatalog(true);
13428 /*
13429 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13430 * things as active and start all the delayed matching: the
13431 * dext and codeless kext personalities should have all been
13432 * delivered via this one call.
13433 */
13434 if (!daemon_ready) {
13435 OSKext::setIOKitDaemonActive();
13436 OSKext::setDeferredLoadSucceeded(TRUE);
13437 IOService::iokitDaemonLaunched();
13438 }
13439 if (sOSKextWasResetAfterUserspaceReboot) {
13440 sOSKextWasResetAfterUserspaceReboot = false;
13441 OSKext::setIOKitDaemonActive();
13442 IOService::startDeferredMatches();
13443 }
13444 }
13445
13446 if (ret == kOSKextReturnKCLoadFailure) {
13447 ret |= kcerr;
13448 }
13449
13450 /*
13451 * Only allow this function to attempt to load the pageable and
13452 * aux KCs once per boot.
13453 */
13454 daemon_ready = true;
13455
13456 IORecursiveLockUnlock(sKextLock);
13457
13458 return ret;
13459 }
13460
13461 OSReturn
13462 OSKext::resetMutableSegments(void)
13463 {
13464 kernel_segment_command_t *seg = NULL;
13465 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13466 u_int index = 0;
13467 OSKextSavedMutableSegment *savedSegment = NULL;
13468 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
13469 OSReturn err;
13470
13471 if (!savedMutableSegments) {
13472 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13473 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13474 err = kOSKextReturnInternalError;
13475 goto finish;
13476 }
13477
13478 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
13479 if (!segmentIsMutable(seg)) {
13480 continue;
13481 }
13482 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13483 uint64_t vmsize = seg->vmsize;
13484 err = kOSKextReturnInternalError;
13485 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13486 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13487 assert(savedSegment);
13488 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13489 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13490 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13491 err = savedSegment->restoreContents(seg);
13492 if (err != kOSReturnSuccess) {
13493 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13494 }
13495 }
13496 }
13497 if (err != kOSReturnSuccess) {
13498 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13499 }
13500 }
13501 err = kOSReturnSuccess;
13502 finish:
13503 return err;
13504 }
13505
13506
13507 /*********************************************************************
13508 * Assumes sKextLock is held.
13509 *********************************************************************/
13510 /* static */
13511 OSReturn
13512 OSKext::loadKCFileSet(
13513 const char *filepath,
13514 kc_kind_t type)
13515 {
13516 #if VM_MAPPED_KEXTS
13517 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13518 OSReturn err;
13519 struct vnode *vp = NULL;
13520 void *fileset_control;
13521 off_t fsize;
13522 bool pageable = (type == KCKindPageable);
13523
13524 if ((pageable && pageableKCloaded) ||
13525 (!pageable && auxKCloaded)) {
13526 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13527 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13528
13529 return kOSKextReturnInvalidArgument;
13530 }
13531
13532 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13533 if (!pageable && !pageableKCloaded) {
13534 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13535 "Trying to load the Aux KC without loading the Pageable KC");
13536 return kOSKextReturnInvalidArgument;
13537 }
13538
13539 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13540
13541 if (fileset_control == NULL) {
13542 printf("Could not get memory control object for file %s", filepath);
13543
13544 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13545 "Could not get memory control object for file %s", filepath);
13546 return kOSKextReturnInvalidArgument;
13547 }
13548 if (vp == NULL) {
13549 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13550 "Could not find vnode for file %s", filepath);
13551 return kOSKextReturnInvalidArgument;
13552 }
13553
13554 kernel_mach_header_t *mh = NULL;
13555 uintptr_t slide = 0;
13556
13557 #if CONFIG_CSR
13558 /*
13559 * When SIP is enabled, the KC we map must be SIP-protected
13560 */
13561 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13562 struct vnode_attr va;
13563 int error;
13564 VATTR_INIT(&va);
13565 VATTR_WANTED(&va, va_flags);
13566 error = vnode_getattr(vp, &va, vfs_context_current());
13567 if (error) {
13568 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13569 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13570 err = kOSKextReturnInternalError;
13571 goto finish;
13572 }
13573 if (!(va.va_flags & SF_RESTRICTED)) {
13574 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13575 "Path to KC '%s' is not SIP-protected", filepath);
13576 err = kOSKextReturnInvalidArgument;
13577 goto finish;
13578 }
13579 }
13580 #endif
13581
13582 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13583 if (err) {
13584 printf("KextLog: mapKCFileSet returned %d\n", err);
13585
13586 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13587 "mapKCFileSet returned %d\n", err);
13588
13589 err = kOSKextReturnInvalidArgument;
13590 }
13591
13592 #if CONFIG_CSR
13593 finish:
13594 #endif
13595 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13596 assert(vp != NULL);
13597 if (err == kOSReturnSuccess) {
13598 PE_set_kc_vp(type, vp);
13599 if (pageable) {
13600 pageableKCloaded = true;
13601 } else {
13602 auxKCloaded = true;
13603 }
13604 } else {
13605 vnode_put(vp);
13606 }
13607
13608 return err;
13609 #else
13610 (void)filepath;
13611 (void)type;
13612 return kOSKextReturnUnsupported;
13613 #endif // VM_MAPPED_KEXTS
13614 }
13615
13616 #if defined(__x86_64__) || defined(__i386__)
13617 /*********************************************************************
13618 * Assumes sKextLock is held.
13619 *********************************************************************/
13620 /* static */
13621 OSReturn
13622 OSKext::mapKCFileSet(
13623 void *control,
13624 vm_size_t fsize,
13625 kernel_mach_header_t **mhp,
13626 off_t file_offset,
13627 uintptr_t *slidep,
13628 bool pageable,
13629 void *map_entry_list)
13630 {
13631 bool fileset_load = false;
13632 kern_return_t ret;
13633 OSReturn err;
13634 kernel_section_t *infoPlistSection = NULL;
13635 OSDictionary *infoDict = NULL;
13636
13637 OSSharedPtr<OSObject> parsedXML;
13638 OSSharedPtr<OSString> errorString;
13639 OSSharedPtr<OSData> loaded_kcUUID;
13640
13641 /* Check if initial load for file set */
13642 if (*mhp == NULL) {
13643 fileset_load = true;
13644
13645 /* Get a page aligned address from kext map to map the file */
13646 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13647 if (pagealigned_addr == 0) {
13648 return kOSKextReturnNoMemory;
13649 }
13650
13651 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13652
13653 /* Allocate memory for bailout mechanism */
13654 map_entry_list = allocate_kcfileset_map_entry_list();
13655 if (map_entry_list == NULL) {
13656 return kOSKextReturnNoMemory;
13657 }
13658 }
13659
13660 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13661 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13662 /* mhp and slideptr are updated by mapKCTextSegment */
13663 if (err) {
13664 if (fileset_load) {
13665 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13666 }
13667 return err;
13668 }
13669
13670 /* Initialize the kc header globals */
13671 if (fileset_load) {
13672 if (pageable) {
13673 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13674 } else {
13675 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13676 }
13677 }
13678
13679 /* Iterate through all the segments and map necessary segments */
13680 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13681 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13682 vm_map_offset_t start;
13683 kernel_mach_header_t *k_mh = NULL;
13684 kernel_segment_command_t * seg = NULL;
13685 struct fileset_entry_command *fse = NULL;
13686
13687 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13688 seg = (kernel_segment_command_t *)lcp;
13689 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13690 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13691 fse = (struct fileset_entry_command *)lcp;
13692 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13693
13694 /* Map the segments of the mach-o binary */
13695 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13696 if (err) {
13697 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13698 return kOSKextReturnInvalidArgument;
13699 }
13700 continue;
13701 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13702 /* Check if the Aux KC is built pageable style */
13703 if (!pageable && !fileset_load && !auxKCloaded) {
13704 resetAuxKCSegmentOnUnload = true;
13705 }
13706 continue;
13707 } else {
13708 continue;
13709 }
13710
13711 if (fileset_load) {
13712 if (seg->vmsize == 0) {
13713 continue;
13714 }
13715
13716 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13717 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13718 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13719 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13720 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13721 continue;
13722 }
13723 } else {
13724 if (seg->vmsize == 0) {
13725 continue;
13726 }
13727
13728 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13729 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13730 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13731 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13732 continue;
13733 }
13734 }
13735
13736 ret = vm_map_kcfileset_segment(
13737 &start, seg->vmsize,
13738 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13739
13740 if (ret != KERN_SUCCESS) {
13741 if (fileset_load) {
13742 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13743 }
13744 return kOSKextReturnInvalidArgument;
13745 }
13746 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13747 }
13748
13749 /* Return if regular mach-o */
13750 if (!fileset_load) {
13751 return 0;
13752 }
13753
13754 /*
13755 * Fixup for the Pageable KC and the Aux KC is done by
13756 * i386_slide_kext_collection_mh_addrs, but it differs in
13757 * following ways:
13758 *
13759 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13760 * The fixup of kext segments and kext load commands are done at kext
13761 * load time by calling i386_slide_individual_kext.
13762 *
13763 * AuxKC old style: Fixup all the segments and all the load commands.
13764 *
13765 * AuxKC pageable style: Same as the Pageable KC.
13766 */
13767 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13768 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13769 if (ret != KERN_SUCCESS) {
13770 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13771 return kOSKextReturnInvalidArgument;
13772 }
13773
13774 /* Get the prelink info dictionary */
13775 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13776 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13777 if (parsedXML) {
13778 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13779 }
13780
13781 if (!infoDict) {
13782 const char *errorCString = "(unknown error)";
13783
13784 if (errorString && errorString->getCStringNoCopy()) {
13785 errorCString = errorString->getCStringNoCopy();
13786 } else if (parsedXML) {
13787 errorCString = "not a dictionary";
13788 }
13789 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13790 "Error unserializing kext info plist section: %s.", errorCString);
13791 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13792 return kOSKextReturnInvalidArgument;
13793 }
13794
13795 /* Validate that the Kext Collection is prelinked to the loaded KC */
13796 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13797 if (err) {
13798 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13799 return kOSKextReturnInvalidArgument;
13800 }
13801
13802 /* Set Protection of Segments */
13803 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13804
13805 OSKext::addKextsFromKextCollection(*mhp,
13806 infoDict, kPrelinkTextSegment,
13807 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13808
13809 /* Copy in the KC UUID */
13810 if (!loaded_kcUUID) {
13811 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13812 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13813 } else if (pageable) {
13814 pageablekc_uuid_valid = TRUE;
13815 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13816 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13817 } else {
13818 auxkc_uuid_valid = TRUE;
13819 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13820 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13821 }
13822
13823 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13824
13825 return 0;
13826 }
13827
13828 /*********************************************************************
13829 * Assumes sKextLock is held.
13830 *********************************************************************/
13831 /* static */
13832 OSReturn
13833 OSKext::mapKCTextSegment(
13834 void *control,
13835 kernel_mach_header_t **mhp,
13836 off_t file_offset,
13837 uintptr_t *slidep,
13838 void *map_entry_list)
13839 {
13840 kern_return_t ret;
13841 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13842 PAGE_MASK);
13843 vm_map_offset_t load_command_map_size = 0;
13844 kernel_mach_header_t *base_mh = *mhp;
13845
13846 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13847 ret = vm_map_kcfileset_segment(
13848 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13849 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13850
13851 if (ret != KERN_SUCCESS) {
13852 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13853
13854 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13855 "Failed to map mach header of kc fileset with error %d", ret);
13856 return kOSKextReturnInvalidArgument;
13857 }
13858
13859 if (slidep) {
13860 /* Verify that it's an MH_FILESET */
13861 if (base_mh->filetype != MH_FILESET) {
13862 printf("Kext Log: mapKCTextSegment mach header filetype"
13863 " is not an MH_FILESET, it is %x", base_mh->filetype);
13864
13865 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13866 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
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 /* Map the remaining pages of load commands */
13875 if (base_mh->sizeofcmds > mach_header_map_size) {
13876 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13877 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13878
13879 /* Map the load commands */
13880 ret = vm_map_kcfileset_segment(
13881 &load_command_addr, load_command_map_size,
13882 (memory_object_control_t)control, file_offset + mach_header_map_size,
13883 (VM_PROT_READ | VM_PROT_WRITE));
13884
13885 if (ret != KERN_SUCCESS) {
13886 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13887 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13888 "Failed to map load commands of kc fileset with error %d", ret);
13889
13890 /* Unmap the mach header */
13891 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13892 return kOSKextReturnInvalidArgument;
13893 }
13894 }
13895
13896 kernel_segment_command_t *text_seg;
13897 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13898
13899 /* Calculate the slide and vm addr of mach header */
13900 if (slidep) {
13901 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13902 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13903 }
13904
13905 /* Cache the text segment size and file offset before unmapping */
13906 vm_map_offset_t text_segment_size = text_seg->vmsize;
13907 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13908 vm_prot_t text_maxprot = text_seg->maxprot;
13909
13910 /* Unmap the first page and loadcommands and map the text segment */
13911 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13912 assert(ret == KERN_SUCCESS);
13913
13914 if (load_command_map_size) {
13915 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13916 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13917 assert(ret == KERN_SUCCESS);
13918 }
13919
13920 /* Map the text segment at actual vm addr specified in fileset */
13921 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13922 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13923 if (ret != KERN_SUCCESS) {
13924 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13925 "Failed to map Text segment of kc fileset with error %d", ret);
13926 return kOSKextReturnInvalidArgument;
13927 }
13928
13929 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13930 return 0;
13931 }
13932
13933 /*********************************************************************
13934 * Assumes sKextLock is held.
13935 *********************************************************************/
13936 /* static */
13937 OSReturn
13938 OSKext::protectKCFileSet(
13939 kernel_mach_header_t *mh,
13940 kc_kind_t type)
13941 {
13942 vm_map_t kext_map = g_kext_map;
13943 kernel_segment_command_t * seg = NULL;
13944 vm_map_offset_t start = 0;
13945 vm_map_offset_t end = 0;
13946 vm_map_size_t size = 0;
13947 OSReturn ret = 0;
13948
13949 /* Set VM permissions */
13950 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13951 while (seg) {
13952 start = round_page(seg->vmaddr);
13953 end = trunc_page(seg->vmaddr + seg->vmsize);
13954 size = end - start;
13955
13956 /*
13957 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13958 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13959 * for the Aux KC as well.
13960 */
13961 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13962 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13963 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13964 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13965 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13966 ret = OSKext_protect((kernel_mach_header_t *)mh,
13967 kext_map, start, size, seg->maxprot, TRUE, type);
13968 if (ret != KERN_SUCCESS) {
13969 printf("OSKext protect failed with error %d", ret);
13970 return kOSKextReturnInvalidArgument;
13971 }
13972
13973 ret = OSKext_protect((kernel_mach_header_t *)mh,
13974 kext_map, start, size, seg->initprot, FALSE, type);
13975 if (ret != KERN_SUCCESS) {
13976 printf("OSKext protect failed with error %d", ret);
13977 return kOSKextReturnInvalidArgument;
13978 }
13979
13980 ret = OSKext_wire((kernel_mach_header_t *)mh,
13981 kext_map, start, end, seg->initprot, FALSE, type);
13982 if (ret != KERN_SUCCESS) {
13983 printf("OSKext wire failed with error %d", ret);
13984 return kOSKextReturnInvalidArgument;
13985 }
13986 }
13987
13988 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13989 }
13990
13991 return 0;
13992 }
13993
13994 /*********************************************************************
13995 * Assumes sKextLock is held.
13996 *********************************************************************/
13997 /* static */
13998 void
13999 OSKext::freeKCFileSetcontrol(void)
14000 {
14001 PE_reset_all_kc_vp();
14002 }
14003
14004 /*********************************************************************
14005 * Assumes sKextLock is held.
14006 *
14007 * resetKCFileSetSegments: Kext start function expects data segment to
14008 * be pristine on every load, unmap the dirty segments on unload and
14009 * remap them from FileSet on disk. Remap all segments of kext since
14010 * fixups are done per kext and not per segment.
14011 *********************************************************************/
14012 OSReturn
14013 OSKext::resetKCFileSetSegments(void)
14014 {
14015 kernel_segment_command_t *seg = NULL;
14016 kernel_segment_command_t *text_seg;
14017 uint32_t text_fileoff;
14018 kernel_mach_header_t *k_mh = NULL;
14019 uintptr_t slide;
14020 struct vnode *vp = NULL;
14021 void *fileset_control = NULL;
14022 bool pageable = (kc_type == KCKindPageable);
14023 OSReturn err;
14024 kern_return_t kr;
14025
14026 /* Check the vnode reference is still available */
14027 vp = (struct vnode *)PE_get_kc_vp(kc_type);
14028 if (vp == NULL) {
14029 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
14030 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
14031 return kOSKextReturnInternalError;
14032 }
14033
14034 fileset_control = ubc_getobject(vp, 0);
14035 assert(fileset_control != NULL);
14036
14037 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
14038 "Kext %s resetting all segments", getIdentifierCString());
14039
14040 k_mh = (kernel_mach_header_t *)kmod_info->address;
14041 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
14042 text_fileoff = text_seg->fileoff;
14043 slide = PE_get_kc_slide(kc_type);
14044
14045 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
14046 while (seg) {
14047 if (seg->vmsize == 0) {
14048 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14049 continue;
14050 }
14051
14052 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
14053 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
14054 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
14055 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
14056 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14057 continue;
14058 }
14059
14060 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
14061 assert(kr == KERN_SUCCESS);
14062 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14063 }
14064
14065 /* Unmap the text segment */
14066 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
14067 assert(kr == KERN_SUCCESS);
14068
14069 /* Map all the segments of the kext */
14070 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
14071 if (err) {
14072 panic("Could not reset segments of a mapped kext, error %x", err);
14073 }
14074
14075 /* Update address in kmod_info, since it has been reset */
14076 if (kmod_info->address) {
14077 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
14078 }
14079
14080 return 0;
14081 }
14082
14083 /*********************************************************************
14084 * Mechanism to track all segment mapping while mapping KC fileset.
14085 *********************************************************************/
14086
14087 struct kcfileset_map_entry {
14088 vm_map_offset_t me_start;
14089 vm_map_offset_t me_size;
14090 };
14091
14092 struct kcfileset_map_entry_list {
14093 int kme_list_count;
14094 int kme_list_index;
14095 struct kcfileset_map_entry kme_list[];
14096 };
14097
14098 #define KCFILESET_MAP_ENTRY_MAX (16380)
14099
14100 static void *
14101 allocate_kcfileset_map_entry_list(void)
14102 {
14103 struct kcfileset_map_entry_list *entry_list;
14104
14105 entry_list = kalloc_type(struct kcfileset_map_entry_list,
14106 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
14107
14108 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
14109 entry_list->kme_list_index = 0;
14110 return entry_list;
14111 }
14112
14113 static void
14114 add_kcfileset_map_entry(
14115 void *map_entry_list,
14116 vm_map_offset_t start,
14117 vm_map_offset_t size)
14118 {
14119 if (map_entry_list == NULL) {
14120 return;
14121 }
14122
14123 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14124
14125 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
14126 panic("Ran out of map kc fileset list");
14127 }
14128
14129 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
14130 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
14131
14132 entry_list->kme_list_index++;
14133 }
14134
14135 static void
14136 deallocate_kcfileset_map_entry_list_and_unmap_entries(
14137 void *map_entry_list,
14138 boolean_t unmap_entries,
14139 bool pageable)
14140 {
14141 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14142
14143 if (unmap_entries) {
14144 for (int i = 0; i < entry_list->kme_list_index; i++) {
14145 kern_return_t ret;
14146 ret = vm_unmap_kcfileset_segment(
14147 &(entry_list->kme_list[i].me_start),
14148 entry_list->kme_list[i].me_size);
14149 assert(ret == KERN_SUCCESS);
14150 }
14151
14152 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
14153 }
14154
14155 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
14156 KCFILESET_MAP_ENTRY_MAX, entry_list);
14157 }
14158
14159 /*********************************************************************
14160 * Mechanism to map kext segment.
14161 *********************************************************************/
14162
14163 kern_return_t
14164 vm_map_kcfileset_segment(
14165 vm_map_offset_t *start,
14166 vm_map_offset_t size,
14167 void *control,
14168 vm_object_offset_t fileoffset,
14169 vm_prot_t max_prot)
14170 {
14171 vm_map_kernel_flags_t vmk_flags = {
14172 .vmf_fixed = true,
14173 .vmkf_no_copy_on_read = true,
14174 .vmkf_cs_enforcement_override = true,
14175 .vm_tag = VM_KERN_MEMORY_OSKEXT,
14176 };
14177 kern_return_t ret;
14178
14179 /* Add Write to max prot to allow fixups */
14180 max_prot = max_prot | VM_PROT_WRITE;
14181
14182 /*
14183 * Map the segments from file as COPY mappings to
14184 * make sure changes on disk to the file does not affect
14185 * mapped segments.
14186 */
14187 ret = vm_map_enter_mem_object_control(
14188 g_kext_map,
14189 start,
14190 size,
14191 (mach_vm_offset_t)0,
14192 vmk_flags,
14193 (memory_object_control_t)control,
14194 fileoffset,
14195 TRUE, /* copy */
14196 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
14197 VM_INHERIT_NONE);
14198
14199 return ret;
14200 }
14201
14202 kern_return_t
14203 vm_unmap_kcfileset_segment(
14204 vm_map_offset_t *start,
14205 vm_map_offset_t size)
14206 {
14207 return mach_vm_deallocate(g_kext_map, *start, size);
14208 }
14209
14210 #endif //(__x86_64__) || defined(__i386__)
14211
14212 /*********************************************************************
14213 * Assumes sKextLock is held.
14214 *********************************************************************/
14215 /* static */
14216 OSReturn
14217 OSKext::validateKCFileSetUUID(
14218 OSDictionary *infoDict,
14219 kc_kind_t type)
14220 {
14221 OSReturn ret = kOSReturnSuccess;
14222
14223 if (!kernelcache_uuid_valid) {
14224 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14225 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
14226 ret = kOSKextReturnInvalidArgument;
14227 goto finish;
14228 }
14229 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
14230 if (ret != 0) {
14231 goto finish;
14232 }
14233
14234 #if defined(__x86_64__) || defined(__i386__)
14235 /* Check if the Aux KC is prelinked to correct Pageable KC */
14236 if (type == KCKindAuxiliary) {
14237 if (!pageablekc_uuid_valid) {
14238 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14239 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
14240 ret = kOSKextReturnInvalidArgument;
14241 goto finish;
14242 }
14243 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
14244 if (ret != 0) {
14245 goto finish;
14246 }
14247 }
14248 #endif //(__x86_64__) || defined(__i386__)
14249
14250 printf("KextLog: Collection UUID matches with loaded KCs.\n");
14251 finish:
14252 return ret;
14253 }
14254
14255 /*********************************************************************
14256 * Assumes sKextLock is held.
14257 *********************************************************************/
14258 /* static */
14259 OSReturn
14260 OSKext::validateKCUUIDfromPrelinkInfo(
14261 uuid_t *loaded_kcuuid,
14262 kc_kind_t type,
14263 OSDictionary *infoDict,
14264 const char *uuid_key)
14265 {
14266 /* extract the UUID from the dictionary */
14267 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
14268 if (!prelinkinfoKCUUID) {
14269 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14270 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
14271 return kOSKextReturnInvalidArgument;
14272 }
14273
14274 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
14275 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14276 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
14277 return kOSKextReturnInvalidArgument;
14278 }
14279
14280 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
14281 prelinkinfoKCUUID->getLength())) {
14282 OSData *info_dict_uuid;
14283 uuid_string_t info_dict_uuid_str = {};
14284 uuid_string_t expected_uuid_str = {};
14285 uuid_string_t given_uuid_str = {};
14286 uuid_t given_uuid;
14287
14288 /* extract the KC UUID from the dictionary */
14289 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
14290 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
14291 uuid_t tmp_uuid;
14292 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
14293 uuid_unparse(tmp_uuid, info_dict_uuid_str);
14294 }
14295
14296 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
14297 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
14298 uuid_unparse(given_uuid, given_uuid_str);
14299
14300 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14301 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14302 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14303 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14304 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14305 if (type == KCKindPageable && sPanicOnKCMismatch) {
14306 panic("System KC UUID %s linked against %s, but %s is loaded",
14307 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14308 }
14309 return kOSKextReturnInvalidArgument;
14310 }
14311
14312 return 0;
14313 }
14314
14315 /*********************************************************************
14316 * Assumes sKextLock is held.
14317 *********************************************************************/
14318 /* static */
14319 OSReturn
14320 OSKext::dispatchResource(OSDictionary * requestDict)
14321 {
14322 OSReturn result = kOSReturnError;
14323 OSSharedPtr<OSDictionary> callbackRecord;
14324 OSNumber * requestTag = NULL; // do not release
14325 OSNumber * requestResult = NULL; // do not release
14326 OSData * dataObj = NULL; // do not release
14327 uint32_t dataLength = 0;
14328 const void * dataPtr = NULL; // do not free
14329 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14330 OSKextRequestResourceCallback callback = NULL;
14331 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14332 void * context = NULL; // do not free
14333 OSSharedPtr<OSKext> callbackKext;
14334
14335 /* Get the args from the request. Right now we need the tag
14336 * to look up the callback record, and the result for invoking the callback.
14337 */
14338 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14339 kKextRequestArgumentRequestTagKey));
14340 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14341 kKextRequestArgumentResultKey));
14342 if (!requestTag || !requestResult) {
14343 result = kOSKextReturnInvalidArgument;
14344 goto finish;
14345 }
14346
14347 /* Look for a callback record matching this request's tag.
14348 */
14349 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
14350 if (result != kOSReturnSuccess) {
14351 goto finish;
14352 }
14353
14354 /*****
14355 * Get the context pointer of the callback record (if there is one).
14356 */
14357 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14358 callbackRecord.get(), kKextRequestArgumentContextKey));
14359 context = _OSKextExtractPointer(contextWrapper);
14360 if (contextWrapper && !context) {
14361 goto finish;
14362 }
14363
14364 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14365 _OSKextGetRequestArgument(callbackRecord.get(),
14366 kKextRequestArgumentCallbackKey));
14367 callback = _OSKextExtractCallbackPointer(callbackWrapper);
14368 if (!callback) {
14369 goto finish;
14370 }
14371
14372 /* Check for a data obj. We might not have one and that's ok, that means
14373 * we didn't find the requested resource, and we still have to tell the
14374 * caller that via the callback.
14375 */
14376 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14377 kKextRequestArgumentValueKey));
14378 if (dataObj) {
14379 dataPtr = dataObj->getBytesNoCopy();
14380 dataLength = dataObj->getLength();
14381 }
14382
14383 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
14384 if (!callbackKext) {
14385 OSKextLog(/* kext */ NULL,
14386 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14387 "Can't invoke callback for resource request; ");
14388 goto finish;
14389 }
14390 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14391 OSKextLog(/* kext */ NULL,
14392 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14393 "Can't invoke kext resource callback; ");
14394 goto finish;
14395 }
14396
14397 (void)callback(requestTag->unsigned32BitValue(),
14398 (OSReturn)requestResult->unsigned32BitValue(),
14399 dataPtr, dataLength, context);
14400
14401 result = kOSReturnSuccess;
14402
14403 finish:
14404 return result;
14405 }
14406
14407 /*********************************************************************
14408 * Assumes sKextLock is held.
14409 *********************************************************************/
14410 /* static */
14411 OSReturn
14412 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14413 {
14414 OSSharedPtr<OSDictionary> missingIDs;
14415 OSArray *bundleIDList = NULL; // do not release
14416
14417 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14418 requestDict, kKextRequestArgumentMissingBundleIDs));
14419 if (!bundleIDList) {
14420 return kOSKextReturnInvalidArgument;
14421 }
14422
14423 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
14424 if (!missingIDs) {
14425 return kOSKextReturnNoMemory;
14426 }
14427
14428 uint32_t count, i;
14429 count = bundleIDList->getCount();
14430 for (i = 0; i < count; i++) {
14431 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14432 if (thisID) {
14433 missingIDs->setObject(thisID, kOSBooleanFalse);
14434 }
14435 }
14436
14437 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
14438
14439 return kOSReturnSuccess;
14440 }
14441
14442 /*********************************************************************
14443 * Assumes sKextLock is held.
14444 *********************************************************************/
14445 /* static */
14446 OSReturn
14447 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14448 {
14449 bool loadable = true;
14450 if (!kextIdentifier) {
14451 return kOSKextReturnInvalidArgument;
14452 }
14453
14454 if (requestDict) {
14455 OSBoolean *loadableArg;
14456 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14457 requestDict, kKextRequestArgumentBundleAvailability));
14458 /* If we find the "Bundle Available" arg, and it's false, then
14459 * mark the bundle ID as _not_ loadable
14460 */
14461 if (loadableArg && !loadableArg->getValue()) {
14462 loadable = false;
14463 }
14464 }
14465
14466 if (!sNonLoadableKextsByID) {
14467 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
14468 }
14469
14470 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
14471
14472 OSKextLog(/* kext */ NULL,
14473 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14474 "KextLog: AuxKC bundle %s marked as %s",
14475 kextIdentifier->getCStringNoCopy(),
14476 (loadable ? "loadable" : "NOT loadable"));
14477
14478 return kOSReturnSuccess;
14479 }
14480
14481 /*********************************************************************
14482 *********************************************************************/
14483 /* static */
14484 void
14485 OSKext::invokeRequestCallback(
14486 OSDictionary * callbackRecord,
14487 OSReturn callbackResult)
14488 {
14489 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
14490 OSSharedPtr<OSNumber> resultNum;
14491
14492 if (!predicate) {
14493 goto finish;
14494 }
14495
14496 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
14497 8 * sizeof(callbackResult));
14498 if (!resultNum) {
14499 goto finish;
14500 }
14501
14502 /* Insert the result into the callback record and dispatch it as if it
14503 * were the reply coming down from user space.
14504 */
14505 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
14506 resultNum.get());
14507
14508 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14509 /* This removes the pending callback record.
14510 */
14511 OSKext::dispatchResource(callbackRecord);
14512 }
14513
14514 finish:
14515 return;
14516 }
14517
14518 /*********************************************************************
14519 * Assumes sKextLock is held.
14520 *********************************************************************/
14521 /* static */
14522 OSReturn
14523 OSKext::cancelRequest(
14524 OSKextRequestTag requestTag,
14525 void ** contextOut)
14526 {
14527 OSReturn result = kOSKextReturnNoMemory;
14528 OSSharedPtr<OSDictionary> callbackRecord;
14529 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14530
14531 IORecursiveLockLock(sKextLock);
14532 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14533 callbackRecord);
14534 IORecursiveLockUnlock(sKextLock);
14535
14536 if (result == kOSReturnSuccess && contextOut) {
14537 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14538 _OSKextGetRequestArgument(callbackRecord.get(),
14539 kKextRequestArgumentContextKey));
14540 *contextOut = _OSKextExtractPointer(contextWrapper);
14541 }
14542
14543 return result;
14544 }
14545
14546 /*********************************************************************
14547 * Assumes sKextLock is held.
14548 *********************************************************************/
14549 void
14550 OSKext::invokeOrCancelRequestCallbacks(
14551 OSReturn callbackResult,
14552 bool invokeFlag)
14553 {
14554 unsigned int count, i;
14555
14556 count = sRequestCallbackRecords->getCount();
14557 if (!count) {
14558 goto finish;
14559 }
14560
14561 i = count - 1;
14562 do {
14563 OSDictionary * request = OSDynamicCast(OSDictionary,
14564 sRequestCallbackRecords->getObject(i));
14565
14566 if (!request) {
14567 continue;
14568 }
14569 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14570 _OSKextGetRequestArgument(request,
14571 kKextRequestArgumentCallbackKey));
14572
14573 if (!callbackWrapper) {
14574 sRequestCallbackRecords->removeObject(i);
14575 continue;
14576 }
14577
14578 vm_address_t callbackAddress = (vm_address_t)
14579 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14580
14581 if ((kmod_info->address <= callbackAddress) &&
14582 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14583 if (invokeFlag) {
14584 /* This removes the callback record.
14585 */
14586 invokeRequestCallback(request, callbackResult);
14587 } else {
14588 sRequestCallbackRecords->removeObject(i);
14589 }
14590 }
14591 } while (i--);
14592
14593 finish:
14594 return;
14595 }
14596
14597 /*********************************************************************
14598 * Assumes sKextLock is held.
14599 *********************************************************************/
14600 uint32_t
14601 OSKext::countRequestCallbacks(void)
14602 {
14603 uint32_t result = 0;
14604 unsigned int count, i;
14605
14606 count = sRequestCallbackRecords->getCount();
14607 if (!count) {
14608 goto finish;
14609 }
14610
14611 i = count - 1;
14612 do {
14613 OSDictionary * request = OSDynamicCast(OSDictionary,
14614 sRequestCallbackRecords->getObject(i));
14615
14616 if (!request) {
14617 continue;
14618 }
14619 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14620 _OSKextGetRequestArgument(request,
14621 kKextRequestArgumentCallbackKey));
14622
14623 if (!callbackWrapper) {
14624 continue;
14625 }
14626
14627 vm_address_t callbackAddress = (vm_address_t)
14628 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14629
14630 if ((kmod_info->address <= callbackAddress) &&
14631 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14632 result++;
14633 }
14634 } while (i--);
14635
14636 finish:
14637 return result;
14638 }
14639
14640 /*********************************************************************
14641 *********************************************************************/
14642 static OSReturn
14643 _OSKextCreateRequest(
14644 const char * predicate,
14645 OSSharedPtr<OSDictionary> & requestR)
14646 {
14647 OSReturn result = kOSKextReturnNoMemory;
14648 OSSharedPtr<OSDictionary> request;
14649
14650 request = OSDictionary::withCapacity(2);
14651 if (!request) {
14652 goto finish;
14653 }
14654 result = _OSDictionarySetCStringValue(request.get(),
14655 kKextRequestPredicateKey, predicate);
14656 if (result != kOSReturnSuccess) {
14657 goto finish;
14658 }
14659 result = kOSReturnSuccess;
14660
14661 finish:
14662 if (result == kOSReturnSuccess) {
14663 requestR = os::move(request);
14664 }
14665
14666 return result;
14667 }
14668
14669 /*********************************************************************
14670 *********************************************************************/
14671 static OSString *
14672 _OSKextGetRequestPredicate(OSDictionary * requestDict)
14673 {
14674 return OSDynamicCast(OSString,
14675 requestDict->getObject(kKextRequestPredicateKey));
14676 }
14677
14678 /*********************************************************************
14679 *********************************************************************/
14680 static OSObject *
14681 _OSKextGetRequestArgument(
14682 OSDictionary * requestDict,
14683 const char * argName)
14684 {
14685 OSDictionary * args = OSDynamicCast(OSDictionary,
14686 requestDict->getObject(kKextRequestArgumentsKey));
14687 if (args) {
14688 return args->getObject(argName);
14689 }
14690 return NULL;
14691 }
14692
14693 /*********************************************************************
14694 *********************************************************************/
14695 static bool
14696 _OSKextSetRequestArgument(
14697 OSDictionary * requestDict,
14698 const char * argName,
14699 OSMetaClassBase * value)
14700 {
14701 OSDictionary * args = OSDynamicCast(OSDictionary,
14702 requestDict->getObject(kKextRequestArgumentsKey));
14703 OSSharedPtr<OSDictionary> newArgs;
14704 if (!args) {
14705 newArgs = OSDictionary::withCapacity(2);
14706 args = newArgs.get();
14707 if (!args) {
14708 goto finish;
14709 }
14710 requestDict->setObject(kKextRequestArgumentsKey, args);
14711 }
14712 if (args) {
14713 return args->setObject(argName, value);
14714 }
14715 finish:
14716 return false;
14717 }
14718
14719 /*********************************************************************
14720 *********************************************************************/
14721 template <typename T>
14722 static T *
14723 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
14724 {
14725 if (!wrapper) {
14726 return nullptr;
14727 }
14728 return wrapper->getRef();
14729 }
14730
14731 /*********************************************************************
14732 *********************************************************************/
14733 static OSKextRequestResourceCallback
14734 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14735 {
14736 if (!wrapper) {
14737 return nullptr;
14738 }
14739 return wrapper->getRef();
14740 }
14741
14742
14743 /*********************************************************************
14744 *********************************************************************/
14745 static OSReturn
14746 _OSDictionarySetCStringValue(
14747 OSDictionary * dict,
14748 const char * cKey,
14749 const char * cValue)
14750 {
14751 OSReturn result = kOSKextReturnNoMemory;
14752 OSSharedPtr<const OSSymbol> key;
14753 OSSharedPtr<OSString> value;
14754
14755 key = OSSymbol::withCString(cKey);
14756 value = OSString::withCString(cValue);
14757 if (!key || !value) {
14758 goto finish;
14759 }
14760 if (dict->setObject(key.get(), value.get())) {
14761 result = kOSReturnSuccess;
14762 }
14763
14764 finish:
14765 return result;
14766 }
14767
14768 /*********************************************************************
14769 *********************************************************************/
14770 static bool
14771 _OSArrayContainsCString(
14772 OSArray * array,
14773 const char * cString)
14774 {
14775 bool result = false;
14776 OSSharedPtr<const OSSymbol> symbol;
14777 uint32_t count, i;
14778
14779 if (!array || !cString) {
14780 goto finish;
14781 }
14782
14783 symbol = OSSymbol::withCStringNoCopy(cString);
14784 if (!symbol) {
14785 goto finish;
14786 }
14787
14788 count = array->getCount();
14789 for (i = 0; i < count; i++) {
14790 OSObject * thisObject = array->getObject(i);
14791 if (symbol->isEqualTo(thisObject)) {
14792 result = true;
14793 goto finish;
14794 }
14795 }
14796
14797 finish:
14798 return result;
14799 }
14800
14801 #if CONFIG_KXLD
14802 /*********************************************************************
14803 * We really only care about boot / system start up related kexts.
14804 * We return true if we're less than REBUILD_MAX_TIME since start up,
14805 * otherwise return false.
14806 *********************************************************************/
14807 bool
14808 _OSKextInPrelinkRebuildWindow(void)
14809 {
14810 static bool outside_the_window = false;
14811 AbsoluteTime my_abstime;
14812 UInt64 my_ns;
14813 SInt32 my_secs;
14814
14815 if (outside_the_window) {
14816 return false;
14817 }
14818 clock_get_uptime(&my_abstime);
14819 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14820 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14821 if (my_secs > REBUILD_MAX_TIME) {
14822 outside_the_window = true;
14823 return false;
14824 }
14825 return true;
14826 }
14827 #endif /* CONFIG_KXLD */
14828
14829 /*********************************************************************
14830 *********************************************************************/
14831 bool
14832 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14833 {
14834 int unLoadedCount, i;
14835 bool result = false;
14836
14837 IORecursiveLockLock(sKextLock);
14838
14839 if (sUnloadedPrelinkedKexts == NULL) {
14840 goto finish;
14841 }
14842 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14843 if (unLoadedCount == 0) {
14844 goto finish;
14845 }
14846
14847 for (i = 0; i < unLoadedCount; i++) {
14848 const OSSymbol * myBundleID; // do not release
14849
14850 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14851 if (!myBundleID) {
14852 continue;
14853 }
14854 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
14855 result = true;
14856 break;
14857 }
14858 }
14859 finish:
14860 IORecursiveLockUnlock(sKextLock);
14861 return result;
14862 }
14863
14864 #if PRAGMA_MARK
14865 #pragma mark Personalities (IOKit Drivers)
14866 #endif
14867 /*********************************************************************
14868 *********************************************************************/
14869 /* static */
14870 OSSharedPtr<OSArray>
14871 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14872 {
14873 OSSharedPtr<OSArray> result;
14874 OSSharedPtr<OSCollectionIterator> kextIterator;
14875 OSSharedPtr<OSArray> personalities;
14876
14877 OSString * kextID = NULL; // do not release
14878 OSKext * theKext = NULL; // do not release
14879
14880 IORecursiveLockLock(sKextLock);
14881
14882 /* Let's conservatively guess that any given kext has around 3
14883 * personalities for now.
14884 */
14885 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
14886 if (!result) {
14887 goto finish;
14888 }
14889
14890 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
14891 if (!kextIterator) {
14892 goto finish;
14893 }
14894
14895 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14896 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14897 if (theKext->flags.requireExplicitLoad) {
14898 OSKextLog(theKext,
14899 kOSKextLogDebugLevel |
14900 kOSKextLogLoadFlag,
14901 "Kext %s requires an explicit kextload; "
14902 "omitting its personalities.",
14903 theKext->getIdentifierCString());
14904 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14905 personalities = theKext->copyPersonalitiesArray();
14906 if (!personalities) {
14907 continue;
14908 }
14909 result->merge(personalities.get());
14910 } else {
14911 // xxx - check for better place to put this log msg
14912 OSKextLog(theKext,
14913 kOSKextLogWarningLevel |
14914 kOSKextLogLoadFlag,
14915 "Kext %s is not loadable during safe boot; "
14916 "omitting its personalities.",
14917 theKext->getIdentifierCString());
14918 }
14919 }
14920
14921 finish:
14922 IORecursiveLockUnlock(sKextLock);
14923
14924 return result;
14925 }
14926
14927 /*********************************************************************
14928 *********************************************************************/
14929 /* static */
14930 void
14931 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14932 {
14933 int numPersonalities = 0;
14934
14935 OSKextLog(/* kext */ NULL,
14936 kOSKextLogStepLevel |
14937 kOSKextLogLoadFlag,
14938 "Sending all eligible registered kexts' personalities "
14939 "to the IOCatalogue %s.",
14940 startMatching ? "and starting matching" : "but not starting matching");
14941
14942 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14943 /* filterSafeBootFlag */ true);
14944
14945 if (personalities) {
14946 gIOCatalogue->addDrivers(personalities.get(), startMatching);
14947 numPersonalities = personalities->getCount();
14948 }
14949
14950 OSKextLog(/* kext */ NULL,
14951 kOSKextLogStepLevel |
14952 kOSKextLogLoadFlag,
14953 "%d kext personalit%s sent to the IOCatalogue; %s.",
14954 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14955 startMatching ? "matching started" : "matching not started");
14956 return;
14957 }
14958
14959 /*********************************************************************
14960 * Do not make a deep copy, just convert the IOKitPersonalities dict
14961 * to an array for sending to the IOCatalogue.
14962 *********************************************************************/
14963 OSSharedPtr<OSArray>
14964 OSKext::copyPersonalitiesArray(void)
14965 {
14966 OSSharedPtr<OSArray> result;
14967 OSDictionary * personalities = NULL; // do not release
14968 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14969
14970 OSString * personalityName = NULL; // do not release
14971 OSString * personalityBundleIdentifier = NULL; // do not release
14972
14973 personalities = OSDynamicCast(OSDictionary,
14974 getPropertyForHostArch(kIOKitPersonalitiesKey));
14975 if (!personalities) {
14976 goto finish;
14977 }
14978
14979 result = OSArray::withCapacity(personalities->getCount());
14980 if (!result) {
14981 goto finish;
14982 }
14983
14984 personalitiesIterator =
14985 OSCollectionIterator::withCollection(personalities);
14986 if (!personalitiesIterator) {
14987 goto finish;
14988 }
14989 while ((personalityName = OSDynamicCast(OSString,
14990 personalitiesIterator->getNextObject()))) {
14991 OSDictionary * personality = OSDynamicCast(OSDictionary,
14992 personalities->getObject(personalityName));
14993
14994 if (personality) {
14995 /******
14996 * If the personality doesn't have a CFBundleIdentifier, or if it
14997 * differs from the kext's, insert the kext's ID so we can find it.
14998 * The publisher ID is used to remove personalities from bundles
14999 * correctly.
15000 */
15001 personalityBundleIdentifier = OSDynamicCast(OSString,
15002 personality->getObject(kCFBundleIdentifierKey));
15003
15004 if (!personalityBundleIdentifier) {
15005 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
15006 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
15007 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
15008 }
15009 }
15010
15011 result->setObject(personality);
15012 }
15013
15014 finish:
15015 return result;
15016 }
15017
15018 /*********************************************************************
15019 * Might want to change this to a bool return?
15020 *********************************************************************/
15021 OSReturn
15022 OSKext::sendPersonalitiesToCatalog(
15023 bool startMatching,
15024 OSArray * personalityNames)
15025 {
15026 OSReturn result = kOSReturnSuccess;
15027 OSSharedPtr<OSArray> personalitiesToSend;
15028 OSDictionary * kextPersonalities = NULL; // do not release
15029 int count, i;
15030
15031 if (!sLoadEnabled) {
15032 OSKextLog(this,
15033 kOSKextLogErrorLevel |
15034 kOSKextLogLoadFlag,
15035 "Kext loading is disabled (attempt to start matching for kext %s).",
15036 getIdentifierCString());
15037 result = kOSKextReturnDisabled;
15038 goto finish;
15039 }
15040
15041 if (sSafeBoot && !isLoadableInSafeBoot()) {
15042 OSKextLog(this,
15043 kOSKextLogErrorLevel |
15044 kOSKextLogLoadFlag,
15045 "Kext %s is not loadable during safe boot; "
15046 "not sending personalities to the IOCatalogue.",
15047 getIdentifierCString());
15048 result = kOSKextReturnNotLoadable;
15049 goto finish;
15050 }
15051
15052 if (!personalityNames || !personalityNames->getCount()) {
15053 personalitiesToSend = copyPersonalitiesArray();
15054 } else {
15055 kextPersonalities = OSDynamicCast(OSDictionary,
15056 getPropertyForHostArch(kIOKitPersonalitiesKey));
15057 if (!kextPersonalities || !kextPersonalities->getCount()) {
15058 // not an error
15059 goto finish;
15060 }
15061 personalitiesToSend = OSArray::withCapacity(0);
15062 if (!personalitiesToSend) {
15063 result = kOSKextReturnNoMemory;
15064 goto finish;
15065 }
15066 count = personalityNames->getCount();
15067 for (i = 0; i < count; i++) {
15068 OSString * name = OSDynamicCast(OSString,
15069 personalityNames->getObject(i));
15070 if (!name) {
15071 continue;
15072 }
15073 OSDictionary * personality = OSDynamicCast(OSDictionary,
15074 kextPersonalities->getObject(name));
15075 if (personality) {
15076 personalitiesToSend->setObject(personality);
15077 }
15078 }
15079 }
15080 if (personalitiesToSend) {
15081 unsigned numPersonalities = personalitiesToSend->getCount();
15082 OSKextLog(this,
15083 kOSKextLogStepLevel |
15084 kOSKextLogLoadFlag,
15085 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
15086 getIdentifierCString(),
15087 numPersonalities,
15088 numPersonalities > 1 ? "ies" : "y",
15089 startMatching ? " and starting matching" : " but not starting matching");
15090 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
15091 }
15092 finish:
15093 return result;
15094 }
15095
15096 /*********************************************************************
15097 * xxx - We should allow removing the kext's declared personalities,
15098 * xxx - even with other bundle identifiers.
15099 *********************************************************************/
15100 void
15101 OSKext::removePersonalitiesFromCatalog(void)
15102 {
15103 OSSharedPtr<OSDictionary> personality;
15104
15105 personality = OSDictionary::withCapacity(1);
15106 if (!personality) {
15107 goto finish;
15108 }
15109 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
15110
15111 OSKextLog(this,
15112 kOSKextLogStepLevel |
15113 kOSKextLogLoadFlag,
15114 "Kext %s removing all personalities naming it from the IOCatalogue.",
15115 getIdentifierCString());
15116
15117 /* Have the IOCatalog remove all personalities matching this kext's
15118 * bundle ID and trigger matching anew.
15119 */
15120 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
15121
15122 finish:
15123 return;
15124 }
15125
15126 void
15127 OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
15128 {
15129 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
15130 return;
15131 }
15132
15133 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(1);
15134 if (!personalityToRemove) {
15135 return;
15136 }
15137
15138 /*
15139 * Create a personality dictionary with just the bundleID.
15140 * We will remove any personality that has a matching bundleID,
15141 * irrespective of which other keys are present on the dictionary.
15142 */
15143 personalityToRemove->setObject(kCFBundleIdentifierKey, getIdentifier());
15144 gIOCatalogue->exchangeDrivers(personalityToRemove.get(), upgradedPersonalities, true);
15145 }
15146
15147 #if PRAGMA_MARK
15148 #pragma mark Logging
15149 #endif
15150 /*********************************************************************
15151 * Do not call any function that takes sKextLock here!
15152 *********************************************************************/
15153 /* static */
15154 OSKextLogSpec
15155 OSKext::setUserSpaceLogFilter(
15156 OSKextLogSpec newUserLogFilter,
15157 bool captureFlag)
15158 {
15159 OSKextLogSpec result;
15160 bool allocError = false;
15161
15162 /* Do not call any function that takes sKextLoggingLock during
15163 * this critical block. That means do logging after.
15164 */
15165 IOLockLock(sKextLoggingLock);
15166
15167 result = sUserSpaceKextLogFilter;
15168 sUserSpaceKextLogFilter = newUserLogFilter;
15169
15170 if (newUserLogFilter && captureFlag &&
15171 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
15172 // xxx - do some measurements for a good initial capacity?
15173 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
15174 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
15175
15176 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
15177 allocError = true;
15178 }
15179 }
15180
15181 IOLockUnlock(sKextLoggingLock);
15182
15183 /* If the config flag itself is changing, log the state change
15184 * going both ways, before setting up the user-space log arrays,
15185 * so that this is only logged in the kernel.
15186 */
15187 if (result != newUserLogFilter) {
15188 OSKextLog(/* kext */ NULL,
15189 kOSKextLogDebugLevel |
15190 kOSKextLogGeneralFlag,
15191 "User-space log flags changed from 0x%x to 0x%x.",
15192 result, newUserLogFilter);
15193 }
15194 if (allocError) {
15195 OSKextLog(/* kext */ NULL,
15196 kOSKextLogErrorLevel |
15197 kOSKextLogGeneralFlag,
15198 "Failed to allocate user-space log message arrays.");
15199 }
15200
15201 return result;
15202 }
15203
15204 /*********************************************************************
15205 * Do not call any function that takes sKextLock here!
15206 *********************************************************************/
15207 /* static */
15208 OSSharedPtr<OSArray>
15209 OSKext::clearUserSpaceLogFilter(void)
15210 {
15211 OSSharedPtr<OSArray> result;
15212 OSKextLogSpec oldLogFilter;
15213 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
15214
15215 /* Do not call any function that takes sKextLoggingLock during
15216 * this critical block. That means do logging after.
15217 */
15218 IOLockLock(sKextLoggingLock);
15219
15220 result = OSArray::withCapacity(2);
15221 if (result) {
15222 result->setObject(sUserSpaceLogSpecArray.get());
15223 result->setObject(sUserSpaceLogMessageArray.get());
15224 }
15225 sUserSpaceLogSpecArray.reset();
15226 sUserSpaceLogMessageArray.reset();
15227
15228 oldLogFilter = sUserSpaceKextLogFilter;
15229 sUserSpaceKextLogFilter = newLogFilter;
15230
15231 IOLockUnlock(sKextLoggingLock);
15232
15233 /* If the config flag itself is changing, log the state change
15234 * going both ways, after tearing down the user-space log
15235 * arrays, so this is only logged within the kernel.
15236 */
15237 if (oldLogFilter != newLogFilter) {
15238 OSKextLog(/* kext */ NULL,
15239 kOSKextLogDebugLevel |
15240 kOSKextLogGeneralFlag,
15241 "User-space log flags changed from 0x%x to 0x%x.",
15242 oldLogFilter, newLogFilter);
15243 }
15244
15245 return result;
15246 }
15247
15248
15249 /*********************************************************************
15250 * Do not call any function that takes sKextLock here!
15251 *********************************************************************/
15252 /* static */
15253 OSKextLogSpec
15254 OSKext::getUserSpaceLogFilter(void)
15255 {
15256 OSKextLogSpec result;
15257
15258 IOLockLock(sKextLoggingLock);
15259 result = sUserSpaceKextLogFilter;
15260 IOLockUnlock(sKextLoggingLock);
15261
15262 return result;
15263 }
15264
15265 /*********************************************************************
15266 * This function is called by OSMetaClass during kernel C++ setup.
15267 * Be careful what you access here; assume only OSKext::initialize()
15268 * has been called.
15269 *
15270 * Do not call any function that takes sKextLock here!
15271 *********************************************************************/
15272 #define VTRESET "\033[0m"
15273
15274 #define VTBOLD "\033[1m"
15275 #define VTUNDER "\033[4m"
15276
15277 #define VTRED "\033[31m"
15278 #define VTGREEN "\033[32m"
15279 #define VTYELLOW "\033[33m"
15280 #define VTBLUE "\033[34m"
15281 #define VTMAGENTA "\033[35m"
15282 #define VTCYAN "\033[36m"
15283
15284 inline const char *
15285 colorForFlags(OSKextLogSpec flags)
15286 {
15287 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
15288
15289 switch (logLevel) {
15290 case kOSKextLogErrorLevel:
15291 return VTRED VTBOLD;
15292 case kOSKextLogWarningLevel:
15293 return VTRED;
15294 case kOSKextLogBasicLevel:
15295 return VTYELLOW VTUNDER;
15296 case kOSKextLogProgressLevel:
15297 return VTYELLOW;
15298 case kOSKextLogStepLevel:
15299 return VTGREEN;
15300 case kOSKextLogDetailLevel:
15301 return VTCYAN;
15302 case kOSKextLogDebugLevel:
15303 return VTMAGENTA;
15304 default:
15305 return ""; // white
15306 }
15307 }
15308
15309 inline bool
15310 logSpecMatch(
15311 OSKextLogSpec msgLogSpec,
15312 OSKextLogSpec logFilter)
15313 {
15314 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15315 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15316 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15317
15318 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15319 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15320 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15321
15322 /* Explicit messages always get logged.
15323 */
15324 if (msgLevel == kOSKextLogExplicitLevel) {
15325 return true;
15326 }
15327
15328 /* Warnings and errors are logged regardless of the flags.
15329 */
15330 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15331 return true;
15332 }
15333
15334 /* A verbose message that isn't for a logging-enabled kext and isn't global
15335 * does *not* get logged.
15336 */
15337 if (!msgKextGlobal && !filterKextGlobal) {
15338 return false;
15339 }
15340
15341 /* Warnings and errors are logged regardless of the flags.
15342 * All other messages must fit the flags and
15343 * have a level at or below the filter.
15344 *
15345 */
15346 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15347 return true;
15348 }
15349 return false;
15350 }
15351
15352 extern "C" {
15353 void
15354 OSKextLog(
15355 OSKext * aKext,
15356 OSKextLogSpec msgLogSpec,
15357 const char * format, ...)
15358 {
15359 va_list argList;
15360
15361 va_start(argList, format);
15362 OSKextVLog(aKext, msgLogSpec, format, argList);
15363 va_end(argList);
15364 }
15365
15366 void
15367 OSKextVLog(
15368 OSKext * aKext,
15369 OSKextLogSpec msgLogSpec,
15370 const char * format,
15371 va_list srcArgList)
15372 {
15373 bool logForKernel = false;
15374 bool logForUser = false;
15375 va_list argList;
15376 char stackBuffer[120];
15377 uint32_t length = 0;
15378 char * allocBuffer = NULL; // must kfree
15379 OSSharedPtr<OSNumber> logSpecNum;
15380 OSSharedPtr<OSString> logString;
15381 char * buffer = stackBuffer; // do not free
15382
15383 IOLockLock(sKextLoggingLock);
15384
15385 /* Set the kext/global bit in the message spec if we have no
15386 * kext or if the kext requests logging.
15387 */
15388 if (!aKext || aKext->flags.loggingEnabled) {
15389 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15390 }
15391
15392 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
15393 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15394 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
15395 }
15396
15397 if (!(logForKernel || logForUser)) {
15398 goto finish;
15399 }
15400
15401 /* No goto from here until past va_end()!
15402 */
15403 va_copy(argList, srcArgList);
15404 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15405 va_end(argList);
15406
15407 if (length + 1 >= sizeof(stackBuffer)) {
15408 allocBuffer = (char *)kalloc_data_tag(length + 1,
15409 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15410 if (!allocBuffer) {
15411 goto finish;
15412 }
15413
15414 /* No goto from here until past va_end()!
15415 */
15416 va_copy(argList, srcArgList);
15417 vsnprintf(allocBuffer, length + 1, format, argList);
15418 va_end(argList);
15419
15420 buffer = allocBuffer;
15421 }
15422
15423 /* If user space wants the log message, queue it up.
15424 */
15425 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15426 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
15427 logString = OSString::withCString(buffer);
15428 if (logSpecNum && logString) {
15429 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15430 sUserSpaceLogMessageArray->setObject(logString.get());
15431 }
15432 }
15433
15434 /* Always log messages from the kernel according to the kernel's
15435 * log flags.
15436 */
15437 if (logForKernel) {
15438 /* If we are in console mode and have a custom log filter,
15439 * colorize the log message.
15440 */
15441 if (sBootArgLogFilterFound) {
15442 const char * color = ""; // do not free
15443 color = colorForFlags(msgLogSpec);
15444 printf("%s%s%s\n", colorForFlags(msgLogSpec),
15445 buffer, color[0] ? VTRESET : "");
15446 } else {
15447 printf("%s\n", buffer);
15448 }
15449 }
15450
15451 finish:
15452 IOLockUnlock(sKextLoggingLock);
15453
15454 if (allocBuffer) {
15455 kfree_data(allocBuffer, length + 1);
15456 }
15457 return;
15458 }
15459
15460 #if KASLR_IOREG_DEBUG
15461
15462 #define IOLOG_INDENT( the_indention ) \
15463 { \
15464 int i; \
15465 for ( i = 0; i < (the_indention); i++ ) { \
15466 IOLog(" "); \
15467 } \
15468 }
15469
15470 extern vm_offset_t vm_kernel_stext;
15471 extern vm_offset_t vm_kernel_etext;
15472 extern mach_vm_offset_t kext_alloc_base;
15473 extern mach_vm_offset_t kext_alloc_max;
15474
15475 bool ScanForAddrInObject(OSObject * theObject,
15476 int indent );
15477
15478 bool
15479 ScanForAddrInObject(OSObject * theObject,
15480 int indent)
15481 {
15482 const OSMetaClass * myTypeID;
15483 OSSharedPtr<OSCollectionIterator> myIter;
15484 OSSymbol * myKey;
15485 OSObject * myValue;
15486 bool myResult = false;
15487
15488 if (theObject == NULL) {
15489 IOLog("%s: theObject is NULL \n",
15490 __FUNCTION__);
15491 return myResult;
15492 }
15493
15494 myTypeID = OSTypeIDInst(theObject);
15495
15496 if (myTypeID == OSTypeID(OSDictionary)) {
15497 OSDictionary * myDictionary;
15498
15499 myDictionary = OSDynamicCast(OSDictionary, theObject);
15500 myIter = OSCollectionIterator::withCollection( myDictionary );
15501 if (myIter == NULL) {
15502 return myResult;
15503 }
15504
15505 // !! reset the iterator
15506 myIter->reset();
15507
15508 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15509 bool myTempResult;
15510
15511 myValue = myDictionary->getObject(myKey);
15512 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15513 if (myTempResult) {
15514 // if we ever get a true result return true
15515 myResult = true;
15516 IOLOG_INDENT(indent);
15517 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15518 }
15519 }
15520
15521 // !! release the iterator
15522 myIter.reset();
15523 } else if (myTypeID == OSTypeID(OSArray)) {
15524 OSArray * myArray;
15525
15526 myArray = OSDynamicCast(OSArray, theObject);
15527 myIter = OSCollectionIterator::withCollection(myArray);
15528 if (myIter == NULL) {
15529 return myResult;
15530 }
15531 // !! reset the iterator
15532 myIter->reset();
15533
15534 while ((myValue = myIter->getNextObject())) {
15535 bool myTempResult;
15536 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15537 if (myTempResult) {
15538 // if we ever get a true result return true
15539 myResult = true;
15540 IOLOG_INDENT(indent);
15541 IOLog("OSArray: \n");
15542 }
15543 }
15544 // !! release the iterator
15545 myIter.reset();
15546 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15547 // should we look for addresses in strings?
15548 } else if (myTypeID == OSTypeID(OSData)) {
15549 void * * myPtrPtr;
15550 unsigned int myLen;
15551 OSData * myDataObj;
15552
15553 myDataObj = OSDynamicCast(OSData, theObject);
15554 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15555 myLen = myDataObj->getLength();
15556
15557 if (myPtrPtr && myLen && myLen > 7) {
15558 int i;
15559 int myPtrCount = (myLen / sizeof(void *));
15560
15561 for (i = 0; i < myPtrCount; i++) {
15562 UInt64 numberValue = (UInt64) * (myPtrPtr);
15563
15564 if (kext_alloc_max != 0 &&
15565 numberValue >= kext_alloc_base &&
15566 numberValue < kext_alloc_max) {
15567 OSSharedPtr<OSKext> myKext;
15568 // IOLog("found OSData %p in kext map %p to %p \n",
15569 // *(myPtrPtr),
15570 // (void *) kext_alloc_base,
15571 // (void *) kext_alloc_max);
15572
15573 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15574 if (myKext) {
15575 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15576 *(myPtrPtr),
15577 myKext->getIdentifierCString());
15578 }
15579 myResult = true;
15580 }
15581 if (vm_kernel_etext != 0 &&
15582 numberValue >= vm_kernel_stext &&
15583 numberValue < vm_kernel_etext) {
15584 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15585 *(myPtrPtr),
15586 (void *) vm_kernel_stext,
15587 (void *) vm_kernel_etext);
15588 myResult = true;
15589 }
15590 myPtrPtr++;
15591 }
15592 }
15593 } else if (myTypeID == OSTypeID(OSBoolean)) {
15594 // do nothing here...
15595 } else if (myTypeID == OSTypeID(OSNumber)) {
15596 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15597
15598 UInt64 numberValue = number->unsigned64BitValue();
15599
15600 if (kext_alloc_max != 0 &&
15601 numberValue >= kext_alloc_base &&
15602 numberValue < kext_alloc_max) {
15603 OSSharedPtr<OSKext> myKext;
15604 IOLog("found OSNumber in kext map %p to %p \n",
15605 (void *) kext_alloc_base,
15606 (void *) kext_alloc_max);
15607 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15608
15609 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15610 if (myKext) {
15611 IOLog("found in kext \"%s\" \n",
15612 myKext->getIdentifierCString());
15613 }
15614
15615 myResult = true;
15616 }
15617 if (vm_kernel_etext != 0 &&
15618 numberValue >= vm_kernel_stext &&
15619 numberValue < vm_kernel_etext) {
15620 IOLog("found OSNumber in kernel text segment %p to %p \n",
15621 (void *) vm_kernel_stext,
15622 (void *) vm_kernel_etext);
15623 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15624 myResult = true;
15625 }
15626 }
15627 #if 0
15628 else {
15629 const OSMetaClass* myMetaClass = NULL;
15630
15631 myMetaClass = theObject->getMetaClass();
15632 if (myMetaClass) {
15633 IOLog("class %s \n", myMetaClass->getClassName());
15634 } else {
15635 IOLog("Unknown object \n" );
15636 }
15637 }
15638 #endif
15639
15640 return myResult;
15641 }
15642 #endif // KASLR_KEXT_DEBUG
15643 }; /* extern "C" */
15644
15645 #if PRAGMA_MARK
15646 #pragma mark Backtrace Dump & kmod_get_info() support
15647 #endif
15648 /*********************************************************************
15649 * This function must be safe to call in panic context.
15650 *********************************************************************/
15651 /* static */
15652 void
15653 OSKext::printKextsInBacktrace(
15654 vm_offset_t * addr __unused,
15655 unsigned int cnt __unused,
15656 int (* printf_func)(const char *fmt, ...) __unused,
15657 uint32_t flags __unused)
15658 {
15659 addr64_t summary_page = 0;
15660 addr64_t last_summary_page = 0;
15661
15662 if (kPrintKextsLock & flags) {
15663 if (!sKextSummariesLock) {
15664 return;
15665 }
15666 IOLockLock(sKextSummariesLock);
15667 }
15668
15669 if (!gLoadedKextSummaries) {
15670 (*printf_func)(" can't perform kext scan: no kext summary");
15671 goto finish;
15672 }
15673
15674 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15675 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
15676 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15677 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
15678 (*printf_func)(" can't perform kext scan: "
15679 "missing kext summary page %p", summary_page);
15680 goto finish;
15681 }
15682 }
15683
15684 foreachKextInBacktrace(addr, cnt, 0, ^(OSKextLoadedKextSummary *summary, uint32_t index) {
15685 if (index == 0 && !(kPrintKextsTerse & flags)) {
15686 (*printf_func)(" Kernel Extensions in backtrace:\n");
15687 }
15688
15689 printSummary(summary, printf_func, flags);
15690 });
15691
15692 finish:
15693 if (kPrintKextsLock & flags) {
15694 IOLockUnlock(sKextSummariesLock);
15695 }
15696
15697 return;
15698 }
15699
15700 void
15701 OSKext::foreachKextInBacktrace(
15702 vm_offset_t * addr,
15703 uint32_t cnt,
15704 uint32_t flags,
15705 void (^ handler)(OSKextLoadedKextSummary *summary, uint32_t index))
15706 {
15707 uint32_t n = 0;
15708
15709 if (kPrintKextsLock & flags) {
15710 if (!sKextSummariesLock) {
15711 return;
15712 }
15713 IOLockLock(sKextSummariesLock);
15714 }
15715
15716 for (uint32_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15717 OSKextLoadedKextSummary * summary;
15718
15719 summary = gLoadedKextSummaries->summaries + i;
15720 if (!summary->address) {
15721 continue;
15722 }
15723
15724 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15725 continue;
15726 }
15727
15728 handler(summary, n++);
15729 }
15730
15731 if (kPrintKextsLock & flags) {
15732 IOLockUnlock(sKextSummariesLock);
15733 }
15734 }
15735
15736 /*********************************************************************
15737 * This function must be safe to call in panic context.
15738 *********************************************************************/
15739 /* static */
15740 boolean_t
15741 OSKext::summaryIsInBacktrace(
15742 OSKextLoadedKextSummary * summary,
15743 vm_offset_t * addr,
15744 unsigned int cnt)
15745 {
15746 u_int i = 0;
15747
15748 for (i = 0; i < cnt; i++) {
15749 vm_offset_t kscan_addr = addr[i];
15750 #if __has_feature(ptrauth_calls)
15751 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15752 #endif /* __has_feature(ptrauth_calls) */
15753 if ((kscan_addr >= summary->text_exec_address) &&
15754 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15755 return TRUE;
15756 }
15757 }
15758
15759 return FALSE;
15760 }
15761
15762 /*
15763 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15764 * sKextSummariesLock held.
15765 */
15766 OSKextLoadedKextSummary *
15767 OSKext::summaryForAddress(uintptr_t addr)
15768 {
15769 #if __has_feature(ptrauth_calls)
15770 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15771 #endif /* __has_feature(ptrauth_calls) */
15772 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15773 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15774 if (!summary->address) {
15775 continue;
15776 }
15777
15778 #if VM_MAPPED_KEXTS
15779 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15780 * support split kexts, but we also may unmap the kexts, which can
15781 * race with the above codepath (see OSKext::unload). As such,
15782 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15783 */
15784 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15785 return summary;
15786 }
15787 #else
15788 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15789 kernel_segment_command_t *seg;
15790
15791 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
15792 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15793 return summary;
15794 }
15795 }
15796 #endif
15797 }
15798
15799 /* addr did not map to any kext */
15800 return NULL;
15801 }
15802
15803 /* static */
15804 void *
15805 OSKext::kextForAddress(const void *address)
15806 {
15807 OSKextActiveAccount * active;
15808 OSKext * kext = NULL;
15809 uint32_t baseIdx;
15810 uint32_t lim;
15811 uintptr_t addr = (uintptr_t) address;
15812 size_t i;
15813
15814 if (!addr) {
15815 return NULL;
15816 }
15817 #if __has_feature(ptrauth_calls)
15818 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15819 #endif /* __has_feature(ptrauth_calls) */
15820
15821 if (sKextAccountsCount) {
15822 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
15823 // bsearch sKextAccounts list
15824 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15825 active = &sKextAccounts[baseIdx + (lim >> 1)];
15826 if ((addr >= active->address) && (addr < active->address_end)) {
15827 if (active->account &&
15828 (kext = active->account->kext) &&
15829 kext->kmod_info) {
15830 lck_ticket_unlock(sKextAccountsLock);
15831 return (void *)kext->kmod_info->address;
15832 }
15833 break;
15834 } else if (addr > active->address) {
15835 // move right
15836 baseIdx += (lim >> 1) + 1;
15837 lim--;
15838 }
15839 // else move left
15840 }
15841 lck_ticket_unlock(sKextAccountsLock);
15842 }
15843 if (kernel_text_contains(addr)) {
15844 return (void *)&_mh_execute_header;
15845 }
15846 if (gLoadedKextSummaries) {
15847 IOLockLock(sKextSummariesLock);
15848 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15849 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15850 if (addr >= summary->address && addr < summary->address + summary->size) {
15851 void *kextAddress = (void *)summary->address;
15852 IOLockUnlock(sKextSummariesLock);
15853 return kextAddress;
15854 }
15855 }
15856 IOLockUnlock(sKextSummariesLock);
15857 }
15858
15859 return NULL;
15860 }
15861
15862 /* static */
15863 kern_return_t
15864 OSKext::summaryForAddressExt(
15865 const void * address,
15866 OSKextLoadedKextSummary * summary)
15867 {
15868 kern_return_t result = KERN_FAILURE;
15869 const OSKextLoadedKextSummary * foundSummary = NULL;
15870
15871 /*
15872 * This needs to be safe to call even before the lock has been initialized
15873 * in OSKext::initialize(), as we might get here from the ksancov runtime
15874 * when instrumenting XNU itself with sanitizer coverage.
15875 */
15876 if (!sKextSummariesLock) {
15877 return result;
15878 }
15879
15880 IOLockLock(sKextSummariesLock);
15881 if (gLoadedKextSummaries) {
15882 foundSummary = summaryForAddress((uintptr_t)address);
15883 if (foundSummary) {
15884 memcpy(summary, foundSummary, sizeof(*summary));
15885 result = KERN_SUCCESS;
15886 } else {
15887 result = KERN_NOT_FOUND;
15888 }
15889 }
15890 IOLockUnlock(sKextSummariesLock);
15891
15892 return result;
15893 }
15894
15895 /*
15896 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15897 * Safe to call in panic context.
15898 */
15899 static OSKextLoadedKextSummary *
15900 findSummary(uint32_t tagID)
15901 {
15902 OSKextLoadedKextSummary * summary;
15903 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15904 summary = gLoadedKextSummaries->summaries + i;
15905 if (summary->loadTag == tagID) {
15906 return summary;
15907 }
15908 }
15909 return NULL;
15910 }
15911
15912 /*********************************************************************
15913 * This function must be safe to call in panic context.
15914 *********************************************************************/
15915 void
15916 OSKext::printSummary(
15917 OSKextLoadedKextSummary * summary,
15918 int (* printf_func)(const char *fmt, ...),
15919 uint32_t flags)
15920 {
15921 kmod_reference_t * kmod_ref = NULL;
15922 uuid_string_t uuid;
15923 char version[kOSKextVersionMaxLength];
15924 uint64_t tmpAddr;
15925 uint64_t tmpSize;
15926 OSKextLoadedKextSummary *dependencySummary;
15927
15928 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
15929 strlcpy(version, "unknown version", sizeof(version));
15930 }
15931 (void) uuid_unparse(summary->uuid, uuid);
15932
15933 #if defined(__arm__) || defined(__arm64__)
15934 tmpAddr = summary->text_exec_address;
15935 tmpSize = summary->text_exec_size;
15936 #else
15937 tmpAddr = summary->address;
15938 tmpSize = summary->size;
15939 #endif
15940 if (kPrintKextsUnslide & flags) {
15941 tmpAddr = ml_static_unslide(tmpAddr);
15942 }
15943 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15944 (kPrintKextsTerse & flags) ? "" : " ",
15945 summary->name, version, uuid,
15946 tmpAddr, tmpAddr + tmpSize - 1);
15947
15948 if (kPrintKextsTerse & flags) {
15949 return;
15950 }
15951
15952 /* print dependency info */
15953 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15954 kmod_ref;
15955 kmod_ref = kmod_ref->next) {
15956 kmod_info_t * rinfo;
15957
15958 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15959 (*printf_func)(" kmod dependency scan stopped "
15960 "due to missing dependency page: %p\n",
15961 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
15962 break;
15963 }
15964 rinfo = kmod_ref->info;
15965
15966 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
15967 (*printf_func)(" kmod dependency scan stopped "
15968 "due to missing kmod page: %p\n",
15969 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
15970 break;
15971 }
15972
15973 if (!rinfo->address) {
15974 continue; // skip fake entries for built-ins
15975 }
15976
15977 dependencySummary = findSummary(rinfo->id);
15978 uuid[0] = 0x00;
15979 tmpAddr = rinfo->address;
15980 tmpSize = rinfo->size;
15981 if (dependencySummary) {
15982 (void) uuid_unparse(dependencySummary->uuid, uuid);
15983 #if defined(__arm__) || defined(__arm64__)
15984 tmpAddr = dependencySummary->text_exec_address;
15985 tmpSize = dependencySummary->text_exec_size;
15986 #endif
15987 }
15988
15989 if (kPrintKextsUnslide & flags) {
15990 tmpAddr = ml_static_unslide(tmpAddr);
15991 }
15992 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15993 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15994 }
15995 return;
15996 }
15997
15998
15999 #if !defined(__arm__) && !defined(__arm64__)
16000 /*******************************************************************************
16001 * substitute() looks at an input string (a pointer within a larger buffer)
16002 * for a match to a substring, and on match it writes the marker & substitution
16003 * character to an output string, updating the scan (from) and
16004 * output (to) indexes as appropriate.
16005 *******************************************************************************/
16006 static int substitute(
16007 const char * scan_string,
16008 char * string_out,
16009 uint32_t * to_index,
16010 uint32_t * from_index,
16011 const char * substring,
16012 char marker,
16013 char substitution);
16014
16015 /* string_out must be at least KMOD_MAX_NAME bytes.
16016 */
16017 static int
16018 substitute(
16019 const char * scan_string,
16020 char * string_out,
16021 uint32_t * to_index,
16022 uint32_t * from_index,
16023 const char * substring,
16024 char marker,
16025 char substitution)
16026 {
16027 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
16028
16029 /* On a substring match, append the marker (if there is one) and then
16030 * the substitution character, updating the output (to) index accordingly.
16031 * Then update the input (from) length by the length of the substring
16032 * that got replaced.
16033 */
16034 if (!strncmp(scan_string, substring, substring_length)) {
16035 if (marker) {
16036 string_out[(*to_index)++] = marker;
16037 }
16038 string_out[(*to_index)++] = substitution;
16039 (*from_index) += substring_length;
16040 return 1;
16041 }
16042 return 0;
16043 }
16044
16045 /*******************************************************************************
16046 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
16047 * KMOD_MAX_NAME characters and performs various substitutions of common
16048 * prefixes & substrings as defined by tables in kext_panic_report.h.
16049 *******************************************************************************/
16050 static void compactIdentifier(
16051 const char * identifier,
16052 char * identifier_out,
16053 char ** identifier_out_end);
16054
16055 static void
16056 compactIdentifier(
16057 const char * identifier,
16058 char * identifier_out,
16059 char ** identifier_out_end)
16060 {
16061 uint32_t from_index, to_index;
16062 uint32_t scan_from_index = 0;
16063 uint32_t scan_to_index = 0;
16064 subs_entry_t * subs_entry = NULL;
16065 int did_sub = 0;
16066
16067 from_index = to_index = 0;
16068 identifier_out[0] = '\0';
16069
16070 /* Replace certain identifier prefixes with shorter @+character sequences.
16071 * Check the return value of substitute() so we only replace the prefix.
16072 */
16073 for (subs_entry = &kext_identifier_prefix_subs[0];
16074 subs_entry->substring && !did_sub;
16075 subs_entry++) {
16076 did_sub = substitute(identifier, identifier_out,
16077 &scan_to_index, &scan_from_index,
16078 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
16079 }
16080 did_sub = 0;
16081
16082 /* Now scan through the identifier looking for the common substrings
16083 * and replacing them with shorter !+character sequences via substitute().
16084 */
16085 for (/* see above */;
16086 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
16087 /* see loop */) {
16088 const char * scan_string = &identifier[scan_from_index];
16089
16090 did_sub = 0;
16091
16092 if (scan_from_index) {
16093 for (subs_entry = &kext_identifier_substring_subs[0];
16094 subs_entry->substring && !did_sub;
16095 subs_entry++) {
16096 did_sub = substitute(scan_string, identifier_out,
16097 &scan_to_index, &scan_from_index,
16098 subs_entry->substring, '!', subs_entry->substitute);
16099 }
16100 }
16101
16102 /* If we didn't substitute, copy the input character to the output.
16103 */
16104 if (!did_sub) {
16105 identifier_out[scan_to_index++] = identifier[scan_from_index++];
16106 }
16107 }
16108
16109 identifier_out[scan_to_index] = '\0';
16110 if (identifier_out_end) {
16111 *identifier_out_end = &identifier_out[scan_to_index];
16112 }
16113
16114 return;
16115 }
16116 #endif /* !defined(__arm__) && !defined(__arm64__) */
16117
16118 /*******************************************************************************
16119 * assemble_identifier_and_version() adds to a string buffer a compacted
16120 * bundle identifier followed by a version string.
16121 *******************************************************************************/
16122
16123 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
16124 */
16125 static size_t assemble_identifier_and_version(
16126 kmod_info_t * kmod_info,
16127 char * identPlusVers,
16128 size_t bufSize);
16129
16130 static size_t
16131 assemble_identifier_and_version(
16132 kmod_info_t * kmod_info,
16133 char * identPlusVers,
16134 size_t bufSize)
16135 {
16136 size_t result = 0;
16137
16138 #if defined(__arm__) || defined(__arm64__)
16139 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
16140 #else
16141 compactIdentifier(kmod_info->name, identPlusVers, NULL);
16142 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
16143 #endif
16144 identPlusVers[result++] = '\t'; // increment for real char
16145 identPlusVers[result] = '\0'; // don't increment for nul char
16146 result = strlcat(identPlusVers, kmod_info->version, bufSize);
16147 if (result >= bufSize) {
16148 identPlusVers[bufSize - 1] = '\0';
16149 result = bufSize - 1;
16150 }
16151
16152 return result;
16153 }
16154
16155 /*******************************************************************************
16156 * Assumes sKextLock is held.
16157 *******************************************************************************/
16158 /* static */
16159 int
16160 OSKext::saveLoadedKextPanicListTyped(
16161 const char * prefix,
16162 int invertFlag,
16163 int libsFlag,
16164 char * paniclist,
16165 uint32_t list_size)
16166 {
16167 int result = -1;
16168 unsigned int count, i;
16169
16170 count = sLoadedKexts->getCount();
16171 if (!count) {
16172 goto finish;
16173 }
16174
16175 i = count - 1;
16176 do {
16177 OSObject * rawKext = sLoadedKexts->getObject(i);
16178 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
16179 int match;
16180 size_t identPlusVersLength;
16181 size_t tempLen;
16182 char identPlusVers[2 * KMOD_MAX_NAME];
16183
16184 if (!rawKext) {
16185 printf("OSKext::saveLoadedKextPanicListTyped - "
16186 "NULL kext in loaded kext list; continuing\n");
16187 continue;
16188 }
16189
16190 if (!theKext) {
16191 printf("OSKext::saveLoadedKextPanicListTyped - "
16192 "Kext type cast failed in loaded kext list; continuing\n");
16193 continue;
16194 }
16195
16196 /* Skip all built-in kexts.
16197 */
16198 if (theKext->isKernelComponent()) {
16199 continue;
16200 }
16201
16202 kmod_info_t * kmod_info = theKext->kmod_info;
16203
16204 /* Filter for kmod name (bundle identifier).
16205 */
16206 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
16207 if ((match && invertFlag) || (!match && !invertFlag)) {
16208 continue;
16209 }
16210
16211 /* Filter for libraries (kexts that have a compatible version).
16212 */
16213 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
16214 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
16215 continue;
16216 }
16217
16218 if (!kmod_info ||
16219 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
16220 printf("kext scan stopped due to missing kmod_info page: %p\n",
16221 kmod_info);
16222 goto finish;
16223 }
16224
16225 identPlusVersLength = assemble_identifier_and_version(kmod_info,
16226 identPlusVers,
16227 sizeof(identPlusVers));
16228 if (!identPlusVersLength) {
16229 printf("error saving loaded kext info\n");
16230 goto finish;
16231 }
16232
16233 /* make sure everything fits and we null terminate.
16234 */
16235 tempLen = strlcat(paniclist, identPlusVers, list_size);
16236 if (tempLen >= list_size) {
16237 // panic list is full, keep it and null terminate
16238 paniclist[list_size - 1] = 0x00;
16239 result = 0;
16240 goto finish;
16241 }
16242 tempLen = strlcat(paniclist, "\n", list_size);
16243 if (tempLen >= list_size) {
16244 // panic list is full, keep it and null terminate
16245 paniclist[list_size - 1] = 0x00;
16246 result = 0;
16247 goto finish;
16248 }
16249 } while (i--);
16250
16251 result = 0;
16252 finish:
16253
16254 return result;
16255 }
16256
16257 /*********************************************************************
16258 *********************************************************************/
16259 /* static */
16260 void
16261 OSKext::saveLoadedKextPanicList(void)
16262 {
16263 char * newlist = NULL;
16264 uint32_t newlist_size = 0;
16265
16266 newlist_size = KEXT_PANICLIST_SIZE;
16267 newlist = (char *)kalloc_data_tag(newlist_size,
16268 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
16269
16270 if (!newlist) {
16271 OSKextLog(/* kext */ NULL,
16272 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
16273 "Couldn't allocate kext panic log buffer.");
16274 goto finish;
16275 }
16276
16277 newlist[0] = '\0';
16278
16279 // non-"com.apple." kexts
16280 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
16281 /* libs? */ -1, newlist, newlist_size) != 0) {
16282 goto finish;
16283 }
16284 // "com.apple." nonlibrary kexts
16285 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16286 /* libs? */ 0, newlist, newlist_size) != 0) {
16287 goto finish;
16288 }
16289 // "com.apple." library kexts
16290 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16291 /* libs? */ 1, newlist, newlist_size) != 0) {
16292 goto finish;
16293 }
16294
16295 if (loaded_kext_paniclist) {
16296 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
16297 }
16298 loaded_kext_paniclist = newlist;
16299 newlist = NULL;
16300 loaded_kext_paniclist_size = newlist_size;
16301
16302 finish:
16303 if (newlist) {
16304 kfree_data(newlist, newlist_size);
16305 }
16306 return;
16307 }
16308
16309 /*********************************************************************
16310 * Assumes sKextLock is held.
16311 *********************************************************************/
16312 void
16313 OSKext::savePanicString(bool isLoading)
16314 {
16315 u_long len;
16316
16317 if (!kmod_info) {
16318 return; // do not goto finish here b/c of lock
16319 }
16320
16321 len = assemble_identifier_and_version( kmod_info,
16322 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
16323 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
16324 if (!len) {
16325 printf("error saving unloaded kext info\n");
16326 goto finish;
16327 }
16328
16329 if (isLoading) {
16330 last_loaded_strlen = len;
16331 last_loaded_address = (void *)kmod_info->address;
16332 last_loaded_size = kmod_info->size;
16333 clock_get_uptime(&last_loaded_timestamp);
16334 } else {
16335 last_unloaded_strlen = len;
16336 last_unloaded_address = (void *)kmod_info->address;
16337 last_unloaded_size = kmod_info->size;
16338 clock_get_uptime(&last_unloaded_timestamp);
16339 }
16340
16341 finish:
16342 return;
16343 }
16344
16345 /*********************************************************************
16346 *********************************************************************/
16347 /* static */
16348 void
16349 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
16350 {
16351 if (last_loaded_strlen) {
16352 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
16353 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16354 last_loaded_strlen, last_loaded_str_buf,
16355 last_loaded_address, last_loaded_size);
16356 }
16357
16358 if (last_unloaded_strlen) {
16359 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16360 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16361 last_unloaded_strlen, last_unloaded_str_buf,
16362 last_unloaded_address, last_unloaded_size);
16363 }
16364
16365 printf_func("loaded kexts:\n");
16366 if (loaded_kext_paniclist &&
16367 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16368 loaded_kext_paniclist[0]) {
16369 printf_func("%.*s",
16370 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
16371 loaded_kext_paniclist);
16372 } else {
16373 printf_func("(none)\n");
16374 }
16375 return;
16376 }
16377
16378 /*********************************************************************
16379 * Assumes sKextLock is held.
16380 *********************************************************************/
16381 /* static */
16382 void
16383 OSKext::updateLoadedKextSummaries(void)
16384 {
16385 kern_return_t result = KERN_FAILURE;
16386 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16387 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16388 OSKext *aKext;
16389 vm_map_offset_t start;
16390 size_t summarySize = 0;
16391 size_t size;
16392 u_int count;
16393 u_int maxKexts;
16394 u_int i, j;
16395 OSKextActiveAccount * accountingList;
16396 OSKextActiveAccount * prevAccountingList;
16397 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16398
16399 prevAccountingList = NULL;
16400 prevAccountingListCount = 0;
16401
16402 #if DEVELOPMENT || DEBUG
16403 if (IORecursiveLockHaveLock(sKextLock) == false) {
16404 panic("sKextLock must be held");
16405 }
16406 #endif
16407
16408 IOLockLock(sKextSummariesLock);
16409
16410 count = sLoadedKexts->getCount();
16411 for (i = 0, maxKexts = 0; i < count; ++i) {
16412 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16413 maxKexts += (aKext && (aKext->isExecutable() || aKext->isSpecialKernelBinary()));
16414 }
16415
16416 if (!maxKexts) {
16417 goto finish;
16418 }
16419 if (maxKexts < kOSKextTypicalLoadCount) {
16420 maxKexts = kOSKextTypicalLoadCount;
16421 }
16422
16423 /* Calculate the size needed for the new summary headers.
16424 */
16425
16426 size = sizeof(*gLoadedKextSummaries);
16427 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16428 size = round_page(size);
16429
16430 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16431 if (gLoadedKextSummaries) {
16432 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
16433 gLoadedKextSummaries = NULL;
16434 gLoadedKextSummariesTimestamp = mach_absolute_time();
16435 sLoadedKextSummariesAllocSize = 0;
16436 }
16437 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
16438 KMA_NONE, VM_KERN_MEMORY_OSKEXT);
16439 if (result != KERN_SUCCESS) {
16440 goto finish;
16441 }
16442 summaryHeader = summaryHeaderAlloc;
16443 summarySize = size;
16444 } else {
16445 summaryHeader = gLoadedKextSummaries;
16446 summarySize = sLoadedKextSummariesAllocSize;
16447
16448 start = (vm_map_offset_t) summaryHeader;
16449 result = mach_vm_protect(kernel_map,
16450 start,
16451 summarySize,
16452 false,
16453 VM_PROT_DEFAULT);
16454 if (result != KERN_SUCCESS) {
16455 goto finish;
16456 }
16457 }
16458
16459 /* Populate the summary header.
16460 */
16461
16462 bzero(summaryHeader, summarySize);
16463 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16464 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16465
16466 /* Populate each kext summary.
16467 */
16468
16469 count = sLoadedKexts->getCount();
16470 accountingListAlloc = 0;
16471 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16472 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16473 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16474 continue;
16475 }
16476
16477 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
16478 summaryHeader->numSummaries++;
16479 accountingListAlloc++;
16480 }
16481
16482 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16483 accountingListCount = 0;
16484 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16485 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16486 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16487 continue;
16488 }
16489
16490 OSKextActiveAccount activeAccount;
16491 aKext->updateActiveAccount(&activeAccount);
16492 // order by address
16493 for (idx = 0; idx < accountingListCount; idx++) {
16494 if (activeAccount.address < accountingList[idx].address) {
16495 break;
16496 }
16497 }
16498 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
16499 accountingList[idx] = activeAccount;
16500 accountingListCount++;
16501 }
16502 assert(accountingListCount == accountingListAlloc);
16503 /* Write protect the buffer and move it into place.
16504 */
16505
16506 start = (vm_map_offset_t) summaryHeader;
16507
16508 result = mach_vm_protect(kernel_map, start, summarySize, false, VM_PROT_READ);
16509 if (result != KERN_SUCCESS) {
16510 goto finish;
16511 }
16512
16513 gLoadedKextSummaries = summaryHeader;
16514 gLoadedKextSummariesTimestamp = mach_absolute_time();
16515 sLoadedKextSummariesAllocSize = summarySize;
16516 summaryHeaderAlloc = NULL;
16517
16518 /* Call the magic breakpoint function through a static function pointer so
16519 * the compiler can't optimize the function away.
16520 */
16521 if (sLoadedKextSummariesUpdated) {
16522 (*sLoadedKextSummariesUpdated)();
16523 }
16524
16525 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16526 prevAccountingList = sKextAccounts;
16527 prevAccountingListCount = sKextAccountsCount;
16528 sKextAccounts = accountingList;
16529 sKextAccountsCount = accountingListCount;
16530 lck_ticket_unlock(sKextAccountsLock);
16531
16532 finish:
16533 IOLockUnlock(sKextSummariesLock);
16534
16535 /* If we had to allocate a new buffer but failed to generate the summaries,
16536 * free that now.
16537 */
16538 if (summaryHeaderAlloc) {
16539 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
16540 }
16541 if (prevAccountingList) {
16542 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16543 }
16544
16545 return;
16546 }
16547
16548 /*********************************************************************
16549 *********************************************************************/
16550 void
16551 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16552 {
16553 OSSharedPtr<OSData> uuid;
16554
16555 strlcpy(summary->name, getIdentifierCString(),
16556 sizeof(summary->name));
16557
16558 uuid = copyUUID();
16559 if (uuid) {
16560 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
16561 }
16562
16563 if (flags.builtin) {
16564 // this value will stop lldb from parsing the mach-o header
16565 // summary->address = UINT64_MAX;
16566 // summary->size = 0;
16567 summary->address = kmod_info->address;
16568 summary->size = kmod_info->size;
16569 } else {
16570 summary->address = kmod_info->address;
16571 summary->size = kmod_info->size;
16572 }
16573 summary->version = getVersion();
16574 summary->loadTag = kmod_info->id;
16575 summary->flags = 0;
16576 summary->reference_list = (uint64_t) kmod_info->reference_list;
16577
16578 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16579 if (summary->text_exec_address == 0) {
16580 // Fallback to __TEXT
16581 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16582 }
16583
16584 /**
16585 * If the addresses within the Mach-O are unslid, then manually slide any
16586 * addresses coming from the Mach-O as higher layer software using these
16587 * summaries expects a slid address here.
16588 */
16589 if (flags.unslidMachO) {
16590 summary->text_exec_address = (uint64_t) ml_static_slide((vm_offset_t) summary->text_exec_address);
16591 }
16592
16593 return;
16594 }
16595
16596 /*********************************************************************
16597 *********************************************************************/
16598
16599 void
16600 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16601 {
16602 kernel_mach_header_t *hdr = NULL;
16603 kernel_segment_command_t *seg = NULL;
16604
16605 bzero(accountp, sizeof(*accountp));
16606
16607 hdr = (kernel_mach_header_t *)kmod_info->address;
16608 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16609 /*
16610 * If this kext supports split segments (or is in a new
16611 * MH_FILESET kext collection), use the first
16612 * executable segment as the range for instructions
16613 * (and thus for backtracing.
16614 */
16615 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
16616 if (seg->initprot & VM_PROT_EXECUTE) {
16617 break;
16618 }
16619 }
16620 }
16621 if (seg) {
16622 accountp->address = seg->vmaddr;
16623 if (accountp->address) {
16624 accountp->address_end = seg->vmaddr + seg->vmsize;
16625 }
16626 } else {
16627 /* For non-split kexts and for kexts without executable
16628 * segments, just use the kmod_info range (as the kext
16629 * is either all in one range or should not show up in
16630 * instruction backtraces).
16631 */
16632 accountp->address = kmod_info->address;
16633 if (accountp->address) {
16634 accountp->address_end = kmod_info->address + kmod_info->size;
16635 }
16636 }
16637
16638 accountp->account = this->account;
16639 }
16640
16641 bool
16642 OSKext::isDriverKit(void)
16643 {
16644 OSString *bundleType;
16645
16646 if (infoDict) {
16647 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16648 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16649 return TRUE;
16650 }
16651 }
16652 return FALSE;
16653 }
16654
16655 bool
16656 OSKext::isInFileset(void)
16657 {
16658 if (!kmod_info) {
16659 goto check_prelinked;
16660 }
16661
16662 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16663 return true;
16664 }
16665
16666 check_prelinked:
16667 if (isPrelinked()) {
16668 /*
16669 * If we haven't setup kmod_info yet, but we know
16670 * we're loading a prelinked kext in an MH_FILESET KC,
16671 * then return true
16672 */
16673 kc_format_t kc_format;
16674 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
16675 return true;
16676 }
16677 }
16678 return false;
16679 }
16680
16681 OSSharedPtr<OSDextStatistics>
16682 OSKext::copyDextStatistics(void)
16683 {
16684 return dextStatistics;
16685 }
16686
16687 bool
16688 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16689 {
16690 kern_return_t result;
16691 if (!super::init()) {
16692 return false;
16693 }
16694 if (seg == nullptr) {
16695 return false;
16696 }
16697 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
16698 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16699 if (result != KERN_SUCCESS) {
16700 return false;
16701 }
16702 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
16703 savedSegment = seg;
16704 vmsize = seg->vmsize;
16705 vmaddr = seg->vmaddr;
16706 return true;
16707 }
16708
16709 OSSharedPtr<OSKextSavedMutableSegment>
16710 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16711 {
16712 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16713 if (me && !me->initWithSegment(seg)) {
16714 return nullptr;
16715 }
16716 return me;
16717 }
16718
16719 void
16720 OSKextSavedMutableSegment::free(void)
16721 {
16722 if (data) {
16723 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
16724 }
16725 }
16726
16727 vm_offset_t
16728 OSKextSavedMutableSegment::getVMAddr() const
16729 {
16730 return vmaddr;
16731 }
16732
16733 vm_offset_t
16734 OSKextSavedMutableSegment::getVMSize() const
16735 {
16736 return vmsize;
16737 }
16738
16739 OSReturn
16740 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16741 {
16742 if (seg != savedSegment) {
16743 return kOSKextReturnInvalidArgument;
16744 }
16745 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16746 return kOSKextReturnInvalidArgument;
16747 }
16748 memcpy((void *)seg->vmaddr, data, vmsize);
16749 return kOSReturnSuccess;
16750 }
16751
16752 extern "C" kern_return_t
16753 OSKextSetReceiptQueried(void)
16754 {
16755 OSKextLog(/* kext */ NULL,
16756 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16757 "Setting kext receipt as queried");
16758
16759 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
16760 return KERN_SUCCESS;
16761 }
16762
16763 extern "C" const vm_allocation_site_t *
16764 OSKextGetAllocationSiteForCaller(uintptr_t address)
16765 {
16766 OSKextActiveAccount * active;
16767 vm_allocation_site_t * site;
16768 vm_allocation_site_t * releasesite;
16769
16770 uint32_t baseIdx;
16771 uint32_t lim;
16772 #if __has_feature(ptrauth_calls)
16773 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16774 #endif /* __has_feature(ptrauth_calls) */
16775
16776 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16777 site = releasesite = NULL;
16778
16779 // bsearch sKextAccounts list
16780 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16781 active = &sKextAccounts[baseIdx + (lim >> 1)];
16782 if ((address >= active->address) && (address < active->address_end)) {
16783 site = &active->account->site;
16784 if (!site->tag) {
16785 vm_tag_alloc_locked(site, &releasesite);
16786 }
16787 break;
16788 } else if (address > active->address) {
16789 // move right
16790 baseIdx += (lim >> 1) + 1;
16791 lim--;
16792 }
16793 // else move left
16794 }
16795 lck_ticket_unlock(sKextAccountsLock);
16796 if (releasesite) {
16797 kern_allocation_name_release(releasesite);
16798 }
16799
16800 return site;
16801 }
16802
16803 #if DEVELOPMENT || DEBUG
16804 extern "C" void
16805 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16806 {
16807 OSKextActiveAccount * active;
16808
16809 uint32_t baseIdx;
16810 uint32_t lim;
16811 #if __has_feature(ptrauth_calls)
16812 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16813 #endif /* __has_feature(ptrauth_calls) */
16814
16815 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16816
16817 // bsearch sKextAccounts list
16818 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16819 active = &sKextAccounts[baseIdx + (lim >> 1)];
16820 if ((address >= active->address) && (address < active->address_end)) {
16821 cb(&active->account->task_refgrp);
16822 break;
16823 } else if (address > active->address) {
16824 // move right
16825 baseIdx += (lim >> 1) + 1;
16826 lim--;
16827 }
16828 // else move left
16829 }
16830 lck_ticket_unlock(sKextAccountsLock);
16831 }
16832 #endif /* DEVELOPMENT || DEBUG */
16833
16834 extern "C" uint32_t
16835 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16836 {
16837 OSKextAccount * account = (typeof(account))site;
16838 const char * kname;
16839
16840 if (name) {
16841 if (account->kext) {
16842 kname = account->kext->getIdentifierCString();
16843 } else {
16844 kname = "<>";
16845 }
16846 strlcpy(name, kname, namelen);
16847 }
16848
16849 return account->loadTag;
16850 }
16851
16852 extern "C" void
16853 OSKextFreeSite(vm_allocation_site_t * site)
16854 {
16855 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16856 IOFreeType(freeAccount, OSKextAccount);
16857 }
16858
16859 /*********************************************************************
16860 *********************************************************************/
16861
16862 #if CONFIG_IMAGEBOOT
16863 int
16864 OSKextGetUUIDForName(const char *name, uuid_t uuid)
16865 {
16866 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
16867 if (!kext) {
16868 return 1;
16869 }
16870
16871 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16872 if (uuid_data) {
16873 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
16874 return 0;
16875 }
16876
16877 return 1;
16878 }
16879 #endif
16880
16881
16882
16883 class OSDextCrash : public OSObject {
16884 OSDeclareDefaultStructors(OSDextCrash);
16885 public:
16886 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16887 uint64_t getTimestamp();
16888
16889 private:
16890 virtual bool initWithTimestamp(uint64_t timestamp);
16891 uint64_t fTimestamp;
16892 };
16893
16894 OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16895
16896 OSSharedPtr<OSDextCrash>
16897 OSDextCrash::withTimestamp(uint64_t timestamp)
16898 {
16899 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16900 if (!result->initWithTimestamp(timestamp)) {
16901 return NULL;
16902 }
16903 return result;
16904 }
16905
16906 bool
16907 OSDextCrash::initWithTimestamp(uint64_t timestamp)
16908 {
16909 if (!OSObject::init()) {
16910 return false;
16911 }
16912 fTimestamp = timestamp;
16913 return true;
16914 }
16915
16916 uint64_t
16917 OSDextCrash::getTimestamp()
16918 {
16919 return fTimestamp;
16920 }
16921
16922 OSSharedPtr<OSDextStatistics>
16923 OSDextStatistics::create()
16924 {
16925 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16926 if (!result->init()) {
16927 return NULL;
16928 }
16929 return result;
16930 }
16931
16932 bool
16933 OSDextStatistics::init()
16934 {
16935 if (!OSObject::init()) {
16936 return false;
16937 }
16938
16939 lock = IOLockAlloc();
16940 crashes = OSArray::withCapacity(kMaxDextCrashesInOneDay);
16941 return true;
16942 }
16943
16944 void
16945 OSDextStatistics::free()
16946 {
16947 if (lock) {
16948 IOLockFree(lock);
16949 }
16950 crashes.reset();
16951 OSObject::free();
16952 }
16953
16954 OSDextCrashPolicy
16955 OSDextStatistics::recordCrash()
16956 {
16957 size_t i = 0;
16958 uint64_t timestamp = mach_continuous_time();
16959 uint64_t interval;
16960 nanoseconds_to_absolutetime(86400 * NSEC_PER_SEC /* 1 day */, &interval);
16961 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16962 OSDextCrashPolicy policy;
16963
16964 IOLockLock(lock);
16965 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16966 for (i = 0; i < crashes->getCount();) {
16967 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16968 assert(current != NULL);
16969 if (current->getTimestamp() < lastTimestamp) {
16970 crashes->removeObject(i);
16971 } else {
16972 i++;
16973 }
16974 }
16975
16976 crashes->setObject(crash);
16977
16978 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16979 policy = kOSDextCrashPolicyReboot;
16980 } else {
16981 policy = kOSDextCrashPolicyNone;
16982 }
16983
16984 IOLockUnlock(lock);
16985
16986 return policy;
16987 }
16988
16989 size_t
16990 OSDextStatistics::getCrashCount()
16991 {
16992 size_t result = 0;
16993 IOLockLock(lock);
16994 result = crashes->getCount();
16995 IOLockUnlock(lock);
16996 return result;
16997 }
16998
16999 static int
17000 sysctl_willuserspacereboot
17001 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
17002 {
17003 int new_value = 0, old_value = get_system_inuserspacereboot(), changed = 0;
17004 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
17005 if (error) {
17006 return error;
17007 }
17008 if (changed) {
17009 OSKext::setWillUserspaceReboot();
17010 }
17011 return 0;
17012 }
17013
17014 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
17015 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
17016 NULL, 0, sysctl_willuserspacereboot, "I", "");
17017