1 /*
2 * Copyright (c) 2008-2021 Apple Inc. All rights reserved.
3 *
4 * @APPLE_OSREFERENCE_LICENSE_HEADER_START@
5 *
6 * This file contains Original Code and/or Modifications of Original Code
7 * as defined in and that are subject to the Apple Public Source License
8 * Version 2.0 (the 'License'). You may not use this file except in
9 * compliance with the License. The rights granted to you under the License
10 * may not be used to create, or enable the creation or redistribution of,
11 * unlawful or unlicensed copies of an Apple operating system, or to
12 * circumvent, violate, or enable the circumvention or violation of, any
13 * terms of an Apple operating system software license agreement.
14 *
15 * Please obtain a copy of the License at
16 * http://www.opensource.apple.com/apsl/ and read it before using this file.
17 *
18 * The Original Code and all software distributed under the License are
19 * distributed on an 'AS IS' basis, WITHOUT WARRANTY OF ANY KIND, EITHER
20 * EXPRESS OR IMPLIED, AND APPLE HEREBY DISCLAIMS ALL SUCH WARRANTIES,
21 * INCLUDING WITHOUT LIMITATION, ANY WARRANTIES OF MERCHANTABILITY,
22 * FITNESS FOR A PARTICULAR PURPOSE, QUIET ENJOYMENT OR NON-INFRINGEMENT.
23 * Please see the License for the specific language governing rights and
24 * limitations under the License.
25 *
26 * @APPLE_OSREFERENCE_LICENSE_HEADER_END@
27 */
28
29 #define IOKIT_ENABLE_SHARED_PTR
30
31 extern "C" {
32 #include <string.h>
33 #include <kern/clock.h>
34 #include <kern/host.h>
35 #include <kern/kext_alloc.h>
36 #include <firehose/tracepoint_private.h>
37 #include <firehose/chunk_private.h>
38 #include <os/firehose_buffer_private.h>
39 #include <vm/vm_map_xnu.h>
40 #include <kextd/kextd_mach.h>
41 #include <libkern/kernel_mach_header.h>
42 #include <libkern/kext_panic_report.h>
43 #include <libkern/kext_request_keys.h>
44 #include <libkern/mkext.h>
45 #include <libkern/prelink.h>
46 #include <libkern/version.h>
47 #include <libkern/zlib.h>
48 #include <mach/host_special_ports.h>
49 #include <mach/mach_vm.h>
50 #include <mach/mach_time.h>
51 #include <uuid/uuid.h>
52 #include <sys/random.h>
53 #include <pexpert/pexpert.h>
54
55 #include <sys/pgo.h>
56
57 #if CONFIG_CSR
58 #include <sys/csr.h>
59 #include <sys/stat.h>
60 #include <sys/vnode.h>
61 #endif /* CONFIG_CSR */
62 };
63
64 #if CONFIG_MACF
65 #include <sys/kauth.h>
66 #include <security/mac_framework.h>
67 #endif
68
69 #include <vm/vm_kern_xnu.h>
70 #include <sys/sysctl.h>
71 #include <kern/task.h>
72 #include <os/cpp_util.h>
73
74 #include <libkern/OSKextLibPrivate.h>
75 #include <libkern/c++/OSKext.h>
76 #include <libkern/c++/OSLib.h>
77
78 #include <IOKit/IOLib.h>
79 #include <IOKit/IOCatalogue.h>
80 #include <IOKit/IORegistryEntry.h>
81 #include <IOKit/IOService.h>
82 #include <IOKit/IOUserServer.h>
83
84 #include <IOKit/IOStatisticsPrivate.h>
85 #include <IOKit/IOBSD.h>
86 #include <IOKit/IOPlatformExpert.h>
87
88 #include <san/kasan.h>
89
90 #if CONFIG_SPTM
91 #include <arm64/sptm/sptm.h>
92 #endif
93
94 #if PRAGMA_MARK
95 #pragma mark External & Internal Function Protos
96 #endif
97 /*********************************************************************
98 *********************************************************************/
99 extern "C" {
100 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
101 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
102
103 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
104 extern int dtrace_keep_kernel_symbols(void);
105
106 #if defined(__x86_64__) || defined(__i386__)
107 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
108 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
109 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
110 static void *allocate_kcfileset_map_entry_list(void);
111 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
112 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
113 int vnode_put(struct vnode *vp);
114 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
115 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
116 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
117 void * ubc_getobject(struct vnode *vp, __unused int flags);
118 #endif //(__x86_64__) || defined(__i386__)
119 }
120
121 extern unsigned long gVirtBase;
122 extern unsigned long gPhysBase;
123
124 bool pageableKCloaded = false;
125 bool auxKCloaded = false;
126 bool resetAuxKCSegmentOnUnload = false;
127
128 extern boolean_t pageablekc_uuid_valid;
129 extern uuid_t pageablekc_uuid;
130 extern uuid_string_t pageablekc_uuid_string;
131
132 extern boolean_t auxkc_uuid_valid;
133 extern uuid_t auxkc_uuid;
134 extern uuid_string_t auxkc_uuid_string;
135
136 static OSReturn _OSKextCreateRequest(
137 const char * predicate,
138 OSSharedPtr<OSDictionary> & requestP);
139 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
140 static OSObject * _OSKextGetRequestArgument(
141 OSDictionary * requestDict,
142 const char * argName);
143 static bool _OSKextSetRequestArgument(
144 OSDictionary * requestDict,
145 const char * argName,
146 OSMetaClassBase * value);
147 template <typename T>
148 static T * _OSKextExtractPointer(OSValueObject<T *> * wrapper);
149 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper);
150 static OSReturn _OSDictionarySetCStringValue(
151 OSDictionary * dict,
152 const char * key,
153 const char * value);
154 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
155 #if CONFIG_KXLD
156 static bool _OSKextInPrelinkRebuildWindow(void);
157 #endif
158
159 // We really should add containsObject() & containsCString to OSCollection & subclasses.
160 // So few pad slots, though....
161 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
162 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
163
164 static const char *getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size);
165
166 /* Prelinked arm kexts do not have VM entries because the method we use to
167 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
168 * not work on ARM. To get around that, we must free prelinked kext
169 * executables with ml_static_mfree() instead of kext_free().
170 */
171 #if __i386__ || __x86_64__
172 #define VM_MAPPED_KEXTS 1
173 #define KASLR_KEXT_DEBUG 0
174 #define KASLR_IOREG_DEBUG 0
175 #elif __arm__ || __arm64__
176 #define VM_MAPPED_KEXTS 0
177 #define KASLR_KEXT_DEBUG 0
178 #else
179 #error Unsupported architecture
180 #endif
181
182 #if PRAGMA_MARK
183 #pragma mark Constants & Macros
184 #endif
185 /*********************************************************************
186 * Constants & Macros
187 *********************************************************************/
188
189 /* Use this number to create containers.
190 */
191 #define kOSKextTypicalLoadCount (150)
192 #define kOSKextTypicalUpgradeCount (5)
193
194 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
195 * A loaded kext will no dependents or external retains will have 2 retains.
196 */
197 #define kOSKextMinRetainCount (1)
198 #define kOSKextMinLoadedRetainCount (2)
199
200 #define kOSKextMaxDextLaunchedCount (~((uint32_t)0))
201 #define KOSBundleDextUniqueIdentifierMaxStringLength (KOSBundleDextUniqueIdentifierMaxLength * 2 +1)
202
203 /**********
204 * Strings and substrings used in dependency resolution.
205 */
206 #define APPLE_KEXT_PREFIX "com.apple."
207 #define KERNEL_LIB "com.apple.kernel"
208
209 #define PRIVATE_KPI "com.apple.kpi.private"
210
211 /* Version for compatbility pseudokexts (com.apple.kernel.*),
212 * compatible back to v6.0.
213 */
214 #define KERNEL6_LIB "com.apple.kernel.6.0"
215 #define KERNEL6_VERSION "7.9.9"
216
217 #define KERNEL_LIB_PREFIX "com.apple.kernel."
218 #define KPI_LIB_PREFIX "com.apple.kpi."
219
220 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
221
222 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
223 #define MINIMUM_WAKEUP_SECONDS (30)
224
225 /*********************************************************************
226 * infoDict keys for internally-stored data. Saves on ivar slots for
227 * objects we don't keep around past boot time or during active load.
228 *********************************************************************/
229
230 /* A usable, uncompressed file is stored under this key.
231 */
232 #define _kOSKextExecutableKey "_OSKextExecutable"
233
234 /* An indirect reference to the executable file from an mkext
235 * is stored under this key.
236 */
237 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
238
239 /* If the file is contained in a larger buffer laid down by the booter or
240 * sent from user space, the OSKext stores that OSData under this key so that
241 * references are properly tracked. This is always an mkext, right now.
242 */
243 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
244
245 #define OS_LOG_HDR_VERSION 1
246 #define NUM_OS_LOG_SECTIONS 3
247
248 #define OS_LOG_SECT_IDX 0
249 #define CSTRING_SECT_IDX 1
250 #define ASAN_CSTRING_SECT_IDX 2
251
252 #if PRAGMA_MARK
253 #pragma mark Typedefs
254 #endif
255 /*********************************************************************
256 * Typedefs
257 *********************************************************************/
258
259 /*********************************************************************
260 * osLogDataHeaderRef describes the header information of an OSData
261 * object that is returned when querying for kOSBundleLogStringsKey.
262 * We currently return information regarding 2 sections - os_log and
263 * cstring. In the case that the os_log section doesn't exist, we just
264 * return an offset and length of 0 for that section.
265 *********************************************************************/
266 typedef struct osLogDataHeader {
267 uint32_t version;
268 uint32_t sect_count;
269 struct {
270 uint32_t sect_offset;
271 uint32_t sect_size;
272 } sections[0];
273 } osLogDataHeaderRef;
274
275 /*********************************************************************
276 * MkextEntryRef describes the contents of an OSData object
277 * referencing a file entry from an mkext so that we can uncompress
278 * (if necessary) and extract it on demand.
279 *
280 * It contains the mkextVersion in case we ever wind up supporting
281 * multiple mkext formats. Mkext format 1 is officially retired as of
282 * Snow Leopard.
283 *********************************************************************/
284 typedef struct MkextEntryRef {
285 mkext_basic_header * mkext; // beginning of whole mkext file
286 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
287 } MkextEntryRef;
288
289 #if PRAGMA_MARK
290 #pragma mark Global and static Module Variables
291 #endif
292 /*********************************************************************
293 * Global & static variables, used to keep track of kexts.
294 *********************************************************************/
295
296 static bool sPrelinkBoot = false;
297 static bool sSafeBoot = false;
298 static bool sKeepSymbols = false;
299 static bool sPanicOnKCMismatch = false;
300 static bool sOSKextWasResetAfterUserspaceReboot = false;
301
302 /*********************************************************************
303 * sKextLock is the principal lock for OSKext, and guards all static
304 * and global variables not owned by other locks (declared further
305 * below). It must be taken by any entry-point method or function,
306 * including internal functions called on scheduled threads.
307 *
308 * sKextLock and sKextInnerLock are recursive due to multiple functions
309 * that are called both externally and internally. The other locks are
310 * nonrecursive.
311 *
312 * Which locks are taken depends on what they protect, but if more than
313 * one must be taken, they must always be locked in this order
314 * (and unlocked in reverse order) to prevent deadlocks:
315 *
316 * 1. sKextLock
317 * 2. sKextInnerLock
318 * 3. sKextSummariesLock
319 * 4. sKextLoggingLock
320 */
321 static IORecursiveLock * sKextLock = NULL;
322
323 static OSSharedPtr<OSDictionary> sKextsByID;
324 static OSSharedPtr<OSDictionary> sExcludeListByID;
325 static OSKextVersion sExcludeListVersion = 0;
326 static OSSharedPtr<OSArray> sLoadedKexts;
327 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
328 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
329 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
330 static OSSharedPtr<OSDictionary> sDriverKitToUpgradeByID;
331
332 // Requests to the IOKit daemon waiting to be picked up.
333 static OSSharedPtr<OSArray> sKernelRequests;
334 // Identifier of kext load requests in sKernelRequests
335 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
336 static OSSharedPtr<OSArray> sRequestCallbackRecords;
337
338 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
339 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
340 #if CONFIG_KXLD
341 static KXLDContext * sKxldContext = NULL;
342 #endif
343 static uint32_t sNextLoadTag = 0;
344 static uint32_t sNextRequestTag = 0;
345
346 static bool sUserLoadsActive = false;
347 static bool sIOKitDaemonActive = false;
348 static bool sDeferredLoadSucceeded = false;
349 static bool sConsiderUnloadsExecuted = false;
350
351 #if NO_KEXTD
352 static bool sKernelRequestsEnabled = false;
353 #else
354 static bool sKernelRequestsEnabled = true;
355 #endif
356 static bool sLoadEnabled = true;
357 static bool sUnloadEnabled = true;
358
359 /*********************************************************************
360 * Stuff for the OSKext representing the kernel itself.
361 **********/
362 static OSKext * sKernelKext = NULL;
363
364 /* Load Tag IDs used by statically loaded binaries (e.g, the kernel itself). */
365 enum : uint32_t {
366 kOSKextKernelLoadTag = 0,
367 #if CONFIG_SPTM
368 kOSKextSPTMLoadTag = 1,
369 kOSKextTXMLoadTag = 2,
370 #endif /* CONFIG_SPTM */
371 kOSKextLoadTagCount
372 };
373
374 /* Set up a fake kmod_info struct for the kernel.
375 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
376 * before OSKext is initialized; that call only needs the name
377 * and address to be set correctly.
378 *
379 * We don't do much else with the kerne's kmod_info; we never
380 * put it into the kmod list, never adjust the reference count,
381 * and never have kernel components reference it.
382 * For that matter, we don't do much with kmod_info structs
383 * at all anymore! We just keep them filled in for gdb and
384 * binary compability.
385 */
386 kmod_info_t g_kernel_kmod_info = {
387 .next = NULL,
388 .info_version = KMOD_INFO_VERSION,
389 .id = kOSKextKernelLoadTag, // loadTag: kernel is always 0
390 .name = kOSKextKernelIdentifier,// bundle identifier
391 .version = "0", // filled in in OSKext::initialize()
392 .reference_count = -1, // never adjusted; kernel never unloads
393 .reference_list = NULL,
394 .address = 0,
395 .size = 0, // filled in in OSKext::initialize()
396 .hdr_size = 0,
397 .start = NULL,
398 .stop = NULL
399 };
400
401 #if CONFIG_SPTM
402 /* The SPTM and TXM need fake kmod structures just like the kernel. */
403 kmod_info_t g_sptm_kmod_info = {
404 .next = NULL,
405 .info_version = KMOD_INFO_VERSION,
406 .id = kOSKextSPTMLoadTag, // Always one after the kernel
407 .name = kOSKextSPTMIdentifier,// bundle identifier
408 .version = "0", // filled in by OSKext::initialize()
409 .reference_count = -1, // never adjusted; SPTM never unloads
410 .reference_list = NULL,
411 .address = 0,
412 .size = 0, // filled in by OSKext::initialize()
413 .hdr_size = 0,
414 .start = NULL,
415 .stop = NULL
416 };
417
418 kmod_info_t g_txm_kmod_info = {
419 .next = NULL,
420 .info_version = KMOD_INFO_VERSION,
421 .id = kOSKextTXMLoadTag, // Always one after the SPTM
422 .name = kOSKextTXMIdentifier,// bundle identifier
423 .version = "0", // filled in by OSKext::initialize()
424 .reference_count = -1, // never adjusted; TXM never unloads
425 .reference_list = NULL,
426 .address = 0,
427 .size = 0, // filled in by OSKext::initialize()
428 .hdr_size = 0,
429 .start = NULL,
430 .stop = NULL
431 };
432 #endif /* CONFIG_SPTM */
433
434 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
435
436 kmod_info_t invalid_kmod_info = {
437 .next = NULL,
438 .info_version = KMOD_INFO_VERSION,
439 .id = UINT32_MAX,
440 .name = "invalid",
441 .version = "0",
442 .reference_count = -1,
443 .reference_list = NULL,
444 .address = 0,
445 .size = 0,
446 .hdr_size = 0,
447 .start = NULL,
448 .stop = NULL
449 };
450
451 extern "C" {
452 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
453 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
454 // misc_protos.h, db_low_trace.c, kgmacros
455 // 'kmod' is a holdover from the old kmod system, we can't rename it.
456 kmod_info_t * kmod = NULL;
457
458 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
459
460
461 static char * loaded_kext_paniclist = NULL;
462 static uint32_t loaded_kext_paniclist_size = 0;
463
464 AbsoluteTime last_loaded_timestamp;
465 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
466 static u_long last_loaded_strlen = 0;
467 static void * last_loaded_address = NULL;
468 static u_long last_loaded_size = 0;
469
470 AbsoluteTime last_unloaded_timestamp;
471 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
472 static u_long last_unloaded_strlen = 0;
473 static void * last_unloaded_address = NULL;
474 static u_long last_unloaded_size = 0;
475
476 // Statically linked kmods described by several mach-o sections:
477 //
478 // kPrelinkInfoSegment:kBuiltinInfoSection
479 // Array of pointers to kmod_info_t structs.
480 //
481 // kPrelinkInfoSegment:kBuiltinInfoSection
482 // Array of pointers to an embedded mach-o header.
483 //
484 // __DATA:kBuiltinInitSection, kBuiltinTermSection
485 // Structors for all kmods. Has to be filtered by proc address.
486 //
487
488 static uint32_t gBuiltinKmodsCount;
489 static kernel_section_t * gBuiltinKmodsSectionInfo;
490 static kernel_section_t * gBuiltinKmodsSectionStart;
491
492 const OSSymbol * gIOSurfaceIdentifier;
493 vm_tag_t gIOSurfaceTag;
494
495 /*********************************************************************
496 * sKextInnerLock protects against cross-calls with IOService and
497 * IOCatalogue, and owns the variables declared immediately below.
498 *
499 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
500 *
501 * When both sKextLock and sKextInnerLock need to be taken,
502 * always lock sKextLock first and unlock it second. Never take both
503 * locks in an entry point to OSKext; if you need to do so, you must
504 * spawn an independent thread to avoid potential deadlocks for threads
505 * calling into OSKext.
506 **********/
507 static IORecursiveLock * sKextInnerLock = NULL;
508
509 #if XNU_TARGET_OS_OSX
510 static bool sAutounloadEnabled = true;
511 #endif
512 static bool sConsiderUnloadsCalled = false;
513 static bool sConsiderUnloadsPending = false;
514
515 static unsigned int sConsiderUnloadDelay = 60; // seconds
516 static thread_call_t sUnloadCallout = NULL;
517 #if CONFIG_KXLD
518 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
519 #endif // CONFIG_KXLD
520 static bool sSystemSleep = false; // true when system going to sleep
521 static AbsoluteTime sLastWakeTime; // last time we woke up
522
523 /*********************************************************************
524 * Backtraces can be printed at various times so we need a tight lock
525 * on data used for that. sKextSummariesLock protects the variables
526 * declared immediately below.
527 *
528 * gLoadedKextSummaries is accessed by other modules, but only during
529 * a panic so the lock isn't needed then.
530 *
531 * gLoadedKextSummaries has the "used" attribute in order to ensure
532 * that it remains visible even when we are performing extremely
533 * aggressive optimizations, as it is needed to allow the debugger
534 * to automatically parse the list of loaded kexts.
535 **********/
536 static IOLock * sKextSummariesLock = NULL;
537 extern "C" lck_grp_t vm_page_lck_grp_bucket;
538 static lck_grp_t * sKextAccountsLockGrp = &vm_page_lck_grp_bucket;
539 #define sKextAccountsLock (&vm_allocation_sites_lock)
540
541 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
542 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
543 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
544 static size_t sLoadedKextSummariesAllocSize = 0;
545
546 static OSKextActiveAccount * sKextAccounts;
547 static uint32_t sKextAccountsCount;
548 };
549
550 /*********************************************************************
551 * sKextLoggingLock protects the logging variables declared immediately below.
552 **********/
553 static IOLock * sKextLoggingLock = NULL;
554
555 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
556 kOSKextLogVerboseFlagsMask;
557 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
558 static bool sBootArgLogFilterFound = false;
559 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
560 0, "kernel kext logging");
561
562 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
563 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
564 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
565
566 /*********
567 * End scope for sKextInnerLock-protected variables.
568 *********************************************************************/
569
570 /*********************************************************************
571 * OSValueObject concrete type instantiations
572 **********/
573 OSDefineValueObjectForDependentType(void*)
574 OSDefineValueObjectForDependentType(OSKextRequestResourceCallback)
575
576
577 /**********************************************************************/
578
579 TUNABLE(uint32_t, kMaxDextCrashesInOneDay, "daily_max_dext_crashes", kMaxDextCrashesInOneDayDefault);
580
581 /*********************************************************************
582 * helper function used for collecting PGO data upon unload of a kext
583 */
584
585 static int OSKextGrabPgoDataLocked(OSKext *kext,
586 bool metadata,
587 uuid_t instance_uuid,
588 uint64_t *pSize,
589 char *pBuffer,
590 uint64_t bufferSize);
591
592 /**********************************************************************/
593
594
595
596 #if PRAGMA_MARK
597 #pragma mark OSData callbacks (need to move to OSData)
598 #endif
599 /*********************************************************************
600 * C functions used for callbacks.
601 *********************************************************************/
602 extern "C" {
603 void
osdata_kmem_free(void * ptr,unsigned int length)604 osdata_kmem_free(void * ptr, unsigned int length)
605 {
606 kmem_free(kernel_map, (vm_address_t)ptr, length);
607 return;
608 }
609
610 void
osdata_phys_free(void * ptr,unsigned int length)611 osdata_phys_free(void * ptr, unsigned int length)
612 {
613 ml_static_mfree((vm_offset_t)ptr, length);
614 return;
615 }
616
617 void
osdata_vm_deallocate(void * ptr,unsigned int length)618 osdata_vm_deallocate(void * ptr, unsigned int length)
619 {
620 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
621 return;
622 }
623
624 void
osdata_kext_free(void * ptr,unsigned int length)625 osdata_kext_free(void * ptr, unsigned int length)
626 {
627 (void)kext_free((vm_offset_t)ptr, length);
628 }
629 };
630
631 #if PRAGMA_MARK
632 #pragma mark KXLD Allocation Callback
633 #endif
634 #if CONFIG_KXLD
635 /*********************************************************************
636 * KXLD Allocation Callback
637 *********************************************************************/
638 kxld_addr_t
kern_allocate(u_long size,KXLDAllocateFlags * flags,void * user_data)639 kern_allocate(
640 u_long size,
641 KXLDAllocateFlags * flags,
642 void * user_data)
643 {
644 vm_address_t result = 0; // returned
645 kern_return_t mach_result = KERN_FAILURE;
646 bool success = false;
647 OSKext * theKext = (OSKext *)user_data;
648 unsigned int roundSize = 0;
649 OSSharedPtr<OSData> linkBuffer;
650
651 if (round_page(size) > UINT_MAX) {
652 OSKextLog(theKext,
653 kOSKextLogErrorLevel |
654 kOSKextLogGeneralFlag,
655 "%s: Requested memory size is greater than UINT_MAX.",
656 theKext->getIdentifierCString());
657 goto finish;
658 }
659
660 roundSize = (unsigned int)round_page(size);
661
662 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
663 if (mach_result != KERN_SUCCESS) {
664 OSKextLog(theKext,
665 kOSKextLogErrorLevel |
666 kOSKextLogGeneralFlag,
667 "Can't allocate kernel memory to link %s.",
668 theKext->getIdentifierCString());
669 goto finish;
670 }
671
672 /* Create an OSData wrapper for the allocated buffer.
673 */
674 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
675 if (!linkBuffer) {
676 OSKextLog(theKext,
677 kOSKextLogErrorLevel |
678 kOSKextLogGeneralFlag,
679 "Can't allocate linked executable wrapper for %s.",
680 theKext->getIdentifierCString());
681 goto finish;
682 }
683 linkBuffer->setDeallocFunction(osdata_kext_free);
684 OSKextLog(theKext,
685 kOSKextLogProgressLevel |
686 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
687 "Allocated link buffer for kext %s at %p (%lu bytes).",
688 theKext->getIdentifierCString(),
689 (void *)result, (unsigned long)roundSize);
690
691 theKext->setLinkedExecutable(linkBuffer.get());
692
693 *flags = kKxldAllocateWritable;
694 success = true;
695
696 finish:
697 if (!success && result) {
698 kext_free(result, roundSize);
699 result = 0;
700 }
701
702 return (kxld_addr_t)result;
703 }
704
705 /*********************************************************************
706 *********************************************************************/
707 void
kxld_log_callback(KXLDLogSubsystem subsystem,KXLDLogLevel level,const char * format,va_list argList,void * user_data)708 kxld_log_callback(
709 KXLDLogSubsystem subsystem,
710 KXLDLogLevel level,
711 const char * format,
712 va_list argList,
713 void * user_data)
714 {
715 OSKext *theKext = (OSKext *) user_data;
716 OSKextLogSpec logSpec = 0;
717
718 switch (subsystem) {
719 case kKxldLogLinking:
720 logSpec |= kOSKextLogLinkFlag;
721 break;
722 case kKxldLogPatching:
723 logSpec |= kOSKextLogPatchFlag;
724 break;
725 }
726
727 switch (level) {
728 case kKxldLogExplicit:
729 logSpec |= kOSKextLogExplicitLevel;
730 break;
731 case kKxldLogErr:
732 logSpec |= kOSKextLogErrorLevel;
733 break;
734 case kKxldLogWarn:
735 logSpec |= kOSKextLogWarningLevel;
736 break;
737 case kKxldLogBasic:
738 logSpec |= kOSKextLogProgressLevel;
739 break;
740 case kKxldLogDetail:
741 logSpec |= kOSKextLogDetailLevel;
742 break;
743 case kKxldLogDebug:
744 logSpec |= kOSKextLogDebugLevel;
745 break;
746 }
747
748 OSKextVLog(theKext, logSpec, format, argList);
749 }
750 #endif // CONFIG_KXLD
751
752 #if PRAGMA_MARK
753 #pragma mark IOStatistics defines
754 #endif
755
756 #if IOKITSTATS
757
758 #define notifyKextLoadObservers(kext, kmod_info) \
759 do { \
760 IOStatistics::onKextLoad(kext, kmod_info); \
761 } while (0)
762
763 #define notifyKextUnloadObservers(kext) \
764 do { \
765 IOStatistics::onKextUnload(kext); \
766 } while (0)
767
768 #define notifyAddClassObservers(kext, addedClass, flags) \
769 do { \
770 IOStatistics::onClassAdded(kext, addedClass); \
771 } while (0)
772
773 #define notifyRemoveClassObservers(kext, removedClass, flags) \
774 do { \
775 IOStatistics::onClassRemoved(kext, removedClass); \
776 } while (0)
777
778 #else
779
780 #define notifyKextLoadObservers(kext, kmod_info)
781 #define notifyKextUnloadObservers(kext)
782 #define notifyAddClassObservers(kext, addedClass, flags)
783 #define notifyRemoveClassObservers(kext, removedClass, flags)
784
785 #endif /* IOKITSTATS */
786
787 #if PRAGMA_MARK
788 #pragma mark Module Config (Startup & Shutdown)
789 #endif
790 /*********************************************************************
791 * Module Config (Class Definition & Class Methods)
792 *********************************************************************/
793 #define super OSObject
794 OSDefineMetaClassAndStructors(OSKext, OSObject)
795
796 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
797
798 OSDefineMetaClassAndStructors(OSDextStatistics, OSObject);
799
800 /*********************************************************************
801 *********************************************************************/
802 /**
803 * Allocate and intialize a fake/representative OSKext object for a statically
804 * loaded (by iBoot) binary (e.g., the XNU kernel itself).
805 *
806 * @param kmod_info Pointer to the kmod_info structure for the binary being
807 * setup. At least the "name" and "id" fields needs to already
808 * be set correctly.
809 *
810 * @return The allocated and initialized OSKext object.
811 */
812 /* static */
813 OSKext *
allocAndInitFakeKext(kmod_info_t * kmod_info)814 OSKext::allocAndInitFakeKext(kmod_info_t *kmod_info)
815 {
816 vm_offset_t load_address = 0;
817 const char *bundle_name = NULL;
818 bool macho_is_unslid = false;
819 bool set_custom_path = false;
820 const char *executable_fallback_name = NULL;
821
822 if (kmod_info->id == kOSKextKernelLoadTag) {
823 load_address = (vm_offset_t)&_mh_execute_header;
824 bundle_name = "mach_kernel";
825
826 /* The kernel Mach-O header is fixed up to slide all of its addresses. */
827 macho_is_unslid = false;
828
829 /**
830 * No path to the binary is set for the kernel in its OSKext object. The
831 * kernel binary is located in fixed directories depending on the OS.
832 */
833 set_custom_path = false;
834 executable_fallback_name = NULL;
835 #if CONFIG_SPTM
836 } else if (kmod_info->id == kOSKextSPTMLoadTag) {
837 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_SPTM];
838 bundle_name = "sptm";
839
840 /* The addresses in the SPTM Mach-O header are all unslid. */
841 macho_is_unslid = true;
842
843 set_custom_path = true;
844 executable_fallback_name = "sptm.no.binname.in.macho";
845 } else if (kmod_info->id == kOSKextTXMLoadTag) {
846 load_address = (vm_offset_t)SPTMArgs->debug_header->image[DEBUG_HEADER_ENTRY_TXM];
847 bundle_name = "txm";
848
849 /* The addresses in the TXM Mach-O header are all unslid. */
850 macho_is_unslid = true;
851
852 set_custom_path = true;
853 executable_fallback_name = "txm.no.binname.in.macho";
854 #endif /* CONFIG_SPTM */
855 } else {
856 panic("%s: Unsupported kmod_info->id (%d)", __func__, kmod_info->id);
857 }
858
859 /* Set up an OSKext instance to represent the statically loaded binary. */
860 OSKext *fakeKext = new OSKext;
861 assert(fakeKext);
862 assert(load_address != 0);
863
864 /*
865 * The start address is always a slid address whereas the last VA returned
866 * by getlastaddr() might be unslid depending on the Mach-O. If the address
867 * coming from the Mach-O is unslid, then unslide the start address before
868 * computing the length of the executable.
869 */
870 size_t binaryLength = getlastaddr((kernel_mach_header_t*)load_address);
871 binaryLength -= (macho_is_unslid) ? ml_static_unslide(load_address) : load_address;
872 assert(binaryLength <= UINT_MAX);
873
874 /**
875 * The load address is always slid. That value will be unslid before being
876 * exposed to userspace.
877 */
878 OSSharedPtr<OSData> executable = OSData::withBytesNoCopy(
879 (void*)load_address, (unsigned int)binaryLength);
880 assert(executable);
881
882 fakeKext->loadTag = sNextLoadTag++;
883 fakeKext->bundleID = OSSymbol::withCString(kmod_info->name);
884
885 fakeKext->version = OSKextParseVersionString(osrelease);
886 fakeKext->compatibleVersion = fakeKext->version;
887 fakeKext->linkedExecutable = os::move(executable);
888 fakeKext->interfaceUUID = fakeKext->copyUUID();
889
890 fakeKext->flags.hasAllDependencies = 1;
891 fakeKext->flags.kernelComponent = 1;
892 fakeKext->flags.prelinked = 0;
893 fakeKext->flags.loaded = 1;
894 fakeKext->flags.started = 1;
895 fakeKext->flags.CPPInitialized = 0;
896 fakeKext->flags.jettisonLinkeditSeg = 0;
897 fakeKext->flags.unslidMachO = macho_is_unslid;
898
899 #if CONFIG_SPTM
900 if (set_custom_path) {
901 /* Only SPTM/TXM should have custom paths to their executables set. */
902 assert((kmod_info->id == kOSKextSPTMLoadTag) ||
903 (kmod_info->id == kOSKextTXMLoadTag));
904
905 /* All SPTM/TXM binaries are placed into the same path on internal systems. */
906 fakeKext->path = OSString::withCStringNoCopy("/usr/appleinternal/standalone/platform");
907
908 /**
909 * Each SPTM/TXM Mach-O should contain a __TEXT,__binname section which contains
910 * a character array representing the name of the Mach-O executable.
911 */
912 kernel_section_t *binname_sect =
913 getsectbynamefromheader((kernel_mach_header_t*)load_address, "__TEXT", "__binname");
914
915 if (binname_sect != NULL) {
916 const char *binname = (const char *)ml_static_slide(binname_sect->addr);
917 fakeKext->executableRelPath = OSString::withCStringNoCopy(binname);
918 } else {
919 fakeKext->executableRelPath = OSString::withCStringNoCopy(executable_fallback_name);
920 }
921 }
922 #endif /* CONFIG_SPTM */
923
924 fakeKext->kmod_info = kmod_info;
925 strlcpy(kmod_info->version, osrelease,
926 sizeof(kmod_info->version));
927 kmod_info->size = binaryLength;
928 assert(kmod_info->id == fakeKext->loadTag);
929
930 /*
931 * Con up an info dict, so we don't have to have special-case checking all
932 * over.
933 */
934 fakeKext->infoDict = OSDictionary::withCapacity(5);
935 assert(fakeKext->infoDict);
936 bool setResult = fakeKext->infoDict->setObject(kCFBundleIdentifierKey,
937 fakeKext->bundleID.get());
938 assert(setResult);
939 setResult = fakeKext->infoDict->setObject(kOSKernelResourceKey,
940 kOSBooleanTrue);
941 assert(setResult);
942
943 {
944 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
945 assert(scratchString);
946 setResult = fakeKext->infoDict->setObject(kCFBundleVersionKey,
947 scratchString.get());
948 assert(setResult);
949 }
950
951 {
952 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(bundle_name));
953 assert(scratchString);
954 setResult = fakeKext->infoDict->setObject(kCFBundleNameKey,
955 scratchString.get());
956 assert(setResult);
957 }
958
959 return fakeKext;
960 }
961
962 /* static */
963 void
initialize(void)964 OSKext::initialize(void)
965 {
966 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
967 IORegistryEntry * registryRoot = NULL;// do not release
968 OSSharedPtr<OSNumber> kernelCPUType;
969 OSSharedPtr<OSNumber> kernelCPUSubtype;
970 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
971 bool setResult = false;
972 uint64_t * timestamp = NULL;
973 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
974
975 /* This must be the first thing allocated. Everything else grabs this lock.
976 */
977 sKextLock = IORecursiveLockAlloc();
978 sKextInnerLock = IORecursiveLockAlloc();
979 sKextSummariesLock = IOLockAlloc();
980 sKextLoggingLock = IOLockAlloc();
981 assert(sKextLock);
982 assert(sKextInnerLock);
983 assert(sKextSummariesLock);
984 assert(sKextLoggingLock);
985
986 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
987 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
988 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
989 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
990 sKernelRequests = OSArray::withCapacity(0);
991 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
992 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
993 sRequestCallbackRecords = OSArray::withCapacity(0);
994 sDriverKitToUpgradeByID = OSDictionary::withCapacity(kOSKextTypicalUpgradeCount);
995
996 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
997 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
998 sRequestCallbackRecords && sUnloadedPrelinkedKexts && sDriverKitToUpgradeByID);
999
1000 /* Read the log flag boot-args and set the log flags.
1001 */
1002 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
1003 sBootArgLogFilterFound = true;
1004 sKernelLogFilter = bootLogFilter;
1005 // log this if any flags are set
1006 OSKextLog(/* kext */ NULL,
1007 kOSKextLogBasicLevel |
1008 kOSKextLogFlagsMask,
1009 "Kernel kext log filter 0x%x per kextlog boot arg.",
1010 (unsigned)sKernelLogFilter);
1011 }
1012
1013 #if !defined(__arm__) && !defined(__arm64__)
1014 /*
1015 * On our ARM targets, the kernelcache/boot kernel collection contains
1016 * the set of kexts required to boot, as specified by KCB. Safeboot is
1017 * either unsupported, or is supported by the bootloader only loading
1018 * the boot kernel collection; as a result OSKext has no role to play
1019 * in safeboot policy on ARM.
1020 */
1021 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
1022 sizeof(bootArgBuffer)) ? true : false;
1023 #endif /* defined(__arm__) && defined(__arm64__) */
1024
1025 if (sSafeBoot) {
1026 OSKextLog(/* kext */ NULL,
1027 kOSKextLogWarningLevel |
1028 kOSKextLogGeneralFlag,
1029 "SAFE BOOT DETECTED - "
1030 "only valid OSBundleRequired kexts will be loaded.");
1031 }
1032
1033 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
1034 #if CONFIG_DTRACE
1035 if (dtrace_keep_kernel_symbols()) {
1036 sKeepSymbols = true;
1037 }
1038 #endif /* CONFIG_DTRACE */
1039 #if KASAN_DYNAMIC_BLACKLIST
1040 /* needed for function lookup */
1041 sKeepSymbols = true;
1042 #endif
1043
1044 /*
1045 * Should we panic when the SystemKC is not linked against the
1046 * BootKC that was loaded by the booter? By default: yes, if the
1047 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
1048 * on mis-match and instead just print an error and continue.
1049 */
1050 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
1051 sizeof(bootArgBuffer)) ? false : true;
1052
1053 /* Set up an OSKext instance to represent the kernel itself. */
1054 sKernelKext = allocAndInitFakeKext(&g_kernel_kmod_info);
1055 assert(sKernelKext);
1056
1057 #if CONFIG_SPTM
1058 /* Set up OSKext instances to represent the SPTM/TXM. */
1059 OSKext *SPTMKext = allocAndInitFakeKext(&g_sptm_kmod_info);
1060 OSKext *TXMKext = allocAndInitFakeKext(&g_txm_kmod_info);
1061 #endif
1062
1063 /* Add the kernel kext to the bookkeeping dictionaries. Note that
1064 * the kernel kext doesn't have a kmod_info struct. copyInfo()
1065 * gathers info from other places anyhow.
1066 */
1067 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
1068 assert(setResult);
1069 setResult = sLoadedKexts->setObject(sKernelKext);
1070 assert(setResult);
1071
1072 #if CONFIG_SPTM
1073 setResult = sKextsByID->setObject(SPTMKext->bundleID.get(), SPTMKext);
1074 assert(setResult);
1075 setResult = sLoadedKexts->setObject(SPTMKext);
1076 assert(setResult);
1077
1078 setResult = sKextsByID->setObject(TXMKext->bundleID.get(), TXMKext);
1079 assert(setResult);
1080 setResult = sLoadedKexts->setObject(TXMKext);
1081 assert(setResult);
1082 #endif /* CONFIG_SPTM */
1083
1084 // XXX: better way with OSSharedPtr?
1085 // sKernelKext remains a valid pointer even after the decref
1086 sKernelKext->release();
1087 #if CONFIG_SPTM
1088 SPTMKext->release();
1089 TXMKext->release();
1090 #endif /* CONFIG_SPTM */
1091
1092 registryRoot = IORegistryEntry::getRegistryRoot();
1093 kernelCPUType = OSNumber::withNumber(
1094 (long long unsigned int)_mh_execute_header.cputype,
1095 8 * sizeof(_mh_execute_header.cputype));
1096 kernelCPUSubtype = OSNumber::withNumber(
1097 (long long unsigned int)_mh_execute_header.cpusubtype,
1098 8 * sizeof(_mh_execute_header.cpusubtype));
1099 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
1100
1101 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
1102 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
1103
1104 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
1105 if (gBuiltinKmodsSectionInfo) {
1106 uint32_t count;
1107
1108 assert(gBuiltinKmodsSectionInfo->addr);
1109 assert(gBuiltinKmodsSectionInfo->size);
1110 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
1111 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
1112
1113 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
1114 assert(gBuiltinKmodsSectionStart);
1115 assert(gBuiltinKmodsSectionStart->addr);
1116 assert(gBuiltinKmodsSectionStart->size);
1117 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
1118 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
1119 // one extra pointer for the end of last kmod
1120 assert(count == (gBuiltinKmodsCount + 1));
1121
1122 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
1123 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
1124 }
1125
1126 // Don't track this object -- it's never released
1127 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
1128
1129 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
1130 *timestamp = 0;
1131 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
1132 *timestamp = 0;
1133 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
1134 *timestamp = 0;
1135
1136 OSKextLog(/* kext */ NULL,
1137 kOSKextLogProgressLevel |
1138 kOSKextLogGeneralFlag,
1139 "Kext system initialized.");
1140
1141 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
1142 #if CONFIG_SPTM
1143 notifyKextLoadObservers(SPTMKext, SPTMKext->kmod_info);
1144 notifyKextLoadObservers(TXMKext, TXMKext->kmod_info);
1145 #endif
1146
1147 return;
1148 }
1149
1150 /*********************************************************************
1151 * This is expected to be called exactly once, from exactly one thread
1152 * context, during kernel bootstrap.
1153 *********************************************************************/
1154 /* static */
1155 OSReturn
removeKextBootstrap(void)1156 OSKext::removeKextBootstrap(void)
1157 {
1158 OSReturn result = kOSReturnError;
1159
1160 const char * dt_kernel_header_name = "Kernel-__HEADER";
1161 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
1162 kernel_mach_header_t * dt_mach_header = NULL;
1163 int dt_mach_header_size = 0;
1164 struct symtab_command * dt_symtab = NULL;
1165 int dt_symtab_size = 0;
1166 int dt_result = 0;
1167
1168 kernel_segment_command_t * seg_kld = NULL;
1169 kernel_segment_command_t * seg_klddata = NULL;
1170 kernel_segment_command_t * seg_linkedit = NULL;
1171
1172 const char __unused * dt_segment_name = NULL;
1173 void __unused * segment_paddress = NULL;
1174 int __unused segment_size = 0;
1175
1176 OSKextLog(/* kext */ NULL,
1177 kOSKextLogProgressLevel |
1178 kOSKextLogGeneralFlag,
1179 "Jettisoning kext bootstrap segments.");
1180
1181 /*
1182 * keep the linkedit segment around when booted from a new MH_FILESET
1183 * KC because all the kexts shared a linkedit segment.
1184 */
1185 kc_format_t kc_format;
1186 if (!PE_get_primary_kc_format(&kc_format)) {
1187 OSKextLog(/* kext */ NULL,
1188 kOSKextLogErrorLevel |
1189 kOSKextLogGeneralFlag,
1190 "Unable to determine primary KC format");
1191 }
1192
1193 /*****
1194 * Dispose of unnecessary stuff that the booter didn't need to load.
1195 */
1196 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1197 (void **)&dt_mach_header, &dt_mach_header_size);
1198 if (dt_result == 0 && dt_mach_header) {
1199 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1200 round_page_32(dt_mach_header_size));
1201 }
1202 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1203 (void **)&dt_symtab, &dt_symtab_size);
1204 if (dt_result == 0 && dt_symtab) {
1205 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1206 round_page_32(dt_symtab_size));
1207 }
1208
1209 /*****
1210 * KLD & KLDDATA bootstrap segments.
1211 */
1212 // xxx - should rename KLD segment
1213 seg_kld = getsegbyname("__KLD");
1214 seg_klddata = getsegbyname("__KLDDATA");
1215 if (seg_klddata) {
1216 // __mod_term_func is part of __KLDDATA
1217 OSRuntimeUnloadCPPForSegment(seg_klddata);
1218 }
1219
1220 #if __arm__ || __arm64__
1221 /* Free the memory that was set up by iBoot.
1222 */
1223 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1224 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1225 * is covered by the contiguous rorgn.
1226 */
1227 dt_segment_name = "Kernel-__KLD";
1228 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1229 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1230 (int)segment_size); // calls ml_static_mfree
1231 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1232 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1233 #if !CONFIG_SPTM
1234 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1235 seg_kld->vmsize);
1236 #else
1237 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1238 #endif
1239 }
1240 #endif
1241 dt_segment_name = "Kernel-__KLDDATA";
1242 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1243 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1244 (int)segment_size); // calls ml_static_mfree
1245 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1246 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1247 #if !CONFIG_SPTM
1248 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1249 seg_klddata->vmsize);
1250 #else
1251 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1252 #endif
1253 }
1254 #elif __i386__ || __x86_64__
1255 /* On x86, use the mapping data from the segment load command to
1256 * unload KLD & KLDDATA directly.
1257 * This may invalidate any assumptions about "avail_start"
1258 * defining the lower bound for valid physical addresses.
1259 */
1260 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1261 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1262 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1263 }
1264 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1265 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1266 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1267 }
1268 #else
1269 #error arch
1270 #endif
1271
1272 /*****
1273 * Prelinked kernel's symtab (if there is one).
1274 */
1275 if (kc_format != KCFormatFileset) {
1276 kernel_section_t * sect;
1277 sect = getsectbyname("__PRELINK", "__symtab");
1278 if (sect && sect->addr && sect->size) {
1279 ml_static_mfree(sect->addr, sect->size);
1280 }
1281 }
1282
1283 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1284
1285 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1286 * pageable, unless keepsyms is set. To do that, we have to copy it from
1287 * its booter-allocated memory, free the booter memory, reallocate proper
1288 * managed memory, then copy the segment back in.
1289 *
1290 * NOTE: This optimization is not valid for fileset KCs because each
1291 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1292 * that points to one fileset-global LINKEDIT segment. This
1293 * optimization is also only valid for platforms that support vm
1294 * mapped kexts or mapped kext collections (pageable KCs)
1295 */
1296 #if VM_MAPPED_KEXTS
1297 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1298 kern_return_t mem_result;
1299 void *seg_copy = NULL;
1300 void *seg_data = NULL;
1301 vm_map_offset_t seg_offset = 0;
1302 vm_map_offset_t seg_copy_offset = 0;
1303 vm_map_size_t seg_length = 0;
1304
1305 seg_data = (void *) seg_linkedit->vmaddr;
1306 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1307 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1308
1309 /* Allocate space for the LINKEDIT copy.
1310 */
1311 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1312 seg_length, KMA_ZERO, VM_KERN_MEMORY_KEXT);
1313 if (mem_result != KERN_SUCCESS) {
1314 OSKextLog(/* kext */ NULL,
1315 kOSKextLogErrorLevel |
1316 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1317 "Can't copy __LINKEDIT segment for VM reassign.");
1318 return result;
1319 }
1320 seg_copy_offset = (vm_map_offset_t) seg_copy;
1321
1322 /* Copy it out.
1323 */
1324 memcpy(seg_copy, seg_data, seg_length);
1325
1326 /* Dump the booter memory.
1327 */
1328 ml_static_mfree(seg_offset, seg_length);
1329
1330 /* Set up the VM region.
1331 */
1332 mem_result = mach_vm_map_kernel(
1333 kernel_map,
1334 &seg_offset,
1335 seg_length, /* mask */ 0,
1336 VM_MAP_KERNEL_FLAGS_FIXED(.vmf_overwrite = true),
1337 (ipc_port_t)NULL,
1338 (vm_object_offset_t) 0,
1339 /* copy */ FALSE,
1340 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1341 /* max_protection */ VM_PROT_ALL,
1342 /* inheritance */ VM_INHERIT_DEFAULT);
1343 if ((mem_result != KERN_SUCCESS) ||
1344 (seg_offset != (vm_map_offset_t) seg_data)) {
1345 OSKextLog(/* kext */ NULL,
1346 kOSKextLogErrorLevel |
1347 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1348 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1349 seg_data, seg_length, mem_result);
1350 return result;
1351 }
1352
1353 /* And copy it back.
1354 */
1355 memcpy(seg_data, seg_copy, seg_length);
1356
1357 /* Free the copy.
1358 */
1359 kmem_free(kernel_map, seg_copy_offset, seg_length);
1360 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1361 /* Remove the linkedit segment of the Boot KC */
1362 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1363 OSKext::jettisonFileSetLinkeditSegment(mh);
1364 }
1365 #else // !VM_MAPPED_KEXTS
1366 /*****
1367 * Dump the LINKEDIT segment, unless keepsyms is set.
1368 */
1369 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1370 dt_segment_name = "Kernel-__LINKEDIT";
1371 if (0 == IODTGetLoaderInfo(dt_segment_name,
1372 &segment_paddress, &segment_size)) {
1373 #ifdef SECURE_KERNEL
1374 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1375 bzero((void*)vmaddr, segment_size);
1376 #endif
1377 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1378 (int)segment_size);
1379 }
1380 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1381 /* Remove the linkedit segment of the Boot KC */
1382 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1383 OSKext::jettisonFileSetLinkeditSegment(mh);
1384 } else {
1385 OSKextLog(/* kext */ NULL,
1386 kOSKextLogBasicLevel |
1387 kOSKextLogGeneralFlag,
1388 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1389 }
1390 #endif // VM_MAPPED_KEXTS
1391
1392 result = kOSReturnSuccess;
1393
1394 return result;
1395 }
1396
1397 #if CONFIG_KXLD
1398 /*********************************************************************
1399 *********************************************************************/
1400 void
flushNonloadedKexts(Boolean flushPrelinkedKexts)1401 OSKext::flushNonloadedKexts(
1402 Boolean flushPrelinkedKexts)
1403 {
1404 OSSharedPtr<OSSet> keepKexts;
1405
1406 /* TODO: make this more efficient with MH_FILESET kexts */
1407
1408 // Do not unload prelinked kexts on arm because the kernelcache is not
1409 // structured in a way that allows them to be unmapped
1410 #if !defined(__x86_64__)
1411 flushPrelinkedKexts = false;
1412 #endif /* defined(__x86_64__) */
1413
1414 IORecursiveLockLock(sKextLock);
1415
1416 OSKextLog(/* kext */ NULL,
1417 kOSKextLogProgressLevel |
1418 kOSKextLogKextBookkeepingFlag,
1419 "Flushing nonloaded kexts and other unused data.");
1420
1421 OSKext::considerDestroyingLinkContext();
1422
1423 /* If we aren't flushing unused prelinked kexts, we have to put them
1424 * aside while we flush everything else so make a container for them.
1425 */
1426 keepKexts = OSSet::withCapacity(16);
1427 if (!keepKexts) {
1428 goto finish;
1429 }
1430
1431 /* Set aside prelinked kexts (in-use or not) and break
1432 * any lingering inter-kext references for nonloaded kexts
1433 * so they have min. retain counts.
1434 */
1435 {
1436 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1437 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1438 if (!thisKext) {
1439 return false;
1440 }
1441 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1442 keepKexts->setObject(thisKext);
1443 } else if (!thisKext->declaresExecutable()) {
1444 /*
1445 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1446 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1447 * flushNonloadedKexts().
1448 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1449 */
1450 keepKexts->setObject(thisKext);
1451 } else if (thisKext->isInFileset()) {
1452 /* keep all kexts in the new MH_FILESET KC */
1453 keepKexts->setObject(thisKext);
1454 }
1455
1456 thisKext->flushDependencies(/* forceIfLoaded */ false);
1457 return false;
1458 });
1459 }
1460 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1461 */
1462 sKextsByID->flushCollection();
1463
1464 /* Now put the loaded kexts back into the ID dictionary.
1465 */
1466 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1467 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1468 if (!thisKext) {
1469 return false;
1470 }
1471 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1472 return false;
1473 });
1474
1475 /* Finally, put back the kept kexts if we saved any.
1476 */
1477 keepKexts->iterateObjects(^bool (OSObject * obj) {
1478 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1479 if (!thisKext) {
1480 return false;
1481 }
1482 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1483 return false;
1484 });
1485
1486 finish:
1487 IORecursiveLockUnlock(sKextLock);
1488 return;
1489 }
1490 #else /* !CONFIG_KXLD */
1491
1492 void
flushNonloadedKexts(Boolean flushPrelinkedKexts __unused)1493 OSKext::flushNonloadedKexts(
1494 Boolean flushPrelinkedKexts __unused)
1495 {
1496 IORecursiveLockLock(sKextLock);
1497
1498 OSKextLog(/* kext */ NULL,
1499 kOSKextLogProgressLevel |
1500 kOSKextLogKextBookkeepingFlag,
1501 "Flushing dependency info for non-loaded kexts.");
1502
1503 /*
1504 * In a world where we don't dynamically link kexts, they all come
1505 * from a kext collection that's either in wired memory, or
1506 * wire-on-demand. We don't need to mess around with moving kexts in
1507 * and out of the sKextsByID array - they can all just stay there.
1508 * Here we just flush the dependency list for kexts that are not
1509 * loaded.
1510 */
1511 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1512 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1513 if (!thisKext) {
1514 return false;
1515 }
1516 thisKext->flushDependencies(/* forceIfLoaded */ false);
1517 return false;
1518 });
1519
1520 IORecursiveLockUnlock(sKextLock);
1521 return;
1522 }
1523
1524 #endif /* CONFIG_KXLD */
1525
1526 /*********************************************************************
1527 *********************************************************************/
1528 /* static */
1529 void
setIOKitDaemonActive(bool active)1530 OSKext::setIOKitDaemonActive(bool active)
1531 {
1532 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1533 IORecursiveLockLock(sKextLock);
1534 sIOKitDaemonActive = active;
1535 if (sKernelRequests->getCount()) {
1536 OSKext::pingIOKitDaemon();
1537 }
1538 IORecursiveLockUnlock(sKextLock);
1539
1540 return;
1541 }
1542
1543 /*********************************************************************
1544 * OSKextLib.cpp might need access to this someday but for now it's
1545 * private.
1546 *********************************************************************/
1547 extern "C" {
1548 extern void ipc_port_release_send(ipc_port_t);
1549 };
1550
1551 /* static */
1552 OSReturn
pingIOKitDaemon(void)1553 OSKext::pingIOKitDaemon(void)
1554 {
1555 OSReturn result = kOSReturnError;
1556 #if !NO_KEXTD
1557 mach_port_t kextd_port = IPC_PORT_NULL;
1558
1559 if (!sIOKitDaemonActive) {
1560 result = kOSKextReturnDisabled; // basically unavailable
1561 goto finish;
1562 }
1563
1564 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1565 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1566 OSKextLog(/* kext */ NULL,
1567 kOSKextLogErrorLevel |
1568 kOSKextLogIPCFlag,
1569 "Can't get " kIOKitDaemonName " port.");
1570 goto finish;
1571 }
1572
1573 result = kextd_ping(kextd_port);
1574 if (result != KERN_SUCCESS) {
1575 OSKextLog(/* kext */ NULL,
1576 kOSKextLogErrorLevel |
1577 kOSKextLogIPCFlag,
1578 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1579 goto finish;
1580 }
1581
1582 finish:
1583 if (IPC_PORT_VALID(kextd_port)) {
1584 ipc_port_release_send(kextd_port);
1585 }
1586 #endif
1587
1588 return result;
1589 }
1590
1591 /*********************************************************************
1592 *********************************************************************/
1593 /* static */
1594 bool
driverkitEnabled(void)1595 OSKext::driverkitEnabled(void)
1596 {
1597 #if XNU_TARGET_OS_WATCH
1598 return false;
1599 #else //!XNU_TARGET_OS_WATCH
1600 return true;
1601 #endif //XNU_TARGET_OS_WATCH
1602 }
1603
1604 /*********************************************************************
1605 *********************************************************************/
1606 /* static */
1607 bool
iokitDaemonAvailable(void)1608 OSKext::iokitDaemonAvailable(void)
1609 {
1610 #if !XNU_TARGET_OS_IOS && !XNU_TARGET_OS_OSX
1611 int notused;
1612 if (PE_parse_boot_argn("-restore", ¬used, sizeof(notused))) {
1613 return false;
1614 }
1615 #endif //!XNU_TARGET_OS_IOS && !XNU_TARGET_OS_OSX
1616 return driverkitEnabled();
1617 }
1618
1619 /*********************************************************************
1620 *********************************************************************/
1621 /* static */
1622 void
setDeferredLoadSucceeded(Boolean succeeded)1623 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1624 {
1625 IORecursiveLockLock(sKextLock);
1626 sDeferredLoadSucceeded = succeeded;
1627 IORecursiveLockUnlock(sKextLock);
1628
1629 return;
1630 }
1631
1632 /*********************************************************************
1633 * Called from IOSystemShutdownNotification.
1634 *********************************************************************/
1635 /* static */
1636 void
willShutdown(void)1637 OSKext::willShutdown(void)
1638 {
1639 #if !NO_KEXTD
1640 OSReturn checkResult = kOSReturnError;
1641 #endif
1642 OSSharedPtr<OSDictionary> exitRequest;
1643
1644 IORecursiveLockLock(sKextLock);
1645
1646 OSKext::setLoadEnabled(false);
1647 OSKext::setUnloadEnabled(false);
1648 OSKext::setAutounloadsEnabled(false);
1649 OSKext::setKernelRequestsEnabled(false);
1650
1651 #if defined(__x86_64__) || defined(__i386__)
1652 if (IOPMRootDomainGetWillShutdown()) {
1653 OSKext::freeKCFileSetcontrol();
1654 }
1655 #endif // (__x86_64__) || defined(__i386__)
1656
1657 #if !NO_KEXTD
1658 OSKextLog(/* kext */ NULL,
1659 kOSKextLogProgressLevel |
1660 kOSKextLogGeneralFlag,
1661 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1662
1663 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1664 exitRequest);
1665 if (checkResult != kOSReturnSuccess) {
1666 goto finish;
1667 }
1668 if (!sKernelRequests->setObject(exitRequest.get())) {
1669 goto finish;
1670 }
1671
1672 OSKext::pingIOKitDaemon();
1673
1674 finish:
1675 #endif
1676
1677 IORecursiveLockUnlock(sKextLock);
1678 return;
1679 }
1680
1681 void
willUserspaceReboot(void)1682 OSKext::willUserspaceReboot(void)
1683 {
1684 OSKext::willShutdown();
1685 IOService::userSpaceWillReboot();
1686 gIOCatalogue->terminateDriversForUserspaceReboot();
1687 }
1688
1689 void
resetAfterUserspaceReboot(void)1690 OSKext::resetAfterUserspaceReboot(void)
1691 {
1692 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1693 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1694
1695 IORecursiveLockLock(sKextLock);
1696 gIOCatalogue->resetAfterUserspaceReboot();
1697 IOService::userSpaceDidReboot();
1698 OSKext::removeDaemonExitRequests();
1699 OSKext::setLoadEnabled(true);
1700 OSKext::setUnloadEnabled(true);
1701 OSKext::setAutounloadsEnabled(true);
1702 OSKext::setKernelRequestsEnabled(true);
1703 sOSKextWasResetAfterUserspaceReboot = true;
1704 IORecursiveLockUnlock(sKextLock);
1705 }
1706
1707 extern "C" void
OSKextResetAfterUserspaceReboot(void)1708 OSKextResetAfterUserspaceReboot(void)
1709 {
1710 OSKext::resetAfterUserspaceReboot();
1711 }
1712
1713 /*
1714 * Remove daemon exit requests from sKernelRequests
1715 *
1716 * If we sent a daemon exit request during a userspace reboot and launchd
1717 * killed the IOKit daemon before it was able to dequeue the exit request, the
1718 * next time the daemon starts up it will immediately exit as it gets the old exit request.
1719 *
1720 * This removes exit requests so that this does not happen.
1721 */
1722 void
removeDaemonExitRequests(void)1723 OSKext::removeDaemonExitRequests(void)
1724 {
1725 OSDictionary * current = NULL;
1726 OSString * predicate = NULL;
1727 size_t index = 0;
1728 OSSharedPtr<const OSSymbol> predicateKey = OSSymbol::withCString(kKextRequestPredicateKey);
1729
1730 while (index < sKernelRequests->getCount()) {
1731 current = OSDynamicCast(OSDictionary, sKernelRequests->getObject(index));
1732 if (current) {
1733 predicate = OSDynamicCast(OSString, current->getObject(predicateKey.get()));
1734 if (predicate && predicate->isEqualTo(kKextRequestPredicateRequestDaemonExit)) {
1735 sKernelRequests->removeObject(index);
1736 continue;
1737 }
1738 }
1739 index++;
1740 }
1741 }
1742
1743 /*********************************************************************
1744 *********************************************************************/
1745 /* static */
1746 bool
getLoadEnabled(void)1747 OSKext::getLoadEnabled(void)
1748 {
1749 bool result;
1750
1751 IORecursiveLockLock(sKextLock);
1752 result = sLoadEnabled;
1753 IORecursiveLockUnlock(sKextLock);
1754 return result;
1755 }
1756
1757 /*********************************************************************
1758 *********************************************************************/
1759 /* static */
1760 bool
setLoadEnabled(bool flag)1761 OSKext::setLoadEnabled(bool flag)
1762 {
1763 bool result;
1764
1765 IORecursiveLockLock(sKextLock);
1766 result = sLoadEnabled;
1767 sLoadEnabled = (flag ? true : false);
1768
1769 if (sLoadEnabled != result) {
1770 OSKextLog(/* kext */ NULL,
1771 kOSKextLogBasicLevel |
1772 kOSKextLogLoadFlag,
1773 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1774 }
1775
1776 IORecursiveLockUnlock(sKextLock);
1777
1778 return result;
1779 }
1780
1781 /*********************************************************************
1782 *********************************************************************/
1783 /* static */
1784 bool
getUnloadEnabled(void)1785 OSKext::getUnloadEnabled(void)
1786 {
1787 bool result;
1788
1789 IORecursiveLockLock(sKextLock);
1790 result = sUnloadEnabled;
1791 IORecursiveLockUnlock(sKextLock);
1792 return result;
1793 }
1794
1795 /*********************************************************************
1796 *********************************************************************/
1797 /* static */
1798 bool
setUnloadEnabled(bool flag)1799 OSKext::setUnloadEnabled(bool flag)
1800 {
1801 bool result;
1802
1803 IORecursiveLockLock(sKextLock);
1804 result = sUnloadEnabled;
1805 sUnloadEnabled = (flag ? true : false);
1806 IORecursiveLockUnlock(sKextLock);
1807
1808 if (sUnloadEnabled != result) {
1809 OSKextLog(/* kext */ NULL,
1810 kOSKextLogBasicLevel |
1811 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1812 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1813 }
1814
1815 return result;
1816 }
1817
1818 /*********************************************************************
1819 * Do not call any function that takes sKextLock here!
1820 *********************************************************************/
1821 /* static */
1822 bool
getAutounloadEnabled(void)1823 OSKext::getAutounloadEnabled(void)
1824 {
1825 #if XNU_TARGET_OS_OSX
1826 bool result;
1827
1828 IORecursiveLockLock(sKextInnerLock);
1829 result = sAutounloadEnabled ? true : false;
1830 IORecursiveLockUnlock(sKextInnerLock);
1831 return result;
1832 #else
1833 return false;
1834 #endif /* XNU_TARGET_OS_OSX */
1835 }
1836
1837 /*********************************************************************
1838 * Do not call any function that takes sKextLock here!
1839 *********************************************************************/
1840 /* static */
1841 bool
setAutounloadsEnabled(bool flag)1842 OSKext::setAutounloadsEnabled(bool flag)
1843 {
1844 #if XNU_TARGET_OS_OSX
1845 bool result;
1846
1847 IORecursiveLockLock(sKextInnerLock);
1848
1849 result = sAutounloadEnabled;
1850 sAutounloadEnabled = (flag ? true : false);
1851 if (!sAutounloadEnabled && sUnloadCallout) {
1852 thread_call_cancel(sUnloadCallout);
1853 }
1854
1855 if (sAutounloadEnabled != result) {
1856 OSKextLog(/* kext */ NULL,
1857 kOSKextLogBasicLevel |
1858 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1859 "Kext autounloading now %sabled.",
1860 sAutounloadEnabled ? "en" : "dis");
1861 }
1862
1863 IORecursiveLockUnlock(sKextInnerLock);
1864
1865 return result;
1866 #else
1867 (void)flag;
1868 return false;
1869 #endif /* XNU_TARGET_OS_OSX */
1870 }
1871
1872 /*********************************************************************
1873 *********************************************************************/
1874 /* instance method operating on OSKext field */
1875 bool
setAutounloadEnabled(bool flag)1876 OSKext::setAutounloadEnabled(bool flag)
1877 {
1878 bool result = flags.autounloadEnabled ? true : false;
1879 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1880
1881 if (result != (flag ? true : false)) {
1882 OSKextLog(this,
1883 kOSKextLogProgressLevel |
1884 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1885 "Autounloading for kext %s now %sabled.",
1886 getIdentifierCString(),
1887 flags.autounloadEnabled ? "en" : "dis");
1888 }
1889 return result;
1890 }
1891
1892 /*********************************************************************
1893 *********************************************************************/
1894 /* static */
1895 bool
setKernelRequestsEnabled(bool flag)1896 OSKext::setKernelRequestsEnabled(bool flag)
1897 {
1898 bool result;
1899
1900 IORecursiveLockLock(sKextLock);
1901 result = sKernelRequestsEnabled;
1902 sKernelRequestsEnabled = flag ? true : false;
1903
1904 if (sKernelRequestsEnabled != result) {
1905 OSKextLog(/* kext */ NULL,
1906 kOSKextLogBasicLevel |
1907 kOSKextLogGeneralFlag,
1908 "Kernel requests now %sabled.",
1909 sKernelRequestsEnabled ? "en" : "dis");
1910 }
1911 IORecursiveLockUnlock(sKextLock);
1912 return result;
1913 }
1914
1915 /*********************************************************************
1916 *********************************************************************/
1917 /* static */
1918 bool
getKernelRequestsEnabled(void)1919 OSKext::getKernelRequestsEnabled(void)
1920 {
1921 bool result;
1922
1923 IORecursiveLockLock(sKextLock);
1924 result = sKernelRequestsEnabled;
1925 IORecursiveLockUnlock(sKextLock);
1926 return result;
1927 }
1928
1929 static bool
segmentIsMutable(kernel_segment_command_t * seg)1930 segmentIsMutable(kernel_segment_command_t *seg)
1931 {
1932 /* Mutable segments have to have VM_PROT_WRITE */
1933 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1934 return false;
1935 }
1936 /* Exclude the __DATA_CONST segment */
1937 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1938 return false;
1939 }
1940 /* Exclude __LINKEDIT */
1941 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1942 return false;
1943 }
1944 return true;
1945 }
1946
1947 #if PRAGMA_MARK
1948 #pragma mark Kext Life Cycle
1949 #endif
1950 /*********************************************************************
1951 *********************************************************************/
1952 OSSharedPtr<OSKext>
withPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)1953 OSKext::withPrelinkedInfoDict(
1954 OSDictionary * anInfoDict,
1955 bool doCoalescedSlides,
1956 kc_kind_t type)
1957 {
1958 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1959
1960 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1961 return NULL;
1962 }
1963
1964 return newKext;
1965 }
1966
1967 OSData *
parseDextUniqueID(OSDictionary * anInfoDict,const char * dextIDCS)1968 OSKext::parseDextUniqueID(
1969 OSDictionary * anInfoDict,
1970 const char *dextIDCS)
1971 {
1972 OSData *ret = NULL;
1973 OSData *data_duid = OSDynamicCast(OSData, anInfoDict->getObject(kOSBundleDextUniqueIdentifierKey));
1974 if (data_duid != NULL) {
1975 if (data_duid->getLength() > KOSBundleDextUniqueIdentifierMaxLength) {
1976 OSKextLog(NULL,
1977 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1978 "Dext %s DextUniqueIdentifier too long.",
1979 dextIDCS);
1980 } else {
1981 /*
1982 * If the DextUniqueID exists it should be
1983 * present also into the personalities.
1984 */
1985 setDextUniqueIDInPersonalities(anInfoDict, data_duid);
1986 ret = data_duid;
1987 }
1988 } else {
1989 OSKextLog(NULL,
1990 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1991 "Dext %s does not have a DextUniqueIdentifier",
1992 dextIDCS);
1993 }
1994 return ret;
1995 }
1996
1997 void
setDextUniqueIDInPersonalities(OSDictionary * anInfoDict,OSData * dextUniqueID)1998 OSKext::setDextUniqueIDInPersonalities(
1999 OSDictionary * anInfoDict,
2000 OSData * dextUniqueID)
2001 {
2002 OSDictionary * dextPersonalities = NULL;
2003 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
2004 OSString * personalityName = NULL;
2005
2006 dextPersonalities = OSDynamicCast(OSDictionary,
2007 anInfoDict->getObject(kIOKitPersonalitiesKey));
2008 if (!dextPersonalities || !dextPersonalities->getCount()) {
2009 return;
2010 }
2011
2012 personalitiesIterator =
2013 OSCollectionIterator::withCollection(dextPersonalities);
2014 if (!personalitiesIterator) {
2015 return;
2016 }
2017 while ((personalityName = OSDynamicCast(OSString,
2018 personalitiesIterator->getNextObject()))) {
2019 OSDictionary * personality = OSDynamicCast(OSDictionary,
2020 dextPersonalities->getObject(personalityName));
2021 if (personality) {
2022 OSObject *duid = personality->getObject(kOSBundleDextUniqueIdentifierKey);
2023 if (duid == NULL) {
2024 personality->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID);
2025 }
2026 }
2027 }
2028 }
2029 /*********************************************************************
2030 *********************************************************************/
2031 bool
initWithPrelinkedInfoDict(OSDictionary * anInfoDict,bool doCoalescedSlides,kc_kind_t type)2032 OSKext::initWithPrelinkedInfoDict(
2033 OSDictionary * anInfoDict,
2034 bool doCoalescedSlides,
2035 kc_kind_t type)
2036 {
2037 bool result = false;
2038 OSString * kextPath = NULL; // do not release
2039 OSNumber * addressNum = NULL; // reused; do not release
2040 OSNumber * lengthNum = NULL; // reused; do not release
2041 OSBoolean * scratchBool = NULL; // do not release
2042 void * data = NULL; // do not free
2043 void * srcData = NULL; // do not free
2044 OSSharedPtr<OSData> prelinkedExecutable;
2045 uint32_t length = 0; // reused
2046 uintptr_t kext_slide = PE_get_kc_slide(type);
2047 bool shouldSaveSegments = false;
2048 kc_format format = KCFormatUnknown;
2049
2050 if (!super::init()) {
2051 goto finish;
2052 }
2053
2054 /* Get the path. Don't look for an arch-specific path property.
2055 */
2056 kextPath = OSDynamicCast(OSString,
2057 anInfoDict->getObject(kPrelinkBundlePathKey));
2058
2059 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2060 goto finish;
2061 }
2062
2063 #if KASLR_KEXT_DEBUG
2064 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
2065 #endif
2066
2067 /* Also get the executable's bundle-relative path if present.
2068 * Don't look for an arch-specific path property.
2069 */
2070 executableRelPath.reset(OSDynamicCast(OSString,
2071 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
2072 userExecutableRelPath.reset(OSDynamicCast(OSString,
2073 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2074
2075 /* Don't need the paths to be in the info dictionary any more.
2076 */
2077 anInfoDict->removeObject(kPrelinkBundlePathKey);
2078 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
2079
2080 scratchBool = OSDynamicCast(OSBoolean,
2081 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2082 if (scratchBool == kOSBooleanTrue) {
2083 flags.requireExplicitLoad = 1;
2084 }
2085
2086 /* Create an OSData wrapper around the linked executable.
2087 */
2088 addressNum = OSDynamicCast(OSNumber,
2089 anInfoDict->getObject(kPrelinkExecutableLoadKey));
2090 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
2091 lengthNum = OSDynamicCast(OSNumber,
2092 anInfoDict->getObject(kPrelinkExecutableSizeKey));
2093 if (!lengthNum) {
2094 OSKextLog(this,
2095 kOSKextLogErrorLevel |
2096 kOSKextLogArchiveFlag,
2097 "Kext %s can't find prelinked kext executable size.",
2098 getIdentifierCString());
2099 return result;
2100 }
2101
2102 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2103 length = (uint32_t) (lengthNum->unsigned32BitValue());
2104
2105 #if KASLR_KEXT_DEBUG
2106 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
2107 (unsigned long)ml_static_unslide((vm_offset_t)data),
2108 (unsigned long)data,
2109 length);
2110 #endif
2111
2112 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
2113 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
2114
2115 /* If the kext's load address differs from its source address, allocate
2116 * space in the kext map at the load address and copy the kext over.
2117 */
2118 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
2119 if (addressNum) {
2120 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2121
2122 #if KASLR_KEXT_DEBUG
2123 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
2124 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
2125 (unsigned long)srcData);
2126 #endif
2127
2128 if (data != srcData) {
2129 #if __LP64__
2130 kern_return_t alloc_result;
2131
2132 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
2133 if (alloc_result != KERN_SUCCESS) {
2134 OSKextLog(this,
2135 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2136 "Failed to allocate space for prelinked kext %s.",
2137 getIdentifierCString());
2138 goto finish;
2139 }
2140 memcpy(data, srcData, length);
2141 #else
2142 OSKextLog(this,
2143 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2144 "Error: prelinked kext %s - source and load addresses "
2145 "differ on ILP32 architecture.",
2146 getIdentifierCString());
2147 goto finish;
2148 #endif /* __LP64__ */
2149 }
2150
2151 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
2152 }
2153
2154 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
2155 if (!prelinkedExecutable) {
2156 OSKextLog(this,
2157 kOSKextLogErrorLevel |
2158 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
2159 "Kext %s failed to create executable wrapper.",
2160 getIdentifierCString());
2161 goto finish;
2162 }
2163
2164 /*
2165 * Fileset KCs are mapped as a whole by iBoot.
2166 * Individual kext executables should not be unmapped
2167 * by xnu.
2168 * Doing so may result in panics like rdar://85419651
2169 */
2170 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
2171 prelinkedExecutable->setDeallocFunction(NULL);
2172 } else { // Not from a Fileset KC
2173 #if VM_MAPPED_KEXTS
2174 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
2175 #else
2176 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
2177 #endif
2178 }
2179 setLinkedExecutable(prelinkedExecutable.get());
2180 addressNum = OSDynamicCast(OSNumber,
2181 anInfoDict->getObject(kPrelinkKmodInfoKey));
2182 if (!addressNum) {
2183 OSKextLog(this,
2184 kOSKextLogErrorLevel |
2185 kOSKextLogArchiveFlag,
2186 "Kext %s can't find prelinked kext kmod_info address.",
2187 getIdentifierCString());
2188 goto finish;
2189 }
2190
2191 if (addressNum->unsigned64BitValue() != 0) {
2192 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
2193 if (kmod_info->address) {
2194 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
2195 } else {
2196 kmod_info->address = (uintptr_t)data;
2197 kmod_info->size = length;
2198 }
2199 #if KASLR_KEXT_DEBUG
2200 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
2201 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
2202 (unsigned long)kmod_info);
2203 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
2204 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
2205 (unsigned long)kmod_info->address);
2206 #endif
2207 }
2208
2209 anInfoDict->removeObject(kPrelinkKmodInfoKey);
2210 }
2211
2212 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
2213 uintptr_t builtinTextStart;
2214 uintptr_t builtinTextEnd;
2215
2216 flags.builtin = true;
2217 builtinKmodIdx = addressNum->unsigned32BitValue();
2218 assert(builtinKmodIdx < gBuiltinKmodsCount);
2219
2220 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
2221 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
2222
2223 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
2224 kmod_info->address = builtinTextStart;
2225 kmod_info->size = builtinTextEnd - builtinTextStart;
2226 }
2227
2228 /* If the plist has a UUID for an interface, save that off.
2229 */
2230 if (isInterface()) {
2231 interfaceUUID.reset(OSDynamicCast(OSData,
2232 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
2233 if (interfaceUUID) {
2234 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
2235 }
2236 }
2237
2238 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
2239 if (!result) {
2240 goto finish;
2241 }
2242
2243 kc_type = type;
2244 /* Exclude builtin and codeless kexts */
2245 if (prelinkedExecutable && kmod_info) {
2246 switch (kc_type) {
2247 case KCKindPrimary:
2248 shouldSaveSegments = (
2249 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
2250 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
2251 if (shouldSaveSegments) {
2252 flags.resetSegmentsFromImmutableCopy = 1;
2253 } else {
2254 flags.unloadUnsupported = 1;
2255 }
2256 break;
2257 case KCKindPageable:
2258 flags.resetSegmentsFromVnode = 1;
2259 break;
2260 case KCKindAuxiliary:
2261 if (!pageableKCloaded) {
2262 flags.resetSegmentsFromImmutableCopy = 1;
2263 } else if (resetAuxKCSegmentOnUnload) {
2264 flags.resetSegmentsFromVnode = 1;
2265 } else {
2266 flags.unloadUnsupported = 1;
2267 }
2268 break;
2269 default:
2270 break;
2271 }
2272 }
2273
2274 if (flags.resetSegmentsFromImmutableCopy) {
2275 /* Save a pristine copy of the mutable segments */
2276 kernel_segment_command_t *seg = NULL;
2277 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
2278
2279 savedMutableSegments = OSArray::withCapacity(0);
2280
2281 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
2282 if (!segmentIsMutable(seg)) {
2283 continue;
2284 }
2285 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
2286 uint64_t vmsize = seg->vmsize;
2287 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2288 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2289 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
2290 if (!savedSegment) {
2291 OSKextLog(this,
2292 kOSKextLogErrorLevel |
2293 kOSKextLogGeneralFlag,
2294 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
2295 result = false;
2296 goto finish;
2297 }
2298 savedMutableSegments->setObject(savedSegment);
2299 }
2300 }
2301
2302 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
2303 /*
2304 * set VM protections now, wire pages for the old style Aux KC now,
2305 * wire pages for the rest of the KC types at load time.
2306 */
2307 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
2308 if (!result) {
2309 goto finish;
2310 }
2311 }
2312
2313 flags.prelinked = true;
2314
2315 if (isDriverKit()) {
2316 dextStatistics = OSDextStatistics::create();
2317 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2318 dextLaunchedCount = 0;
2319 }
2320
2321 /* If we created a kext from prelink info,
2322 * we must be booting from a prelinked kernel.
2323 */
2324 sPrelinkBoot = true;
2325
2326 result = (registerIdentifier() == kOSKextInitialized);
2327 finish:
2328 return result;
2329 }
2330
2331 /*********************************************************************
2332 *********************************************************************/
2333 /* static */
2334 OSSharedPtr<OSKext>
withCodelessInfo(OSDictionary * anInfoDict,OSKextInitResult * result)2335 OSKext::withCodelessInfo(OSDictionary * anInfoDict, OSKextInitResult *result)
2336 {
2337 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
2338 if (!newKext) {
2339 return NULL;
2340 }
2341
2342 OSKextInitResult ret = newKext->initWithCodelessInfo(anInfoDict);
2343 if (result != NULL) {
2344 *result = ret;
2345 }
2346 if (ret != kOSKextInitialized) {
2347 return NULL;
2348 }
2349
2350 return newKext;
2351 }
2352
2353 /*********************************************************************
2354 *********************************************************************/
2355 OSKextInitResult
initWithCodelessInfo(OSDictionary * anInfoDict)2356 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2357 {
2358 OSKextInitResult result = kOSKextInitFailure;
2359 OSString * kextPath = NULL; // do not release
2360 OSBoolean * scratchBool = NULL; // do not release
2361
2362 if (anInfoDict == NULL || !super::init()) {
2363 goto finish;
2364 }
2365
2366 /*
2367 * Get the path. Don't look for an arch-specific path property.
2368 */
2369 kextPath = OSDynamicCast(OSString,
2370 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2371 if (!kextPath) {
2372 OSKextLog(NULL,
2373 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2374 "Requested codeless kext dictionary does not contain the '%s' key",
2375 kKextRequestArgumentCodelessInfoBundlePathKey);
2376 goto finish;
2377 }
2378
2379 uniquePersonalityProperties(anInfoDict);
2380
2381 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2382 goto finish;
2383 }
2384
2385 /*
2386 * This path is meant to initialize codeless kexts only. Refuse
2387 * anything that looks like it has an executable and/or declares
2388 * itself as a kernel component.
2389 */
2390 if (declaresExecutable() || isKernelComponent()) {
2391 OSKextLog(NULL,
2392 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2393 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2394 getIdentifierCString());
2395 goto finish;
2396 }
2397
2398 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2399 boolean_t updated = updateExcludeList(infoDict.get());
2400 if (updated) {
2401 OSKextLog(this,
2402 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2403 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2404 }
2405 }
2406
2407 kc_type = KCKindNone;
2408
2409 scratchBool = OSDynamicCast(OSBoolean,
2410 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2411 if (scratchBool == kOSBooleanTrue) {
2412 flags.requireExplicitLoad = 1;
2413 }
2414
2415 /* Also get the executable's bundle-relative path if present.
2416 * Don't look for an arch-specific path property.
2417 */
2418 userExecutableRelPath.reset(OSDynamicCast(OSString,
2419 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2420
2421 /* remove unnecessary paths from the info dict */
2422 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2423
2424 if (isDriverKit()) {
2425 dextStatistics = OSDextStatistics::create();
2426 dextUniqueID.reset(parseDextUniqueID(anInfoDict, getIdentifierCString()), OSRetain);
2427 dextLaunchedCount = 0;
2428 }
2429
2430 result = registerIdentifier();
2431
2432 finish:
2433 return result;
2434 }
2435
2436 /*********************************************************************
2437 *********************************************************************/
2438 /* static */
2439 void
setAllVMAttributes(void)2440 OSKext::setAllVMAttributes(void)
2441 {
2442 OSSharedPtr<OSCollectionIterator> kextIterator;
2443 const OSSymbol * thisID = NULL; // do not release
2444
2445 IORecursiveLockLock(sKextLock);
2446
2447 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2448 if (!kextIterator) {
2449 goto finish;
2450 }
2451
2452 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2453 OSKext * thisKext; // do not release
2454
2455 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2456 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2457 continue;
2458 }
2459
2460 if (!thisKext->flags.resetSegmentsFromVnode) {
2461 /*
2462 * set VM protections now, wire pages for the old style Aux KC now,
2463 * wire pages for the rest of the KC types at load time.
2464 */
2465 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2466 }
2467 }
2468
2469 finish:
2470 IORecursiveLockUnlock(sKextLock);
2471
2472 return;
2473 }
2474
2475 /*********************************************************************
2476 *********************************************************************/
2477 OSSharedPtr<OSKext>
withBooterData(OSString * deviceTreeName,OSData * booterData)2478 OSKext::withBooterData(
2479 OSString * deviceTreeName,
2480 OSData * booterData)
2481 {
2482 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2483
2484 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2485 return NULL;
2486 }
2487
2488 return newKext;
2489 }
2490
2491 /*********************************************************************
2492 *********************************************************************/
2493 typedef struct _BooterKextFileInfo {
2494 uint32_t infoDictPhysAddr;
2495 uint32_t infoDictLength;
2496 uint32_t executablePhysAddr;
2497 uint32_t executableLength;
2498 uint32_t bundlePathPhysAddr;
2499 uint32_t bundlePathLength;
2500 } _BooterKextFileInfo;
2501
2502 bool
initWithBooterData(OSString * deviceTreeName,OSData * booterData)2503 OSKext::initWithBooterData(
2504 OSString * deviceTreeName,
2505 OSData * booterData)
2506 {
2507 bool result = false;
2508 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2509 char * infoDictAddr = NULL; // do not free
2510 void * executableAddr = NULL; // do not free
2511 char * bundlePathAddr = NULL; // do not free
2512
2513 OSDictionary * theInfoDict = NULL; // do not release
2514 OSSharedPtr<OSObject> parsedXML;
2515 OSSharedPtr<OSString> kextPath;
2516
2517 OSSharedPtr<OSString> errorString;
2518 OSSharedPtr<OSData> executable;
2519
2520 if (!super::init()) {
2521 goto finish;
2522 }
2523
2524 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2525 if (!kextFileInfo) {
2526 OSKextLog(this,
2527 kOSKextLogErrorLevel |
2528 kOSKextLogGeneralFlag,
2529 "No booter-provided data for kext device tree entry %s.",
2530 deviceTreeName->getCStringNoCopy());
2531 goto finish;
2532 }
2533
2534 /* The info plist must exist or we can't read the kext.
2535 */
2536 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2537 OSKextLog(this,
2538 kOSKextLogErrorLevel |
2539 kOSKextLogGeneralFlag,
2540 "No kext info dictionary for booter device tree entry %s.",
2541 deviceTreeName->getCStringNoCopy());
2542 goto finish;
2543 }
2544
2545 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2546 if (!infoDictAddr) {
2547 OSKextLog(this,
2548 kOSKextLogErrorLevel |
2549 kOSKextLogGeneralFlag,
2550 "Can't translate physical address 0x%x of kext info dictionary "
2551 "for device tree entry %s.",
2552 (int)kextFileInfo->infoDictPhysAddr,
2553 deviceTreeName->getCStringNoCopy());
2554 goto finish;
2555 }
2556
2557 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2558 if (parsedXML) {
2559 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2560 }
2561 if (!theInfoDict) {
2562 const char * errorCString = "(unknown error)";
2563
2564 if (errorString && errorString->getCStringNoCopy()) {
2565 errorCString = errorString->getCStringNoCopy();
2566 } else if (parsedXML) {
2567 errorCString = "not a dictionary";
2568 }
2569 OSKextLog(this,
2570 kOSKextLogErrorLevel |
2571 kOSKextLogGeneralFlag,
2572 "Error unserializing info dictionary for device tree entry %s: %s.",
2573 deviceTreeName->getCStringNoCopy(), errorCString);
2574 goto finish;
2575 }
2576
2577 /* A bundle path is not mandatory.
2578 */
2579 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2580 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2581 if (!bundlePathAddr) {
2582 OSKextLog(this,
2583 kOSKextLogErrorLevel |
2584 kOSKextLogGeneralFlag,
2585 "Can't translate physical address 0x%x of kext bundle path "
2586 "for device tree entry %s.",
2587 (int)kextFileInfo->bundlePathPhysAddr,
2588 deviceTreeName->getCStringNoCopy());
2589 goto finish;
2590 }
2591 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2592
2593 kextPath = OSString::withCString(bundlePathAddr);
2594 if (!kextPath) {
2595 OSKextLog(this,
2596 kOSKextLogErrorLevel |
2597 kOSKextLogGeneralFlag,
2598 "Failed to create wrapper for device tree entry %s kext path %s.",
2599 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2600 goto finish;
2601 }
2602 }
2603
2604 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2605 goto finish;
2606 }
2607
2608 /* An executable is not mandatory.
2609 */
2610 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2611 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2612 if (!executableAddr) {
2613 OSKextLog(this,
2614 kOSKextLogErrorLevel |
2615 kOSKextLogGeneralFlag,
2616 "Can't translate physical address 0x%x of kext executable "
2617 "for device tree entry %s.",
2618 (int)kextFileInfo->executablePhysAddr,
2619 deviceTreeName->getCStringNoCopy());
2620 goto finish;
2621 }
2622
2623 executable = OSData::withBytesNoCopy(executableAddr,
2624 kextFileInfo->executableLength);
2625 if (!executable) {
2626 OSKextLog(this,
2627 kOSKextLogErrorLevel |
2628 kOSKextLogGeneralFlag,
2629 "Failed to create executable wrapper for device tree entry %s.",
2630 deviceTreeName->getCStringNoCopy());
2631 goto finish;
2632 }
2633
2634 /* A kext with an executable needs to retain the whole booterData
2635 * object to keep the executable in memory.
2636 */
2637 if (!setExecutable(executable.get(), booterData)) {
2638 OSKextLog(this,
2639 kOSKextLogErrorLevel |
2640 kOSKextLogGeneralFlag,
2641 "Failed to set kext executable for device tree entry %s.",
2642 deviceTreeName->getCStringNoCopy());
2643 goto finish;
2644 }
2645 }
2646
2647 if (isDriverKit()) {
2648 dextStatistics = OSDextStatistics::create();
2649 dextUniqueID.reset(parseDextUniqueID(theInfoDict, getIdentifierCString()), OSRetain);
2650 dextLaunchedCount = 0;
2651 }
2652
2653 result = (registerIdentifier() == kOSKextInitialized);
2654
2655 finish:
2656 return result;
2657 }
2658
2659 /*********************************************************************
2660 *********************************************************************/
2661 OSKextInitResult
registerIdentifier(void)2662 OSKext::registerIdentifier(void)
2663 {
2664 OSKextInitResult result = kOSKextInitFailure;
2665 OSKext * existingKext = NULL; // do not release
2666 bool existingIsLoaded = false;
2667 bool existingIsPrelinked = false;
2668 bool existingIsCodeless = false;
2669 bool existingIsDext = false;
2670 OSKextVersion newVersion = -1;
2671 OSKextVersion existingVersion = -1;
2672 char newVersionCString[kOSKextVersionMaxLength];
2673 char existingVersionCString[kOSKextVersionMaxLength];
2674 OSSharedPtr<OSData> newUUID;
2675 OSSharedPtr<OSData> existingUUID;
2676 const char *newDextUniqueIDCString = NULL;
2677 const char *existingDextUniqueIDCString = NULL;
2678 unsigned int newDextUniqueIDCStringSize = 0;
2679 unsigned int existingDextUniqueIDCStringSize = 0;
2680
2681 IORecursiveLockLock(sKextLock);
2682
2683 /* Get the new kext's version for checks & log messages.
2684 */
2685 newVersion = getVersion();
2686 OSKextVersionGetString(newVersion, newVersionCString,
2687 kOSKextVersionMaxLength);
2688
2689 /* If we don't have an existing kext with this identifier,
2690 * just record the new kext and we're done!
2691 */
2692 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2693 if (!existingKext) {
2694 sKextsByID->setObject(bundleID.get(), this);
2695 result = kOSKextInitialized;
2696 goto finish;
2697 }
2698
2699 /* Get the existing kext's version for checks & log messages.
2700 */
2701 existingVersion = existingKext->getVersion();
2702 OSKextVersionGetString(existingVersion,
2703 existingVersionCString, kOSKextVersionMaxLength);
2704
2705 existingIsLoaded = existingKext->isLoaded();
2706 existingIsPrelinked = existingKext->isPrelinked();
2707 existingIsDext = existingKext->isDriverKit();
2708 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2709
2710 /*
2711 * Check if we are trying to upgrade a dext
2712 * with another dext.
2713 */
2714 if (isDriverKit() && existingIsDext) {
2715 OSData *newDextUID = getDextUniqueID();
2716 if (!newDextUID) {
2717 OSKextLog(this,
2718 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2719 "New dext %s, v%s requested does not have a unique dext identifier\n",
2720 getIdentifierCString(), newVersionCString);
2721 goto finish;
2722 }
2723 newDextUniqueIDCString = getDextUniqueIDCString(newDextUID, &newDextUniqueIDCStringSize);
2724 assert(newDextUniqueIDCString != NULL);
2725
2726 OSData *existingDextUID = existingKext->getDextUniqueID();
2727 if (!existingDextUID) {
2728 OSKextLog(this,
2729 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2730 "Found a dext %s, v%s: with no unique dext identifier\n",
2731 existingKext->getIdentifierCString(), existingVersionCString);
2732 goto finish;
2733 }
2734 existingDextUniqueIDCString = getDextUniqueIDCString(existingDextUID, &existingDextUniqueIDCStringSize);
2735 assert(existingDextUniqueIDCString != NULL);
2736
2737 /*
2738 * We might get multiple requests to save the same dext.
2739 * Check if we already have saved it or if this is an upgrade
2740 * for a dext with the same BundleID.
2741 * Dexts are uniquely identified by DextUniqueID, if a new DextUniqueID
2742 * is requested for a BundleID we are going to upgrade to the newest
2743 * received irrespective from the dext version.
2744 */
2745 if (newDextUID->isEqualTo(existingDextUID) && existingKext->flags.dextToReplace == 0) {
2746 OSKextLog(this,
2747 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2748 "Refusing new dext %s, v%s:"
2749 "a dext v %s with the same unique dext identifier (%s) already exists\n",
2750 getIdentifierCString(), newVersionCString,
2751 existingVersionCString, newDextUniqueIDCString);
2752 result = kOSKextAlreadyExist;
2753 goto finish;
2754 }
2755
2756 bool upgraded = upgradeDext(existingKext, this);
2757 if (upgraded) {
2758 /* If the dext was upgraded existingKext might have been deallocated */
2759 existingKext = NULL;
2760 OSKextLog(this,
2761 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2762 "Dext %s, v%s , unique dext identifier %s "
2763 "Upgraded to v%s, unique dext identifier %s \n",
2764 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2765 newVersionCString, newDextUniqueIDCString);
2766 result = kOSKextInitialized;
2767 } else {
2768 OSKextLog(this,
2769 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2770 "Upgrade delayed for %s v%s, unique dext identifier %s "
2771 "with v%s, unique dext identifier %s.\n",
2772 getIdentifierCString(), existingVersionCString, existingDextUniqueIDCString,
2773 newVersionCString, newDextUniqueIDCString);
2774 result = kOSKextAlreadyExist;
2775 }
2776
2777 goto finish;
2778 }
2779
2780 /* If we have a non-codeless kext with this identifier that's already
2781 * loaded/prelinked, we can't use the new one, but let's be really
2782 * thorough and check how the two are related for a precise diagnostic
2783 * log message.
2784 *
2785 * This check is valid for kexts that declare an executable and for
2786 * dexts, but not for codeless kexts - we can just replace those.
2787 */
2788 if ((!existingIsCodeless || existingIsDext) &&
2789 (existingIsLoaded || existingIsPrelinked)) {
2790 bool sameVersion = (newVersion == existingVersion);
2791 bool sameExecutable = true; // assume true unless we have UUIDs
2792
2793 /* Only get the UUID if the existing kext is loaded. Doing so
2794 * might have to uncompress an mkext executable and we shouldn't
2795 * take that hit when neither kext is loaded.
2796 *
2797 * Note: there is no decompression that happens when all kexts
2798 * are loaded from kext collecitons.
2799 */
2800 newUUID = copyUUID();
2801 existingUUID = existingKext->copyUUID();
2802
2803 if (existingIsDext && !isDriverKit()) {
2804 OSKextLog(this,
2805 kOSKextLogWarningLevel |
2806 kOSKextLogKextBookkeepingFlag,
2807 "Notice - new kext %s, v%s matches a %s dext"
2808 "with the same bundle ID, v%s.",
2809 getIdentifierCString(), newVersionCString,
2810 (existingIsLoaded ? "loaded" : "prelinked"),
2811 existingVersionCString);
2812 goto finish;
2813 }
2814
2815 /* I'm entirely too paranoid about checking equivalence of executables,
2816 * but I remember nasty problems with it in the past.
2817 *
2818 * - If we have UUIDs for both kexts, compare them.
2819 * - If only one kext has a UUID, they're definitely different.
2820 */
2821 if (newUUID && existingUUID) {
2822 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2823 } else if (newUUID || existingUUID) {
2824 sameExecutable = false;
2825 }
2826
2827 if (!newUUID && !existingUUID) {
2828 /* If there are no UUIDs, we can't really tell that the executables
2829 * are *different* without a lot of work; the loaded kext's
2830 * unrelocated executable is no longer around (and we never had it
2831 * in-kernel for a prelinked kext). We certainly don't want to do
2832 * a whole fake link for the new kext just to compare, either.
2833 */
2834 OSKextLog(this,
2835 kOSKextLogWarningLevel |
2836 kOSKextLogKextBookkeepingFlag,
2837 "Notice - new kext %s, v%s matches %s kext "
2838 "but can't determine if executables are the same (no UUIDs).",
2839 getIdentifierCString(),
2840 newVersionCString,
2841 (existingIsLoaded ? "loaded" : "prelinked"));
2842 }
2843
2844 if (sameVersion && sameExecutable) {
2845 OSKextLog(this,
2846 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2847 kOSKextLogKextBookkeepingFlag,
2848 "Refusing new kext %s, v%s: a %s copy is already present "
2849 "(same version and executable).",
2850 getIdentifierCString(), newVersionCString,
2851 (existingIsLoaded ? "loaded" : "prelinked"));
2852 } else {
2853 if (!sameVersion) {
2854 /* This condition is significant so log it under warnings.
2855 */
2856 OSKextLog(this,
2857 kOSKextLogWarningLevel |
2858 kOSKextLogKextBookkeepingFlag,
2859 "Refusing new kext %s, v%s: already have %s v%s.",
2860 getIdentifierCString(),
2861 newVersionCString,
2862 (existingIsLoaded ? "loaded" : "prelinked"),
2863 existingVersionCString);
2864 } else {
2865 /* This condition is significant so log it under warnings.
2866 */
2867 OSKextLog(this,
2868 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2869 "Refusing new kext %s, v%s: a %s copy with a different "
2870 "executable UUID is already present.",
2871 getIdentifierCString(), newVersionCString,
2872 (existingIsLoaded ? "loaded" : "prelinked"));
2873 }
2874 }
2875 goto finish;
2876 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2877
2878 /* Refuse to allow an existing loaded codeless kext be replaced by a
2879 * normal kext with the same bundle ID.
2880 */
2881 if (existingIsCodeless && declaresExecutable()) {
2882 OSKextLog(this,
2883 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2884 "Refusing new kext %s, v%s: a codeless copy is already %s",
2885 getIdentifierCString(), newVersionCString,
2886 (existingIsLoaded ? "loaded" : "prelinked"));
2887 goto finish;
2888 }
2889
2890 /* Dexts packaged in the BootKC will be protected against replacement
2891 * by non-dexts by the logic above which checks if they are prelinked.
2892 * Dexts which are prelinked into the System KC will be registered
2893 * before any other kexts in the AuxKC are registered, and we never
2894 * put dexts in the AuxKC. Therefore, there is no need to check if an
2895 * existing object is a dext and is being replaced by a non-dext.
2896 * The scenario cannot happen by construction.
2897 *
2898 * See: OSKext::loadFileSetKexts()
2899 */
2900
2901
2902 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2903 * user loads are happening or if we're still in early boot. User agents are
2904 * supposed to resolve dependencies topside and include only the exact
2905 * kexts needed; so we always accept the new kext (in fact we should never
2906 * see an older unloaded copy hanging around).
2907 */
2908 if (sUserLoadsActive) {
2909 sKextsByID->setObject(bundleID.get(), this);
2910 result = kOSKextInitialized;
2911
2912 OSKextLog(this,
2913 kOSKextLogStepLevel |
2914 kOSKextLogKextBookkeepingFlag,
2915 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2916 getIdentifierCString(),
2917 existingVersionCString,
2918 newVersionCString);
2919
2920 goto finish;
2921 }
2922
2923 /* During early boot, the kext with the highest version always wins out.
2924 * Prelinked kernels will never hit this, but mkexts and booter-read
2925 * kexts might have duplicates.
2926 */
2927 if (newVersion > existingVersion) {
2928 sKextsByID->setObject(bundleID.get(), this);
2929 result = kOSKextInitialized;
2930
2931 OSKextLog(this,
2932 kOSKextLogStepLevel |
2933 kOSKextLogKextBookkeepingFlag,
2934 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2935 existingVersionCString,
2936 getIdentifierCString(),
2937 newVersionCString);
2938 } else {
2939 OSKextLog(this,
2940 kOSKextLogStepLevel |
2941 kOSKextLogKextBookkeepingFlag,
2942 "Kext %s is already registered with a higher/same version (v%s); "
2943 "dropping newly-added (v%s).",
2944 getIdentifierCString(),
2945 existingVersionCString,
2946 newVersionCString);
2947 }
2948
2949 /* result has been set appropriately by now. */
2950
2951 finish:
2952
2953 IORecursiveLockUnlock(sKextLock);
2954
2955 if (newDextUniqueIDCString != NULL) {
2956 kfree_data(newDextUniqueIDCString, newDextUniqueIDCStringSize);
2957 }
2958 if (existingDextUniqueIDCString != NULL) {
2959 kfree_data(existingDextUniqueIDCString, existingDextUniqueIDCStringSize);
2960 }
2961
2962 if (result == kOSKextInitialized) {
2963 OSKextLog(this,
2964 kOSKextLogStepLevel |
2965 kOSKextLogKextBookkeepingFlag,
2966 "Kext %s, v%s registered and available for loading.",
2967 getIdentifierCString(), newVersionCString);
2968 }
2969
2970 return result;
2971 }
2972
2973 /*********************************************************************
2974 * Does the bare minimum validation to look up a kext.
2975 * All other validation is done on the spot as needed.
2976 **********************************************************************/
2977 bool
setInfoDictionaryAndPath(OSDictionary * aDictionary,OSString * aPath)2978 OSKext::setInfoDictionaryAndPath(
2979 OSDictionary * aDictionary,
2980 OSString * aPath)
2981 {
2982 bool result = false;
2983 OSString * bundleIDString = NULL; // do not release
2984 OSString * versionString = NULL; // do not release
2985 OSString * compatibleVersionString = NULL; // do not release
2986 const char * versionCString = NULL; // do not free
2987 const char * compatibleVersionCString = NULL; // do not free
2988 OSBoolean * scratchBool = NULL; // do not release
2989 OSDictionary * scratchDict = NULL; // do not release
2990
2991 if (infoDict) {
2992 panic("Attempt to set info dictionary on a kext "
2993 "that already has one (%s).",
2994 getIdentifierCString());
2995 }
2996
2997 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2998 goto finish;
2999 }
3000
3001 infoDict.reset(aDictionary, OSRetain);
3002
3003 /* Check right away if the info dictionary has any log flags.
3004 */
3005 scratchBool = OSDynamicCast(OSBoolean,
3006 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
3007 if (scratchBool == kOSBooleanTrue) {
3008 flags.loggingEnabled = 1;
3009 }
3010
3011 /* The very next thing to get is the bundle identifier. Unlike
3012 * in user space, a kext with no bundle identifier gets axed
3013 * immediately.
3014 */
3015 bundleIDString = OSDynamicCast(OSString,
3016 getPropertyForHostArch(kCFBundleIdentifierKey));
3017 if (!bundleIDString) {
3018 OSKextLog(this,
3019 kOSKextLogErrorLevel |
3020 kOSKextLogValidationFlag,
3021 "CFBundleIdentifier missing/invalid type in kext %s.",
3022 aPath ? aPath->getCStringNoCopy() : "(unknown)");
3023 goto finish;
3024 }
3025 bundleID = OSSymbol::withString(bundleIDString);
3026 if (!bundleID) {
3027 OSKextLog(this,
3028 kOSKextLogErrorLevel |
3029 kOSKextLogValidationFlag,
3030 "Can't copy bundle identifier as symbol for kext %s.",
3031 bundleIDString->getCStringNoCopy());
3032 goto finish;
3033 }
3034
3035 /* Save the path if we got one (it should always be available but it's
3036 * just something nice to have for bookkeeping).
3037 */
3038 if (aPath) {
3039 path.reset(aPath, OSRetain);
3040 }
3041
3042 /*****
3043 * Minimal validation to initialize. We'll do other validation on the spot.
3044 */
3045 if (bundleID->getLength() >= KMOD_MAX_NAME) {
3046 OSKextLog(this,
3047 kOSKextLogErrorLevel |
3048 kOSKextLogValidationFlag,
3049 "Kext %s error - CFBundleIdentifier over max length %d.",
3050 getIdentifierCString(), KMOD_MAX_NAME - 1);
3051 goto finish;
3052 }
3053
3054 version = compatibleVersion = -1;
3055
3056 versionString = OSDynamicCast(OSString,
3057 getPropertyForHostArch(kCFBundleVersionKey));
3058 if (!versionString) {
3059 OSKextLog(this,
3060 kOSKextLogErrorLevel |
3061 kOSKextLogValidationFlag,
3062 "Kext %s error - CFBundleVersion missing/invalid type.",
3063 getIdentifierCString());
3064 goto finish;
3065 }
3066 versionCString = versionString->getCStringNoCopy();
3067 version = OSKextParseVersionString(versionCString);
3068 if (version < 0) {
3069 OSKextLog(this,
3070 kOSKextLogErrorLevel |
3071 kOSKextLogValidationFlag,
3072 "Kext %s error - CFBundleVersion bad value '%s'.",
3073 getIdentifierCString(), versionCString);
3074 goto finish;
3075 }
3076
3077 compatibleVersion = -1; // set to illegal value for kexts that don't have
3078
3079 compatibleVersionString = OSDynamicCast(OSString,
3080 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
3081 if (compatibleVersionString) {
3082 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
3083 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
3084 if (compatibleVersion < 0) {
3085 OSKextLog(this,
3086 kOSKextLogErrorLevel |
3087 kOSKextLogValidationFlag,
3088 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
3089 getIdentifierCString(), compatibleVersionCString);
3090 goto finish;
3091 }
3092
3093 if (compatibleVersion > version) {
3094 OSKextLog(this,
3095 kOSKextLogErrorLevel |
3096 kOSKextLogValidationFlag,
3097 "Kext %s error - %s %s > %s %s (must be <=).",
3098 getIdentifierCString(),
3099 kOSBundleCompatibleVersionKey, compatibleVersionCString,
3100 kCFBundleVersionKey, versionCString);
3101 goto finish;
3102 }
3103 }
3104
3105 /* Check to see if this kext is in exclude list */
3106 if (isInExcludeList()) {
3107 OSKextLog(this,
3108 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3109 "Kext %s is in exclude list, not loadable",
3110 getIdentifierCString());
3111 goto finish;
3112 }
3113
3114 /* Set flags for later use if the infoDict gets flushed. We only
3115 * check for true values, not false ones(!)
3116 */
3117 scratchBool = OSDynamicCast(OSBoolean,
3118 getPropertyForHostArch(kOSBundleIsInterfaceKey));
3119 if (scratchBool == kOSBooleanTrue) {
3120 flags.interface = 1;
3121 }
3122
3123 scratchBool = OSDynamicCast(OSBoolean,
3124 getPropertyForHostArch(kOSKernelResourceKey));
3125 if (scratchBool == kOSBooleanTrue) {
3126 flags.kernelComponent = 1;
3127 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
3128 flags.started = 1;
3129
3130 /* A kernel component has one implicit dependency on the kernel.
3131 */
3132 flags.hasAllDependencies = 1;
3133 }
3134
3135 /* Make sure common string values in personalities are uniqued to OSSymbols.
3136 */
3137 scratchDict = OSDynamicCast(OSDictionary,
3138 getPropertyForHostArch(kIOKitPersonalitiesKey));
3139 if (scratchDict) {
3140 uniquePersonalityProperties(scratchDict);
3141 }
3142
3143 result = true;
3144
3145 finish:
3146
3147 return result;
3148 }
3149
3150 /*********************************************************************
3151 * Not used for prelinked kernel boot as there is no unrelocated
3152 * executable.
3153 *********************************************************************/
3154 bool
setExecutable(OSData * anExecutable,OSData * externalData,bool externalDataIsMkext)3155 OSKext::setExecutable(
3156 OSData * anExecutable,
3157 OSData * externalData,
3158 bool externalDataIsMkext)
3159 {
3160 bool result = false;
3161 const char * executableKey = NULL; // do not free
3162
3163 if (!anExecutable) {
3164 infoDict->removeObject(_kOSKextExecutableKey);
3165 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
3166 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
3167 result = true;
3168 goto finish;
3169 }
3170
3171 if (infoDict->getObject(_kOSKextExecutableKey) ||
3172 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
3173 panic("Attempt to set an executable on a kext "
3174 "that already has one (%s).",
3175 getIdentifierCString());
3176 goto finish;
3177 }
3178
3179 if (externalDataIsMkext) {
3180 executableKey = _kOSKextMkextExecutableReferenceKey;
3181 } else {
3182 executableKey = _kOSKextExecutableKey;
3183 }
3184
3185 if (anExecutable) {
3186 infoDict->setObject(executableKey, anExecutable);
3187 if (externalData) {
3188 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
3189 }
3190 }
3191
3192 result = true;
3193
3194 finish:
3195 return result;
3196 }
3197
3198 /*********************************************************************
3199 *********************************************************************/
3200 static void
uniqueStringPlistProperty(OSDictionary * dict,const char * key)3201 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
3202 {
3203 OSObject * value = NULL; // do not release
3204 OSString * stringValue = NULL; // do not release
3205 OSSharedPtr<const OSSymbol> symbolValue;
3206
3207 value = dict->getObject(key);
3208 if (!value) {
3209 goto finish;
3210 }
3211 if (OSDynamicCast(OSSymbol, value)) {
3212 /* this is already an OSSymbol: we're good */
3213 goto finish;
3214 }
3215
3216 stringValue = OSDynamicCast(OSString, value);
3217 if (!stringValue) {
3218 goto finish;
3219 }
3220
3221 symbolValue = OSSymbol::withString(stringValue);
3222 if (!symbolValue) {
3223 goto finish;
3224 }
3225
3226 dict->setObject(key, symbolValue.get());
3227
3228 finish:
3229 return;
3230 }
3231
3232 /*********************************************************************
3233 *********************************************************************/
3234 static void
uniqueStringPlistProperty(OSDictionary * dict,const OSString * key)3235 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
3236 {
3237 OSObject * value = NULL; // do not release
3238 OSString * stringValue = NULL; // do not release
3239 OSSharedPtr<const OSSymbol> symbolValue;
3240
3241 value = dict->getObject(key);
3242 if (!value) {
3243 goto finish;
3244 }
3245 if (OSDynamicCast(OSSymbol, value)) {
3246 /* this is already an OSSymbol: we're good */
3247 goto finish;
3248 }
3249
3250 stringValue = OSDynamicCast(OSString, value);
3251 if (!stringValue) {
3252 goto finish;
3253 }
3254
3255 symbolValue = OSSymbol::withString(stringValue);
3256 if (!symbolValue) {
3257 goto finish;
3258 }
3259
3260 dict->setObject(key, symbolValue.get());
3261
3262 finish:
3263 return;
3264 }
3265
3266 void
uniquePersonalityProperties(OSDictionary * personalityDict)3267 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
3268 {
3269 OSKext::uniquePersonalityProperties(personalityDict, true);
3270 }
3271
3272 /*********************************************************************
3273 * Replace common personality property values with uniqued instances
3274 * to save on wired memory.
3275 *********************************************************************/
3276 /* static */
3277 void
uniquePersonalityProperties(OSDictionary * personalityDict,bool defaultAddKernelBundleIdentifier)3278 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
3279 {
3280 /* Properties every personality has.
3281 */
3282 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
3283 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
3284 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
3285 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
3286 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
3287 } else if (defaultAddKernelBundleIdentifier) {
3288 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
3289 }
3290
3291 /* Other commonly used properties.
3292 */
3293 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
3294 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
3295 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
3296
3297 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
3298 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
3299 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
3300 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
3301 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
3302 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
3303 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
3304 uniqueStringPlistProperty(personalityDict, "Vendor");
3305 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
3306 uniqueStringPlistProperty(personalityDict, "Vendor Name");
3307 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
3308 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
3309 uniqueStringPlistProperty(personalityDict, "idProduct");
3310
3311 return;
3312 }
3313
3314 /*********************************************************************
3315 *********************************************************************/
3316 void
free(void)3317 OSKext::free(void)
3318 {
3319 if (isLoaded()) {
3320 panic("Attempt to free loaded kext %s.", getIdentifierCString());
3321 }
3322
3323 if (isDriverKit()) {
3324 if (dextLaunchedCount > 0) {
3325 panic("Freeing dext %s but dextLaunchedCount is %d\n", getIdentifierCString(), dextLaunchedCount);
3326 }
3327 }
3328
3329 infoDict.reset();
3330 bundleID.reset();
3331 path.reset();
3332 executableRelPath.reset();
3333 userExecutableRelPath.reset();
3334 dependencies.reset();
3335 linkedExecutable.reset();
3336 metaClasses.reset();
3337 interfaceUUID.reset();
3338 driverKitUUID.reset();
3339 dextStatistics.reset();
3340 dextUniqueID.reset();
3341
3342 if (isInterface() && kmod_info) {
3343 kfree_type(kmod_info_t, kmod_info);
3344 }
3345
3346 super::free();
3347 return;
3348 }
3349
3350 #if PRAGMA_MARK
3351 #pragma mark Mkext files
3352 #endif
3353
3354 #if CONFIG_KXLD
3355 /*
3356 * mkext archives are really only relevant on kxld-enabled kernels.
3357 * Without a dynamic kernel linker, we don't need to support any mkexts.
3358 */
3359
3360 /*********************************************************************
3361 *********************************************************************/
3362 OSReturn
readMkextArchive(OSData * mkextData,uint32_t * checksumPtr)3363 OSKext::readMkextArchive(OSData * mkextData,
3364 uint32_t * checksumPtr)
3365 {
3366 OSReturn result = kOSKextReturnBadData;
3367 uint32_t mkextLength = 0;
3368 mkext_header * mkextHeader = NULL; // do not free
3369 uint32_t mkextVersion = 0;
3370
3371 /* Note default return of kOSKextReturnBadData above.
3372 */
3373 mkextLength = mkextData->getLength();
3374 if (mkextLength < sizeof(mkext_basic_header)) {
3375 OSKextLog(/* kext */ NULL,
3376 kOSKextLogErrorLevel |
3377 kOSKextLogArchiveFlag,
3378 "Mkext archive too small to be valid.");
3379 goto finish;
3380 }
3381
3382 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
3383
3384 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
3385 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
3386 OSKextLog(/* kext */ NULL,
3387 kOSKextLogErrorLevel |
3388 kOSKextLogArchiveFlag,
3389 "Mkext archive has invalid magic or signature.");
3390 goto finish;
3391 }
3392
3393 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
3394 OSKextLog(/* kext */ NULL,
3395 kOSKextLogErrorLevel |
3396 kOSKextLogArchiveFlag,
3397 "Mkext archive recorded length doesn't match actual file length.");
3398 goto finish;
3399 }
3400
3401 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3402
3403 if (mkextVersion == MKEXT_VERS_2) {
3404 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
3405 } else {
3406 OSKextLog(/* kext */ NULL,
3407 kOSKextLogErrorLevel |
3408 kOSKextLogArchiveFlag,
3409 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
3410 result = kOSKextReturnUnsupported;
3411 }
3412
3413 finish:
3414 return result;
3415 }
3416
3417 /*********************************************************************
3418 * Assumes magic, signature, version, length have been checked.
3419 * xxx - need to add further bounds checking for each file entry
3420 *
3421 * Should keep track of all kexts created so far, and if we hit a
3422 * fatal error halfway through, remove those kexts. If we've dropped
3423 * an older version that had already been read, whoops! Might want to
3424 * add a level of buffering?
3425 *********************************************************************/
3426 /* static */
3427 OSReturn
readMkext2Archive(OSData * mkextData,OSDictionary ** mkextPlistOut,uint32_t * checksumPtr)3428 OSKext::readMkext2Archive(
3429 OSData * mkextData,
3430 OSDictionary ** mkextPlistOut,
3431 uint32_t * checksumPtr)
3432 {
3433 OSReturn result = kOSReturnError;
3434 uint32_t mkextLength;
3435 mkext2_header * mkextHeader = NULL; // do not free
3436 void * mkextEnd = NULL; // do not free
3437 uint32_t mkextVersion;
3438 uint8_t * crc_address = NULL;
3439 size_t crc_buffer_size = 0;
3440 uint32_t checksum;
3441 uint32_t mkextPlistOffset;
3442 uint32_t mkextPlistCompressedSize;
3443 char * mkextPlistEnd = NULL; // do not free
3444 uint32_t mkextPlistFullSize;
3445 OSSharedPtr<OSString> errorString;
3446 OSSharedPtr<OSData> mkextPlistUncompressedData;
3447 const char * mkextPlistDataBuffer = NULL; // do not free
3448 OSSharedPtr<OSObject> parsedXML;
3449 OSDictionary * mkextPlist = NULL; // do not release
3450 OSArray * mkextInfoDictArray = NULL; // do not release
3451 uint32_t count, i;
3452 kc_format_t kc_format;
3453
3454 if (!PE_get_primary_kc_format(&kc_format)) {
3455 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3456 "Unable to determine primary KC format");
3457 goto finish;
3458 }
3459
3460 mkextLength = mkextData->getLength();
3461 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3462 mkextEnd = (char *)mkextHeader + mkextLength;
3463 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3464
3465 crc_address = (u_int8_t *)&mkextHeader->version;
3466 crc_buffer_size = (uintptr_t)mkextHeader +
3467 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3468 if (crc_buffer_size > INT32_MAX) {
3469 OSKextLog(/* kext */ NULL,
3470 kOSKextLogErrorLevel |
3471 kOSKextLogArchiveFlag,
3472 "Mkext archive size is too large (%lu > INT32_MAX).",
3473 crc_buffer_size);
3474 result = kOSKextReturnBadData;
3475 goto finish;
3476 }
3477 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3478
3479 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3480 OSKextLog(/* kext */ NULL,
3481 kOSKextLogErrorLevel |
3482 kOSKextLogArchiveFlag,
3483 "Mkext archive has bad checksum.");
3484 result = kOSKextReturnBadData;
3485 goto finish;
3486 }
3487
3488 if (checksumPtr) {
3489 *checksumPtr = checksum;
3490 }
3491
3492 /* Check that the CPU type & subtype match that of the running kernel. */
3493 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3494 OSKextLog(/* kext */ NULL,
3495 kOSKextLogErrorLevel |
3496 kOSKextLogArchiveFlag,
3497 "Mkext archive must have a specific CPU type.");
3498 result = kOSKextReturnBadData;
3499 goto finish;
3500 } else {
3501 if ((UInt32)_mh_execute_header.cputype !=
3502 MKEXT_GET_CPUTYPE(mkextHeader)) {
3503 OSKextLog(/* kext */ NULL,
3504 kOSKextLogErrorLevel |
3505 kOSKextLogArchiveFlag,
3506 "Mkext archive does not match the running kernel's CPU type.");
3507 result = kOSKextReturnArchNotFound;
3508 goto finish;
3509 }
3510 }
3511
3512 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3513 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3514 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3515 mkextPlistCompressedSize;
3516 if (mkextPlistEnd > mkextEnd) {
3517 OSKextLog(/* kext */ NULL,
3518 kOSKextLogErrorLevel |
3519 kOSKextLogArchiveFlag,
3520 "Mkext archive file overrun.");
3521 result = kOSKextReturnBadData;
3522 }
3523
3524 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3525 if (mkextPlistCompressedSize) {
3526 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3527 (UInt8 *)mkextHeader + mkextPlistOffset,
3528 "plist",
3529 mkextPlistCompressedSize, mkextPlistFullSize);
3530 if (!mkextPlistUncompressedData) {
3531 goto finish;
3532 }
3533 mkextPlistDataBuffer = (const char *)
3534 mkextPlistUncompressedData->getBytesNoCopy();
3535 } else {
3536 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3537 }
3538
3539 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3540 */
3541 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3542 if (parsedXML) {
3543 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3544 }
3545 if (!mkextPlist) {
3546 const char * errorCString = "(unknown error)";
3547
3548 if (errorString && errorString->getCStringNoCopy()) {
3549 errorCString = errorString->getCStringNoCopy();
3550 } else if (parsedXML) {
3551 errorCString = "not a dictionary";
3552 }
3553 OSKextLog(/* kext */ NULL,
3554 kOSKextLogErrorLevel |
3555 kOSKextLogArchiveFlag,
3556 "Error unserializing mkext plist: %s.", errorCString);
3557 goto finish;
3558 }
3559
3560 mkextInfoDictArray = OSDynamicCast(OSArray,
3561 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3562 if (!mkextInfoDictArray) {
3563 OSKextLog(/* kext */ NULL,
3564 kOSKextLogErrorLevel |
3565 kOSKextLogArchiveFlag,
3566 "Mkext archive contains no kext info dictionaries.");
3567 goto finish;
3568 }
3569
3570 count = mkextInfoDictArray->getCount();
3571 for (i = 0; i < count; i++) {
3572 OSDictionary * infoDict;
3573
3574
3575 infoDict = OSDynamicCast(OSDictionary,
3576 mkextInfoDictArray->getObject(i));
3577
3578 /* Create the kext for the entry, then release it, because the
3579 * kext system keeps them around until explicitly removed.
3580 * Any creation/registration failures are already logged for us.
3581 */
3582 if (infoDict) {
3583 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3584
3585 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3586 if (kc_format == KCFormatFileset &&
3587 newKext &&
3588 !(newKext->isPrelinked()) &&
3589 newKext->declaresExecutable()) {
3590 result = kOSReturnError;
3591 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3592 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3593
3594 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3595 "Dynamic loading of kext denied for kext %s\n",
3596 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3597 goto finish;
3598 }
3599 }
3600 }
3601
3602 /* If the caller needs the plist, hand them back our copy
3603 */
3604 if (mkextPlistOut) {
3605 *mkextPlistOut = mkextPlist;
3606 parsedXML.detach();
3607 }
3608
3609 /* Even if we didn't keep any kexts from the mkext, we may have a load
3610 * request to process, so we are successful (no errors occurred).
3611 */
3612 result = kOSReturnSuccess;
3613
3614 finish:
3615 return result;
3616 }
3617
3618 /* static */
3619 OSReturn
readMkext2Archive(OSData * mkextData,OSSharedPtr<OSDictionary> & mkextPlistOut,uint32_t * checksumPtr)3620 OSKext::readMkext2Archive(
3621 OSData * mkextData,
3622 OSSharedPtr<OSDictionary> &mkextPlistOut,
3623 uint32_t * checksumPtr)
3624 {
3625 OSDictionary * mkextPlist = NULL;
3626 OSReturn ret;
3627
3628 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3629 &mkextPlist,
3630 checksumPtr))) {
3631 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3632 }
3633 return ret;
3634 }
3635
3636 /*********************************************************************
3637 *********************************************************************/
3638 /* static */
3639 OSSharedPtr<OSKext>
withMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3640 OSKext::withMkext2Info(
3641 OSDictionary * anInfoDict,
3642 OSData * mkextData)
3643 {
3644 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3645
3646 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3647 return NULL;
3648 }
3649
3650 return newKext;
3651 }
3652
3653 /*********************************************************************
3654 *********************************************************************/
3655 bool
initWithMkext2Info(OSDictionary * anInfoDict,OSData * mkextData)3656 OSKext::initWithMkext2Info(
3657 OSDictionary * anInfoDict,
3658 OSData * mkextData)
3659 {
3660 bool result = false;
3661 OSString * kextPath = NULL; // do not release
3662 OSNumber * executableOffsetNum = NULL; // do not release
3663 OSSharedPtr<OSData> executable;
3664
3665 if (anInfoDict == NULL || !super::init()) {
3666 goto finish;
3667 }
3668
3669 /* Get the path. Don't look for an arch-specific path property.
3670 */
3671 kextPath = OSDynamicCast(OSString,
3672 anInfoDict->getObject(kMKEXTBundlePathKey));
3673
3674 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3675 goto finish;
3676 }
3677
3678 /* If we have a path to the executable, save it.
3679 */
3680 executableRelPath.reset(OSDynamicCast(OSString,
3681 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3682
3683 /* Don't need the paths to be in the info dictionary any more.
3684 */
3685 anInfoDict->removeObject(kMKEXTBundlePathKey);
3686 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3687
3688 executableOffsetNum = OSDynamicCast(OSNumber,
3689 infoDict->getObject(kMKEXTExecutableKey));
3690 if (executableOffsetNum) {
3691 executable = createMkext2FileEntry(mkextData,
3692 executableOffsetNum, "executable");
3693 infoDict->removeObject(kMKEXTExecutableKey);
3694 if (!executable) {
3695 goto finish;
3696 }
3697 if (!setExecutable(executable.get(), mkextData, true)) {
3698 goto finish;
3699 }
3700 }
3701
3702 result = (registerIdentifier() == kOSKextInitialized);
3703 finish:
3704 return result;
3705 }
3706
3707 /*********************************************************************
3708 *********************************************************************/
3709 OSSharedPtr<OSData>
createMkext2FileEntry(OSData * mkextData,OSNumber * offsetNum,const char * name)3710 OSKext::createMkext2FileEntry(
3711 OSData * mkextData,
3712 OSNumber * offsetNum,
3713 const char * name)
3714 {
3715 OSSharedPtr<OSData> result;
3716 MkextEntryRef entryRef;
3717 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3718 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3719
3720 result = OSData::withCapacity(sizeof(entryRef));
3721 if (!result) {
3722 goto finish;
3723 }
3724
3725 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3726 entryRef.fileinfo = mkextBuffer + entryOffset;
3727 if (!result->appendValue(entryRef)) {
3728 result.reset();
3729 goto finish;
3730 }
3731
3732 finish:
3733 if (!result) {
3734 OSKextLog(this,
3735 kOSKextLogErrorLevel |
3736 kOSKextLogArchiveFlag,
3737 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3738 name, getIdentifierCString());
3739 }
3740 return result;
3741 }
3742
3743 /*********************************************************************
3744 *********************************************************************/
3745 extern "C" {
3746 static void * z_alloc(void *, u_int items, u_int size);
3747 static void z_free(void *, void *ptr);
3748
3749 typedef struct z_mem {
3750 uint32_t alloc_size;
3751 uint8_t data[0];
3752 } z_mem;
3753
3754 /*
3755 * Space allocation and freeing routines for use by zlib routines.
3756 */
3757 void *
z_alloc(void * notused __unused,u_int num_items,u_int size)3758 z_alloc(void * notused __unused, u_int num_items, u_int size)
3759 {
3760 void * result = NULL;
3761 z_mem * zmem = NULL;
3762
3763 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3764 //Check for overflow due to multiplication
3765 if (total > UINT32_MAX) {
3766 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x",
3767 notused, num_items, size, num_items, size);
3768 }
3769
3770 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3771 //Check for overflow due to addition
3772 if (allocSize64 > UINT32_MAX) {
3773 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx",
3774 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3775 }
3776 uint32_t allocSize = (uint32_t)allocSize64;
3777
3778 zmem = (z_mem *)kalloc_data_tag(allocSize, Z_WAITOK,
3779 VM_KERN_MEMORY_OSKEXT);
3780 if (!zmem) {
3781 goto finish;
3782 }
3783 zmem->alloc_size = allocSize;
3784 result = (void *)&(zmem->data);
3785 finish:
3786 return result;
3787 }
3788
3789 void
z_free(void * notused __unused,void * ptr)3790 z_free(void * notused __unused, void * ptr)
3791 {
3792 uint32_t * skipper = (uint32_t *)ptr - 1;
3793 z_mem * zmem = (z_mem *)skipper;
3794 kfree_data(zmem, zmem->alloc_size);
3795 }
3796 };
3797
3798 OSSharedPtr<OSData>
extractMkext2FileData(UInt8 * data,const char * name,uint32_t compressedSize,uint32_t fullSize)3799 OSKext::extractMkext2FileData(
3800 UInt8 * data,
3801 const char * name,
3802 uint32_t compressedSize,
3803 uint32_t fullSize)
3804 {
3805 OSSharedPtr<OSData> result;
3806 OSSharedPtr<OSData> uncompressedData; // release on error
3807
3808 uint8_t * uncompressedDataBuffer = NULL; // do not free
3809 unsigned long uncompressedSize;
3810 z_stream zstream;
3811 bool zstream_inited = false;
3812 int zlib_result;
3813
3814 /* If the file isn't compressed, we want to make a copy
3815 * so that we don't have the tie to the larger mkext file buffer any more.
3816 */
3817 if (!compressedSize) {
3818 uncompressedData = OSData::withBytes(data, fullSize);
3819 // xxx - no check for failure?
3820 result = uncompressedData;
3821 goto finish;
3822 }
3823
3824 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3825 (vm_offset_t*)&uncompressedDataBuffer, fullSize,
3826 KMA_DATA, VM_KERN_MEMORY_OSKEXT)) {
3827 /* How's this for cheesy? The kernel is only asked to extract
3828 * kext plists so we tailor the log messages.
3829 */
3830 if (isKernel()) {
3831 OSKextLog(this,
3832 kOSKextLogErrorLevel |
3833 kOSKextLogArchiveFlag,
3834 "Allocation failure extracting %s from mkext.", name);
3835 } else {
3836 OSKextLog(this,
3837 kOSKextLogErrorLevel |
3838 kOSKextLogArchiveFlag,
3839 "Allocation failure extracting %s from mkext for kext %s.",
3840 name, getIdentifierCString());
3841 }
3842
3843 goto finish;
3844 }
3845 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3846 if (!uncompressedData) {
3847 if (isKernel()) {
3848 OSKextLog(this,
3849 kOSKextLogErrorLevel |
3850 kOSKextLogArchiveFlag,
3851 "Allocation failure extracting %s from mkext.", name);
3852 } else {
3853 OSKextLog(this,
3854 kOSKextLogErrorLevel |
3855 kOSKextLogArchiveFlag,
3856 "Allocation failure extracting %s from mkext for kext %s.",
3857 name, getIdentifierCString());
3858 }
3859 goto finish;
3860 }
3861 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3862
3863 if (isKernel()) {
3864 OSKextLog(this,
3865 kOSKextLogDetailLevel |
3866 kOSKextLogArchiveFlag,
3867 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3868 name, compressedSize, fullSize);
3869 } else {
3870 OSKextLog(this,
3871 kOSKextLogDetailLevel |
3872 kOSKextLogArchiveFlag,
3873 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3874 getIdentifierCString(), name, compressedSize, fullSize);
3875 }
3876
3877 bzero(&zstream, sizeof(zstream));
3878 zstream.next_in = (UInt8 *)data;
3879 zstream.avail_in = compressedSize;
3880
3881 zstream.next_out = uncompressedDataBuffer;
3882 zstream.avail_out = fullSize;
3883
3884 zstream.zalloc = z_alloc;
3885 zstream.zfree = z_free;
3886
3887 zlib_result = inflateInit(&zstream);
3888 if (Z_OK != zlib_result) {
3889 if (isKernel()) {
3890 OSKextLog(this,
3891 kOSKextLogErrorLevel |
3892 kOSKextLogArchiveFlag,
3893 "Mkext error; zlib inflateInit failed (%d) for %s.",
3894 zlib_result, name);
3895 } else {
3896 OSKextLog(this,
3897 kOSKextLogErrorLevel |
3898 kOSKextLogArchiveFlag,
3899 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3900 getIdentifierCString(), zlib_result, name);
3901 }
3902 goto finish;
3903 } else {
3904 zstream_inited = true;
3905 }
3906
3907 zlib_result = inflate(&zstream, Z_FINISH);
3908
3909 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3910 uncompressedSize = zstream.total_out;
3911 } else {
3912 if (isKernel()) {
3913 OSKextLog(this,
3914 kOSKextLogErrorLevel |
3915 kOSKextLogArchiveFlag,
3916 "Mkext error; zlib inflate failed (%d) for %s.",
3917 zlib_result, name);
3918 } else {
3919 OSKextLog(this,
3920 kOSKextLogErrorLevel |
3921 kOSKextLogArchiveFlag,
3922 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3923 getIdentifierCString(), zlib_result, name);
3924 }
3925 if (zstream.msg) {
3926 OSKextLog(this,
3927 kOSKextLogErrorLevel |
3928 kOSKextLogArchiveFlag,
3929 "zlib error: %s.", zstream.msg);
3930 }
3931 goto finish;
3932 }
3933
3934 if (uncompressedSize != fullSize) {
3935 if (isKernel()) {
3936 OSKextLog(this,
3937 kOSKextLogErrorLevel |
3938 kOSKextLogArchiveFlag,
3939 "Mkext error; zlib inflate discrepancy for %s, "
3940 "uncompressed size != original size.", name);
3941 } else {
3942 OSKextLog(this,
3943 kOSKextLogErrorLevel |
3944 kOSKextLogArchiveFlag,
3945 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3946 "uncompressed size != original size.",
3947 getIdentifierCString(), name);
3948 }
3949 goto finish;
3950 }
3951
3952 result = os::move(uncompressedData);
3953
3954 finish:
3955 /* Don't bother checking return, nothing we can do on fail.
3956 */
3957 if (zstream_inited) {
3958 inflateEnd(&zstream);
3959 }
3960
3961 return result;
3962 }
3963
3964 /*********************************************************************
3965 *********************************************************************/
3966 /* static */
3967 OSReturn
loadFromMkext(OSKextLogSpec clientLogFilter,char * mkextBuffer,uint32_t mkextBufferLength,char ** logInfoOut,uint32_t * logInfoLengthOut)3968 OSKext::loadFromMkext(
3969 OSKextLogSpec clientLogFilter,
3970 char * mkextBuffer,
3971 uint32_t mkextBufferLength,
3972 char ** logInfoOut,
3973 uint32_t * logInfoLengthOut)
3974 {
3975 OSReturn result = kOSReturnError;
3976 OSReturn tempResult = kOSReturnError;
3977
3978 OSSharedPtr<OSData> mkextData;
3979 OSSharedPtr<OSDictionary> mkextPlist;
3980
3981 OSSharedPtr<OSArray> logInfoArray;
3982 OSSharedPtr<OSSerialize> serializer;
3983
3984 OSString * predicate = NULL; // do not release
3985 OSDictionary * requestArgs = NULL; // do not release
3986
3987 OSString * kextIdentifier = NULL; // do not release
3988 OSNumber * startKextExcludeNum = NULL; // do not release
3989 OSNumber * startMatchingExcludeNum = NULL; // do not release
3990 OSBoolean * delayAutounloadBool = NULL; // do not release
3991 OSArray * personalityNames = NULL; // do not release
3992
3993 /* Default values for these two options: regular autounload behavior,
3994 * load all kexts, send no personalities.
3995 */
3996 Boolean delayAutounload = false;
3997 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3998 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3999
4000 IORecursiveLockLock(sKextLock);
4001
4002 if (logInfoOut) {
4003 *logInfoOut = NULL;
4004 *logInfoLengthOut = 0;
4005 }
4006
4007 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
4008
4009 OSKextLog(/* kext */ NULL,
4010 kOSKextLogDebugLevel |
4011 kOSKextLogIPCFlag,
4012 "Received kext load request from user space.");
4013
4014 /* Regardless of processing, the fact that we have gotten here means some
4015 * user-space program is up and talking to us, so we'll switch our kext
4016 * registration to reflect that.
4017 */
4018 if (!sUserLoadsActive) {
4019 OSKextLog(/* kext */ NULL,
4020 kOSKextLogProgressLevel |
4021 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
4022 "Switching to late startup (user-space) kext loading policy.");
4023
4024 sUserLoadsActive = true;
4025 }
4026
4027 if (!sLoadEnabled) {
4028 OSKextLog(/* kext */ NULL,
4029 kOSKextLogErrorLevel |
4030 kOSKextLogLoadFlag,
4031 "Kext loading is disabled.");
4032 result = kOSKextReturnDisabled;
4033 goto finish;
4034 }
4035
4036 /* Note that we do not set a dealloc function on this OSData
4037 * object! No references to it can remain after the loadFromMkext()
4038 * call since we are in a MIG function, and will vm_deallocate()
4039 * the buffer.
4040 */
4041 mkextData = OSData::withBytesNoCopy(mkextBuffer,
4042 mkextBufferLength);
4043 if (!mkextData) {
4044 OSKextLog(/* kext */ NULL,
4045 kOSKextLogErrorLevel |
4046 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4047 "Failed to create wrapper for kext load request.");
4048 result = kOSKextReturnNoMemory;
4049 goto finish;
4050 }
4051
4052 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
4053 if (result != kOSReturnSuccess) {
4054 OSKextLog(/* kext */ NULL,
4055 kOSKextLogErrorLevel |
4056 kOSKextLogLoadFlag,
4057 "Failed to read kext load request.");
4058 goto finish;
4059 }
4060
4061 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
4062 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
4063 OSKextLog(/* kext */ NULL,
4064 kOSKextLogErrorLevel |
4065 kOSKextLogLoadFlag,
4066 "Received kext load request with no predicate; skipping.");
4067 result = kOSKextReturnInvalidArgument;
4068 goto finish;
4069 }
4070
4071 requestArgs = OSDynamicCast(OSDictionary,
4072 mkextPlist->getObject(kKextRequestArgumentsKey));
4073 if (!requestArgs || !requestArgs->getCount()) {
4074 OSKextLog(/* kext */ NULL,
4075 kOSKextLogErrorLevel |
4076 kOSKextLogLoadFlag,
4077 "Received kext load request with no arguments.");
4078 result = kOSKextReturnInvalidArgument;
4079 goto finish;
4080 }
4081
4082 kextIdentifier = OSDynamicCast(OSString,
4083 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
4084
4085 if (!kextIdentifier) {
4086 OSKextLog(/* kext */ NULL,
4087 kOSKextLogErrorLevel |
4088 kOSKextLogLoadFlag,
4089 "Received kext load request with no kext identifier.");
4090 result = kOSKextReturnInvalidArgument;
4091 goto finish;
4092 }
4093
4094 startKextExcludeNum = OSDynamicCast(OSNumber,
4095 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
4096 startMatchingExcludeNum = OSDynamicCast(OSNumber,
4097 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
4098 delayAutounloadBool = OSDynamicCast(OSBoolean,
4099 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
4100 personalityNames = OSDynamicCast(OSArray,
4101 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
4102
4103 if (delayAutounloadBool) {
4104 delayAutounload = delayAutounloadBool->getValue();
4105 }
4106 if (startKextExcludeNum) {
4107 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
4108 }
4109 if (startMatchingExcludeNum) {
4110 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
4111 }
4112
4113 OSKextLog(/* kext */ NULL,
4114 kOSKextLogProgressLevel |
4115 kOSKextLogIPCFlag,
4116 "Received request from user space to load kext %s.",
4117 kextIdentifier->getCStringNoCopy());
4118
4119 /* Load the kext, with no deferral, since this is a load from outside
4120 * the kernel.
4121 * xxx - Would like a better way to handle the default values for the
4122 * xxx - start/match opt args.
4123 */
4124 result = OSKext::loadKextWithIdentifier(
4125 kextIdentifier,
4126 /* kextRef */ NULL,
4127 /* allowDefer */ false,
4128 delayAutounload,
4129 startKextExcludeLevel,
4130 startMatchingExcludeLevel,
4131 personalityNames);
4132 if (result != kOSReturnSuccess) {
4133 goto finish;
4134 }
4135 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
4136 * for matching via a separate IOKit calldown.
4137 */
4138
4139 finish:
4140
4141 /* Gather up the collected log messages for user space. Any
4142 * error messages past this call will not make it up as log messages
4143 * but will be in the system log.
4144 */
4145 logInfoArray = OSKext::clearUserSpaceLogFilter();
4146
4147 if (logInfoArray && logInfoOut && logInfoLengthOut) {
4148 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
4149 logInfoOut, logInfoLengthOut);
4150 if (tempResult != kOSReturnSuccess) {
4151 result = tempResult;
4152 }
4153 }
4154
4155 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
4156
4157 IORecursiveLockUnlock(sKextLock);
4158
4159 /* Note: mkextDataObject will have been retained by every kext w/an
4160 * executable in it. That should all have been flushed out at the
4161 * and of the load operation, but you never know....
4162 */
4163 if (mkextData && mkextData->getRetainCount() > 1) {
4164 OSKextLog(/* kext */ NULL,
4165 kOSKextLogErrorLevel |
4166 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
4167 "Kext load request buffer from user space still retained by a kext; "
4168 "probable memory leak.");
4169 }
4170
4171 return result;
4172 }
4173
4174 #endif // CONFIG_KXLD
4175
4176 /*********************************************************************
4177 *********************************************************************/
4178 /* static */
4179 OSReturn
serializeLogInfo(OSArray * logInfoArray,char ** logInfoOut,uint32_t * logInfoLengthOut)4180 OSKext::serializeLogInfo(
4181 OSArray * logInfoArray,
4182 char ** logInfoOut,
4183 uint32_t * logInfoLengthOut)
4184 {
4185 OSReturn result = kOSReturnError;
4186 char * buffer = NULL;
4187 kern_return_t kmem_result = KERN_FAILURE;
4188 OSSharedPtr<OSSerialize> serializer;
4189 char * logInfo = NULL; // returned by reference
4190 uint32_t logInfoLength = 0;
4191
4192 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
4193 OSKextLog(/* kext */ NULL,
4194 kOSKextLogErrorLevel |
4195 kOSKextLogIPCFlag,
4196 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
4197 /* Bad programmer. */
4198 result = kOSKextReturnInvalidArgument;
4199 goto finish;
4200 }
4201
4202 serializer = OSSerialize::withCapacity(0);
4203 if (!serializer) {
4204 OSKextLog(/* kext */ NULL,
4205 kOSKextLogErrorLevel |
4206 kOSKextLogIPCFlag,
4207 "Failed to create serializer on log info for request from user space.");
4208 /* Incidental error; we're going to (try to) allow the request
4209 * itself to succeed. */
4210 } else {
4211 if (!logInfoArray->serialize(serializer.get())) {
4212 OSKextLog(/* kext */ NULL,
4213 kOSKextLogErrorLevel |
4214 kOSKextLogIPCFlag,
4215 "Failed to serialize log info for request from user space.");
4216 /* Incidental error; we're going to (try to) allow the request
4217 * itself to succeed. */
4218 } else {
4219 logInfo = serializer->text();
4220 logInfoLength = serializer->getLength();
4221
4222 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength),
4223 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
4224 if (kmem_result != KERN_SUCCESS) {
4225 OSKextLog(/* kext */ NULL,
4226 kOSKextLogErrorLevel |
4227 kOSKextLogIPCFlag,
4228 "Failed to copy log info for request from user space.");
4229 /* Incidental error; we're going to (try to) allow the request
4230 * to succeed. */
4231 } else {
4232 /* 11981737 - clear uninitialized data in last page */
4233 bzero((void *)(buffer + logInfoLength),
4234 (round_page(logInfoLength) - logInfoLength));
4235 memcpy(buffer, logInfo, logInfoLength);
4236 *logInfoOut = buffer;
4237 *logInfoLengthOut = logInfoLength;
4238 }
4239 }
4240 }
4241
4242 result = kOSReturnSuccess;
4243 finish:
4244 return result;
4245 }
4246
4247 #if PRAGMA_MARK
4248 #pragma mark Instance Management Methods
4249 #endif
4250 /*********************************************************************
4251 *********************************************************************/
4252 OSSharedPtr<OSKext>
lookupKextWithIdentifier(const char * kextIdentifier)4253 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
4254 {
4255 OSSharedPtr<OSKext> foundKext;
4256
4257 IORecursiveLockLock(sKextLock);
4258 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
4259 IORecursiveLockUnlock(sKextLock);
4260
4261 return foundKext;
4262 }
4263
4264 /*********************************************************************
4265 *********************************************************************/
4266 OSSharedPtr<OSKext>
lookupKextWithIdentifier(OSString * kextIdentifier)4267 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
4268 {
4269 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
4270 }
4271
4272 /*********************************************************************
4273 *********************************************************************/
4274 OSSharedPtr<OSKext>
lookupDextWithIdentifier(OSString * dextIdentifier,OSData * dextUniqueIdentifier)4275 OSKext::lookupDextWithIdentifier(OSString * dextIdentifier, OSData *dextUniqueIdentifier)
4276 {
4277 OSSharedPtr<OSKext> foundDext;
4278 foundDext.reset();
4279
4280 IORecursiveLockLock(sKextLock);
4281 OSKext *dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIdentifier->getCStringNoCopy()));
4282 if (dext != NULL && dext->isDriverKit()) {
4283 if (dext->dextUniqueID == NULL || dext->dextUniqueID->isEqualTo(dextUniqueIdentifier)) {
4284 foundDext.reset(dext, OSRetain);
4285 }
4286 }
4287 IORecursiveLockUnlock(sKextLock);
4288
4289 return foundDext;
4290 }
4291
4292 /*********************************************************************
4293 *********************************************************************/
4294 OSSharedPtr<OSKext>
lookupKextWithLoadTag(uint32_t aTag)4295 OSKext::lookupKextWithLoadTag(uint32_t aTag)
4296 {
4297 OSSharedPtr<OSKext> foundKext; // returned
4298 uint32_t i, j;
4299 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4300 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4301
4302 IORecursiveLockLock(sKextLock);
4303
4304 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4305 for (i = 0; i < count[j]; i++) {
4306 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4307 if (thisKext->getLoadTag() == aTag) {
4308 foundKext.reset(thisKext, OSRetain);
4309 goto finish;
4310 }
4311 }
4312 }
4313
4314 finish:
4315 IORecursiveLockUnlock(sKextLock);
4316
4317 return foundKext;
4318 }
4319
4320 /*********************************************************************
4321 *********************************************************************/
4322 OSSharedPtr<OSKext>
lookupKextWithAddress(vm_address_t address)4323 OSKext::lookupKextWithAddress(vm_address_t address)
4324 {
4325 OSSharedPtr<OSKext> foundKext; // returned
4326 uint32_t count, i;
4327 kmod_info_t *kmod_info;
4328 vm_address_t originalAddress;
4329 #if defined(__arm64__)
4330 uint64_t textExecBase;
4331 size_t textExecSize;
4332 #endif /* defined(__arm64__) */
4333
4334 originalAddress = address;
4335 #if __has_feature(ptrauth_calls)
4336 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
4337 #endif /* __has_feature(ptrauth_calls) */
4338
4339 IORecursiveLockLock(sKextLock);
4340
4341 count = sLoadedKexts->getCount();
4342 for (i = 0; i < count; i++) {
4343 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
4344 if (thisKext == sKernelKext) {
4345 continue;
4346 }
4347 if (thisKext->kmod_info && thisKext->kmod_info->address) {
4348 kmod_info = thisKext->kmod_info;
4349 vm_address_t kext_start = kmod_info->address;
4350 vm_address_t kext_end = kext_start + kmod_info->size;
4351 if ((kext_start <= address) && (address < kext_end)) {
4352 foundKext.reset(thisKext, OSRetain);
4353 goto finish;
4354 }
4355 #if defined(__arm64__)
4356 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
4357
4358 /**
4359 * If the addresses within the Mach-O are unslid, then manually
4360 * slide any addresses coming from the Mach-O before usage.
4361 */
4362 if (thisKext->flags.unslidMachO) {
4363 textExecBase = (uintptr_t) ml_static_slide((vm_offset_t) textExecBase);
4364 }
4365
4366 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
4367 foundKext.reset(thisKext, OSRetain);
4368 goto finish;
4369 }
4370 #endif /* defined (__arm64__) */
4371 }
4372 }
4373 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
4374 foundKext.reset(sKernelKext, OSRetain);
4375 goto finish;
4376 }
4377 /*
4378 * DriverKit userspace executables do not have a kernel linkedExecutable,
4379 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
4380 * here, so use the original address passed to this method.
4381 *
4382 * This is supposed to be used for logging reasons only. When logd
4383 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
4384 * remove it here before checking it against the LoadTag.
4385 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
4386 */
4387
4388 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
4389 count = sLoadedDriverKitKexts->getCount();
4390 for (i = 0; i < count; i++) {
4391 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
4392 if (thisKext->getLoadTag() == address) {
4393 foundKext.reset(thisKext, OSRetain);
4394 }
4395 }
4396
4397 finish:
4398 IORecursiveLockUnlock(sKextLock);
4399
4400 return foundKext;
4401 }
4402
4403 OSSharedPtr<OSData>
copyKextUUIDForAddress(OSNumber * address)4404 OSKext::copyKextUUIDForAddress(OSNumber *address)
4405 {
4406 OSSharedPtr<OSData> uuid;
4407 OSSharedPtr<OSKext> kext;
4408
4409 if (!address) {
4410 return NULL;
4411 }
4412
4413 #if CONFIG_MACF
4414 /* Is the calling process allowed to query kext info? */
4415 if (current_task() != kernel_task) {
4416 int macCheckResult = 0;
4417 kauth_cred_t cred = NULL;
4418
4419 cred = kauth_cred_get_with_ref();
4420 macCheckResult = mac_kext_check_query(cred);
4421 kauth_cred_unref(&cred);
4422
4423 if (macCheckResult != 0) {
4424 OSKextLog(/* kext */ NULL,
4425 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
4426 "Failed to query kext UUID (MAC policy error 0x%x).",
4427 macCheckResult);
4428 return NULL;
4429 }
4430 }
4431 #endif
4432
4433 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
4434 if (slidAddress != 0) {
4435 kext = lookupKextWithAddress(slidAddress);
4436 if (kext) {
4437 uuid = kext->copyTextUUID();
4438 }
4439 }
4440
4441 if (!uuid) {
4442 /*
4443 * If we still don't have a UUID, then we failed to match the slid + stripped address with
4444 * a kext. This might have happened because the log message came from a dext.
4445 *
4446 * Try again with the original address.
4447 */
4448 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
4449 if (kext && kext->isDriverKit()) {
4450 uuid = kext->copyTextUUID();
4451 }
4452 }
4453
4454 return uuid;
4455 }
4456
4457 /*********************************************************************
4458 *********************************************************************/
4459 OSSharedPtr<OSKext>
lookupKextWithUUID(uuid_t wanted)4460 OSKext::lookupKextWithUUID(uuid_t wanted)
4461 {
4462 OSSharedPtr<OSKext> foundKext; // returned
4463 uint32_t j, i;
4464 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4465 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4466
4467
4468 IORecursiveLockLock(sKextLock);
4469
4470 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4471 for (i = 0; i < count[j]; i++) {
4472 OSKext * thisKext = NULL;
4473
4474 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4475 if (!thisKext) {
4476 continue;
4477 }
4478
4479 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
4480 if (!uuid_data) {
4481 continue;
4482 }
4483
4484 uuid_t uuid;
4485 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4486
4487 if (0 == uuid_compare(wanted, uuid)) {
4488 foundKext.reset(thisKext, OSRetain);
4489 goto finish;
4490 }
4491 }
4492 }
4493 finish:
4494 IORecursiveLockUnlock(sKextLock);
4495
4496 return foundKext;
4497 }
4498
4499
4500
4501
4502 /*********************************************************************
4503 *********************************************************************/
4504 /* static */
4505 bool
isKextWithIdentifierLoaded(const char * kextIdentifier)4506 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4507 {
4508 bool result = false;
4509 OSKext * foundKext = NULL; // returned
4510
4511 IORecursiveLockLock(sKextLock);
4512
4513 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4514 if (foundKext && foundKext->isLoaded()) {
4515 result = true;
4516 }
4517
4518 IORecursiveLockUnlock(sKextLock);
4519
4520 return result;
4521 }
4522
4523 /*********************************************************************
4524 * xxx - should spawn a separate thread so a kext can safely have
4525 * xxx - itself unloaded.
4526 *********************************************************************/
4527 /* static */
4528 OSReturn
removeKext(OSKext * aKext,__unused bool terminateServicesAndRemovePersonalitiesFlag)4529 OSKext::removeKext(
4530 OSKext * aKext,
4531 #if CONFIG_EMBEDDED
4532 __unused
4533 #endif
4534 bool terminateServicesAndRemovePersonalitiesFlag)
4535 {
4536 #if CONFIG_EMBEDDED
4537 if (!aKext->isDriverKit()) {
4538 OSKextLog(aKext,
4539 kOSKextLogErrorLevel |
4540 kOSKextLogKextBookkeepingFlag,
4541 "removeKext() called for %s, only supported on embedded for DriverKit dexts",
4542 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4543
4544 return kOSReturnSuccess;
4545 }
4546 #endif /* CONFIG_EMBEDDED */
4547 OSReturn result = kOSKextReturnInUse;
4548 OSKext * checkKext = NULL; // do not release
4549 #if CONFIG_MACF
4550 int macCheckResult = 0;
4551 kauth_cred_t cred = NULL;
4552 #endif
4553
4554 IORecursiveLockLock(sKextLock);
4555
4556 /* If the kext has no identifier, it failed to init
4557 * so isn't in sKextsByID and it isn't loaded.
4558 */
4559 if (!aKext->getIdentifier()) {
4560 result = kOSReturnSuccess;
4561 goto finish;
4562 }
4563
4564 checkKext = OSDynamicCast(OSKext,
4565 sKextsByID->getObject(aKext->getIdentifier()));
4566 if (checkKext != aKext) {
4567 result = kOSKextReturnNotFound;
4568 goto finish;
4569 }
4570
4571 if (aKext->isLoaded() || aKext->isDriverKit()) {
4572 #if CONFIG_MACF
4573 if (current_task() != kernel_task) {
4574 cred = kauth_cred_get_with_ref();
4575 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4576 kauth_cred_unref(&cred);
4577 }
4578
4579 if (macCheckResult != 0) {
4580 result = kOSReturnError;
4581 OSKextLog(aKext,
4582 kOSKextLogErrorLevel |
4583 kOSKextLogKextBookkeepingFlag,
4584 "Failed to remove kext %s (MAC policy error 0x%x).",
4585 aKext->getIdentifierCString(), macCheckResult);
4586 goto finish;
4587 }
4588 #endif
4589
4590 /* make sure there are no resource requests in flight - 17187548 */
4591 if (aKext->declaresExecutable() && aKext->countRequestCallbacks()) {
4592 goto finish;
4593 }
4594 if (aKext->flags.unloadUnsupported) {
4595 result = kOSKextReturnInUse;
4596 OSKextLog(aKext,
4597 kOSKextLogErrorLevel |
4598 kOSKextLogKextBookkeepingFlag,
4599 "Can't remove kext %s; unsupported by cache.",
4600 aKext->getIdentifierCString());
4601 goto finish;
4602 }
4603
4604 /* If we are terminating, send the request to the IOCatalogue
4605 * (which will actually call us right back but that's ok we have
4606 * a recursive lock don't you know) but do not ask the IOCatalogue
4607 * to call back with an unload, we'll do that right here.
4608 */
4609 if (terminateServicesAndRemovePersonalitiesFlag) {
4610 result = gIOCatalogue->terminateDriversForModule(
4611 aKext->getIdentifierCString(), /* unload */ false);
4612 if (result != kOSReturnSuccess) {
4613 OSKextLog(aKext,
4614 kOSKextLogErrorLevel |
4615 kOSKextLogKextBookkeepingFlag,
4616 "Can't remove kext %s; services failed to terminate - 0x%x.",
4617 aKext->getIdentifierCString(), result);
4618 goto finish;
4619 }
4620 }
4621
4622 result = aKext->unload();
4623 if (result != kOSReturnSuccess) {
4624 OSKextLog(aKext,
4625 kOSKextLogErrorLevel |
4626 kOSKextLogKextBookkeepingFlag,
4627 "Can't remove kext %s; kext failed to unload - 0x%x.",
4628 aKext->getIdentifierCString(), result);
4629 goto finish;
4630 }
4631 }
4632
4633 /* Remove personalities as requested. This is a bit redundant for a loaded
4634 * kext as IOCatalogue::terminateDriversForModule() removes driver
4635 * personalities, but it doesn't restart matching, which we always want
4636 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4637 * that happens.
4638 */
4639 if (terminateServicesAndRemovePersonalitiesFlag) {
4640 aKext->removePersonalitiesFromCatalog();
4641 }
4642
4643 if (aKext->isInFileset()) {
4644 OSKextLog(aKext,
4645 kOSKextLogProgressLevel |
4646 kOSKextLogKextBookkeepingFlag,
4647 "Fileset kext %s unloaded.",
4648 aKext->getIdentifierCString());
4649 } else {
4650 OSKextLog(aKext,
4651 kOSKextLogProgressLevel |
4652 kOSKextLogKextBookkeepingFlag,
4653 "Removing kext %s.",
4654 aKext->getIdentifierCString());
4655
4656 sKextsByID->removeObject(aKext->getIdentifier());
4657 }
4658 result = kOSReturnSuccess;
4659
4660 finish:
4661 IORecursiveLockUnlock(sKextLock);
4662 return result;
4663 }
4664
4665 /*********************************************************************
4666 *********************************************************************/
4667 /* static */
4668 OSReturn
removeKextWithIdentifier(const char * kextIdentifier,bool terminateServicesAndRemovePersonalitiesFlag)4669 OSKext::removeKextWithIdentifier(
4670 const char * kextIdentifier,
4671 bool terminateServicesAndRemovePersonalitiesFlag)
4672 {
4673 OSReturn result = kOSReturnError;
4674
4675 IORecursiveLockLock(sKextLock);
4676
4677 OSKext * aKext = OSDynamicCast(OSKext,
4678 sKextsByID->getObject(kextIdentifier));
4679 if (!aKext) {
4680 result = kOSKextReturnNotFound;
4681 OSKextLog(/* kext */ NULL,
4682 kOSKextLogErrorLevel |
4683 kOSKextLogKextBookkeepingFlag,
4684 "Can't remove kext %s - not found.",
4685 kextIdentifier);
4686 goto finish;
4687 }
4688
4689 result = OSKext::removeKext(aKext,
4690 terminateServicesAndRemovePersonalitiesFlag);
4691
4692 finish:
4693 IORecursiveLockUnlock(sKextLock);
4694
4695 return result;
4696 }
4697
4698 /*********************************************************************
4699 *********************************************************************/
4700 /* static */
4701 OSReturn
removeKextWithLoadTag(OSKextLoadTag loadTag,bool terminateServicesAndRemovePersonalitiesFlag)4702 OSKext::removeKextWithLoadTag(
4703 OSKextLoadTag loadTag,
4704 bool terminateServicesAndRemovePersonalitiesFlag)
4705 {
4706 OSReturn result = kOSReturnError;
4707 OSKext * foundKext = NULL;
4708 uint32_t i, j;
4709 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4710 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4711
4712
4713 IORecursiveLockLock(sKextLock);
4714
4715 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4716 for (i = 0; i < count[j]; i++) {
4717 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4718 if (thisKext->loadTag == loadTag) {
4719 foundKext = thisKext;
4720 break;
4721 }
4722 }
4723 }
4724
4725 if (!foundKext) {
4726 result = kOSKextReturnNotFound;
4727 OSKextLog(/* kext */ NULL,
4728 kOSKextLogErrorLevel |
4729 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4730 "Can't remove kext with load tag %d - not found.",
4731 loadTag);
4732 goto finish;
4733 }
4734
4735 result = OSKext::removeKext(foundKext,
4736 terminateServicesAndRemovePersonalitiesFlag);
4737
4738 finish:
4739 IORecursiveLockUnlock(sKextLock);
4740
4741 return result;
4742 }
4743
4744 /*********************************************************************
4745 *********************************************************************/
4746 OSSharedPtr<OSDictionary>
copyKexts(void)4747 OSKext::copyKexts(void)
4748 {
4749 OSSharedPtr<OSDictionary> result;
4750
4751 IORecursiveLockLock(sKextLock);
4752 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4753 IORecursiveLockUnlock(sKextLock);
4754
4755 return result;
4756 }
4757
4758 /*********************************************************************
4759 *********************************************************************/
4760 #define BOOTER_KEXT_PREFIX "Driver-"
4761
4762 typedef struct _DeviceTreeBuffer {
4763 uint32_t paddr;
4764 uint32_t length;
4765 } _DeviceTreeBuffer;
4766
4767 /*********************************************************************
4768 * Create a dictionary of excluded kexts from the given booter data.
4769 *********************************************************************/
4770 /* static */
4771 void
createExcludeListFromBooterData(OSDictionary * theDictionary,OSCollectionIterator * theIterator)4772 OSKext::createExcludeListFromBooterData(
4773 OSDictionary * theDictionary,
4774 OSCollectionIterator * theIterator )
4775 {
4776 OSString * deviceTreeName = NULL; // do not release
4777 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4778 char * booterDataPtr = NULL; // do not release
4779 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4780 char * infoDictAddr = NULL; // do not release
4781 OSSharedPtr<OSObject> parsedXML;
4782 OSDictionary * theInfoDict = NULL; // do not release
4783
4784 theIterator->reset();
4785
4786 /* look for AppleKextExcludeList.kext */
4787 while ((deviceTreeName =
4788 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4789 const char * devTreeNameCString;
4790 OSData * deviceTreeEntry; // do not release
4791 OSString * myBundleID; // do not release
4792
4793 deviceTreeEntry =
4794 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4795 if (!deviceTreeEntry) {
4796 continue;
4797 }
4798
4799 /* Make sure it is a kext */
4800 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4801 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4802 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4803 OSKextLog(NULL,
4804 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4805 "\"%s\" not a kext",
4806 devTreeNameCString);
4807 continue;
4808 }
4809
4810 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4811 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4812 if (!deviceTreeBuffer) {
4813 continue;
4814 }
4815
4816 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4817 if (!booterDataPtr) {
4818 continue;
4819 }
4820
4821 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4822 if (!kextFileInfo->infoDictPhysAddr ||
4823 !kextFileInfo->infoDictLength) {
4824 continue;
4825 }
4826
4827 infoDictAddr = (char *)
4828 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4829 if (!infoDictAddr) {
4830 continue;
4831 }
4832
4833 parsedXML = OSUnserializeXML(infoDictAddr);
4834 if (!parsedXML) {
4835 continue;
4836 }
4837
4838 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4839 if (!theInfoDict) {
4840 continue;
4841 }
4842
4843 myBundleID =
4844 OSDynamicCast(OSString,
4845 theInfoDict->getObject(kCFBundleIdentifierKey));
4846 if (myBundleID &&
4847 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4848 boolean_t updated = updateExcludeList(theInfoDict);
4849 if (!updated) {
4850 /* 25322874 */
4851 panic("Missing OSKextExcludeList dictionary");
4852 }
4853 break;
4854 }
4855 } // while ( (deviceTreeName = ...) )
4856
4857 return;
4858 }
4859
4860 /*********************************************************************
4861 * Create a dictionary of excluded kexts from the given prelink
4862 * info (kernelcache).
4863 *********************************************************************/
4864 /* static */
4865 void
createExcludeListFromPrelinkInfo(OSArray * theInfoArray)4866 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4867 {
4868 OSDictionary * myInfoDict = NULL; // do not release
4869 OSString * myBundleID; // do not release
4870 u_int i;
4871
4872 /* Find the Apple Kext Exclude List. */
4873 for (i = 0; i < theInfoArray->getCount(); i++) {
4874 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4875 if (!myInfoDict) {
4876 continue;
4877 }
4878 myBundleID =
4879 OSDynamicCast(OSString,
4880 myInfoDict->getObject(kCFBundleIdentifierKey));
4881 if (myBundleID &&
4882 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4883 boolean_t updated = updateExcludeList(myInfoDict);
4884 if (!updated) {
4885 /* 25322874 */
4886 panic("Missing OSKextExcludeList dictionary");
4887 }
4888 break;
4889 }
4890 } // for (i = 0; i < theInfoArray->getCount()...
4891
4892 return;
4893 }
4894
4895 /* static */
4896 boolean_t
updateExcludeList(OSDictionary * infoDict)4897 OSKext::updateExcludeList(OSDictionary *infoDict)
4898 {
4899 OSDictionary *myTempDict = NULL; // do not free
4900 OSString *myTempString = NULL; // do not free
4901 OSKextVersion newVersion = 0;
4902 boolean_t updated = false;
4903
4904 if (!infoDict) {
4905 return false;
4906 }
4907
4908 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4909 if (!myTempDict) {
4910 return false;
4911 }
4912
4913 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4914 if (!myTempString) {
4915 return false;
4916 }
4917
4918 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4919 if (newVersion == 0) {
4920 return false;
4921 }
4922
4923 IORecursiveLockLock(sKextLock);
4924
4925 if (newVersion > sExcludeListVersion) {
4926 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4927 sExcludeListVersion = newVersion;
4928 updated = true;
4929 }
4930
4931 IORecursiveLockUnlock(sKextLock);
4932 return updated;
4933 }
4934
4935 #if PRAGMA_MARK
4936 #pragma mark Accessors
4937 #endif
4938
4939 /*********************************************************************
4940 *********************************************************************/
4941 const OSObject *
getBundleExecutable(void)4942 OSKext::getBundleExecutable(void)
4943 {
4944 return infoDict->getObject(kCFBundleExecutableKey);
4945 }
4946
4947 /*********************************************************************
4948 *********************************************************************/
4949 const OSSymbol *
getIdentifier(void)4950 OSKext::getIdentifier(void)
4951 {
4952 return bundleID.get();
4953 }
4954
4955 /*********************************************************************
4956 * A kext must have a bundle identifier to even survive initialization;
4957 * this is guaranteed to exist past then.
4958 *********************************************************************/
4959 const char *
getIdentifierCString(void)4960 OSKext::getIdentifierCString(void)
4961 {
4962 return bundleID->getCStringNoCopy();
4963 }
4964
4965 /*********************************************************************
4966 *********************************************************************/
4967 OSKextVersion
getVersion(void)4968 OSKext::getVersion(void)
4969 {
4970 return version;
4971 }
4972
4973 /*********************************************************************
4974 *********************************************************************/
4975 OSKextVersion
getCompatibleVersion(void)4976 OSKext::getCompatibleVersion(void)
4977 {
4978 return compatibleVersion;
4979 }
4980
4981 /*********************************************************************
4982 *********************************************************************/
4983 bool
isLibrary(void)4984 OSKext::isLibrary(void)
4985 {
4986 return getCompatibleVersion() > 0;
4987 }
4988
4989 /*********************************************************************
4990 *********************************************************************/
4991 bool
isCompatibleWithVersion(OSKextVersion aVersion)4992 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4993 {
4994 if ((compatibleVersion > -1 && version > -1) &&
4995 (compatibleVersion <= version && aVersion <= version)) {
4996 return true;
4997 }
4998 return false;
4999 }
5000
5001 /*********************************************************************
5002 *********************************************************************/
5003 bool
declaresExecutable(void)5004 OSKext::declaresExecutable(void)
5005 {
5006 if (isDriverKit()) {
5007 return false;
5008 }
5009 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
5010 }
5011
5012 /*********************************************************************
5013 *********************************************************************/
5014 OSData *
getExecutable(void)5015 OSKext::getExecutable(void)
5016 {
5017 OSData * result = NULL;
5018 OSSharedPtr<OSData> extractedExecutable;
5019
5020 if (flags.builtin) {
5021 return sKernelKext->linkedExecutable.get();
5022 }
5023
5024 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
5025 if (result) {
5026 return result;
5027 }
5028
5029 #if CONFIG_KXLD
5030 OSData * mkextExecutableRef = NULL; // do not release
5031 mkextExecutableRef = OSDynamicCast(OSData,
5032 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
5033
5034 if (mkextExecutableRef) {
5035 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
5036 mkextExecutableRef->getBytesNoCopy();
5037 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
5038 if (mkextVersion == MKEXT_VERS_2) {
5039 mkext2_file_entry * fileinfo =
5040 (mkext2_file_entry *)mkextEntryRef->fileinfo;
5041 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
5042 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
5043 extractedExecutable = extractMkext2FileData(
5044 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
5045 compressedSize, fullSize);
5046 } else {
5047 OSKextLog(this, kOSKextLogErrorLevel |
5048 kOSKextLogArchiveFlag,
5049 "Kext %s - unknown mkext version 0x%x for executable.",
5050 getIdentifierCString(), mkextVersion);
5051 }
5052
5053 /* Regardless of success, remove the mkext executable,
5054 * and drop one reference on the mkext. (setExecutable() does not
5055 * replace, it removes, or panics if asked to replace.)
5056 */
5057 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
5058 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
5059
5060 if (extractedExecutable && extractedExecutable->getLength()) {
5061 if (!setExecutable(extractedExecutable.get())) {
5062 goto finish;
5063 }
5064 result = extractedExecutable.get();
5065 } else {
5066 goto finish;
5067 }
5068 }
5069
5070 finish:
5071 #endif // CONFIG_KXLD
5072 return result;
5073 }
5074
5075 /*********************************************************************
5076 *********************************************************************/
5077 bool
isInterface(void)5078 OSKext::isInterface(void)
5079 {
5080 return flags.interface;
5081 }
5082
5083 /*********************************************************************
5084 *********************************************************************/
5085 bool
isKernel(void)5086 OSKext::isKernel(void)
5087 {
5088 return this == sKernelKext;
5089 }
5090
5091 /*********************************************************************
5092 *********************************************************************/
5093 bool
isKernelComponent(void)5094 OSKext::isKernelComponent(void)
5095 {
5096 return flags.kernelComponent ? true : false;
5097 }
5098
5099 /*********************************************************************
5100 *********************************************************************/
5101 bool
isExecutable(void)5102 OSKext::isExecutable(void)
5103 {
5104 return !isKernel() && !isInterface() && declaresExecutable();
5105 }
5106
5107 /*********************************************************************
5108 *********************************************************************/
5109 bool
isSpecialKernelBinary(void)5110 OSKext::isSpecialKernelBinary(void)
5111 {
5112 #if CONFIG_SPTM
5113 return (this->kmod_info) &&
5114 ((this->kmod_info->id == kOSKextSPTMLoadTag) ||
5115 (this->kmod_info->id == kOSKextTXMLoadTag));
5116 #else
5117 return false;
5118 #endif
5119 }
5120
5121 /*********************************************************************
5122 * We might want to check this recursively for all dependencies,
5123 * since a subtree of dependencies could get loaded before we hit
5124 * a dependency that isn't safe-boot-loadable.
5125 *
5126 * xxx - Might want to return false if OSBundleEnableKextLogging or
5127 * OSBundleDebugLevel
5128 * or IOKitDebug is nonzero too (we used to do that, but I don't see
5129 * the point except it's usually development drivers, which might
5130 * cause panics on startup, that have those properties). Heh; could
5131 * use a "kx" boot-arg!
5132 *********************************************************************/
5133 bool
isLoadableInSafeBoot(void)5134 OSKext::isLoadableInSafeBoot(void)
5135 {
5136 bool result = false;
5137 OSString * required = NULL; // do not release
5138
5139 if (isKernel()) {
5140 result = true;
5141 goto finish;
5142 }
5143
5144 if (isDriverKit()) {
5145 result = true;
5146 goto finish;
5147 }
5148
5149 required = OSDynamicCast(OSString,
5150 getPropertyForHostArch(kOSBundleRequiredKey));
5151 if (!required) {
5152 goto finish;
5153 }
5154 if (required->isEqualTo(kOSBundleRequiredRoot) ||
5155 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
5156 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
5157 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
5158 required->isEqualTo(kOSBundleRequiredConsole)) {
5159 result = true;
5160 }
5161
5162 finish:
5163 return result;
5164 }
5165
5166 /*********************************************************************
5167 *********************************************************************/
5168 bool
isPrelinked(void)5169 OSKext::isPrelinked(void)
5170 {
5171 return flags.prelinked ? true : false;
5172 }
5173
5174 /*********************************************************************
5175 *********************************************************************/
5176 bool
isLoaded(void)5177 OSKext::isLoaded(void)
5178 {
5179 return flags.loaded ? true : false;
5180 }
5181
5182 /*********************************************************************
5183 *********************************************************************/
5184 bool
isStarted(void)5185 OSKext::isStarted(void)
5186 {
5187 return flags.started ? true : false;
5188 }
5189
5190 /*********************************************************************
5191 *********************************************************************/
5192 bool
isCPPInitialized(void)5193 OSKext::isCPPInitialized(void)
5194 {
5195 return flags.CPPInitialized;
5196 }
5197
5198 /*********************************************************************
5199 *********************************************************************/
5200 void
setCPPInitialized(bool initialized)5201 OSKext::setCPPInitialized(bool initialized)
5202 {
5203 flags.CPPInitialized = initialized;
5204 }
5205
5206 /*********************************************************************
5207 *********************************************************************/
5208 uint32_t
getLoadTag(void)5209 OSKext::getLoadTag(void)
5210 {
5211 return loadTag;
5212 }
5213
5214 /*********************************************************************
5215 *********************************************************************/
5216 void
getSizeInfo(uint32_t * loadSize,uint32_t * wiredSize)5217 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
5218 {
5219 if (linkedExecutable) {
5220 *loadSize = linkedExecutable->getLength();
5221
5222 /* If we have a kmod_info struct, calculated the wired size
5223 * from that. Otherwise it's the full load size.
5224 */
5225 if (kmod_info) {
5226 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
5227 } else {
5228 *wiredSize = *loadSize;
5229 }
5230 } else {
5231 *wiredSize = 0;
5232 *loadSize = 0;
5233 }
5234 }
5235
5236 /*********************************************************************
5237 *********************************************************************/
5238 OSSharedPtr<OSData>
copyUUID(void)5239 OSKext::copyUUID(void)
5240 {
5241 OSSharedPtr<OSData> result;
5242 OSData * theExecutable = NULL; // do not release
5243 const kernel_mach_header_t * header;
5244
5245 /* An interface kext doesn't have a linked executable with an LC_UUID,
5246 * we create one when it's linked.
5247 */
5248 if (interfaceUUID) {
5249 result = interfaceUUID;
5250 goto finish;
5251 }
5252
5253 if (flags.builtin || isInterface()) {
5254 return sKernelKext->copyUUID();
5255 }
5256
5257 if (isDriverKit() && infoDict) {
5258 return driverKitUUID;
5259 }
5260
5261 /* For real kexts, try to get the UUID from the linked executable,
5262 * or if is hasn't been linked yet, the unrelocated executable.
5263 */
5264 theExecutable = linkedExecutable.get();
5265 if (!theExecutable) {
5266 theExecutable = getExecutable();
5267 }
5268
5269 if (!theExecutable) {
5270 goto finish;
5271 }
5272
5273 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
5274 result = copyMachoUUID(header);
5275
5276 finish:
5277 return result;
5278 }
5279
5280 /*********************************************************************
5281 *********************************************************************/
5282 OSSharedPtr<OSData>
copyTextUUID(void)5283 OSKext::copyTextUUID(void)
5284 {
5285 if (flags.builtin) {
5286 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
5287 }
5288 return copyUUID();
5289 }
5290
5291 /*********************************************************************
5292 *********************************************************************/
5293 OSSharedPtr<OSData>
copyMachoUUID(const kernel_mach_header_t * header)5294 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
5295 {
5296 OSSharedPtr<OSData> result;
5297 const struct load_command * load_cmd = NULL;
5298 const struct uuid_command * uuid_cmd = NULL;
5299 uint32_t i;
5300
5301 load_cmd = (const struct load_command *)&header[1];
5302
5303 if (header->magic != MH_MAGIC_KERNEL) {
5304 OSKextLog(NULL,
5305 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5306 "%s: bad header %p",
5307 __func__,
5308 header);
5309 goto finish;
5310 }
5311
5312 for (i = 0; i < header->ncmds; i++) {
5313 if (load_cmd->cmd == LC_UUID) {
5314 uuid_cmd = (struct uuid_command *)load_cmd;
5315 result = OSData::withValue(uuid_cmd->uuid);
5316 goto finish;
5317 }
5318 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
5319 }
5320
5321 finish:
5322 return result;
5323 }
5324
5325 void
setDriverKitUUID(OSData * uuid)5326 OSKext::setDriverKitUUID(OSData *uuid)
5327 {
5328 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
5329 OSSafeReleaseNULL(uuid);
5330 }
5331 }
5332
5333 OSData *
getDextUniqueID(void)5334 OSKext::getDextUniqueID(void)
5335 {
5336 if (isDriverKit() && dextUniqueID != NULL) {
5337 return dextUniqueID.get();
5338 }
5339
5340 return NULL;
5341 }
5342
5343 /*
5344 * In case a DextUniqueID exists this function returns
5345 * an allocated char* with the hexadecimal represantition of
5346 * DextUniqueID.
5347 * The returned pinter needs to be freed with kfree_data, the
5348 * size of the allocated buffer is returned in size.
5349 */
5350 static const char *
getDextUniqueIDCString(OSData * dextUniqueID,unsigned int * size)5351 getDextUniqueIDCString(OSData *dextUniqueID, unsigned int *size)
5352 {
5353 if (dextUniqueID != NULL) {
5354 char *s_buffer = NULL;
5355 unsigned int d_length = dextUniqueID->getLength();
5356 /*
5357 * We are converting in hex, so for every byte we will have
5358 * 2 hex chars and one last \0.
5359 */
5360 unsigned int s_length = d_length * 2 + 1;
5361 s_buffer = (char *) kalloc_data(s_length, Z_WAITOK_ZERO);
5362
5363 char *uid = (char*) dextUniqueID->getBytesNoCopy();
5364 int cpos = 0;
5365 for (unsigned int i = 0; i < d_length && cpos < (s_length - 1); i++) {
5366 int ret = snprintf(s_buffer + cpos, s_length - cpos - 1, "%02X", uid[i]);
5367 if (ret <= 0) {
5368 break;
5369 }
5370 cpos += ret;
5371 }
5372 *size = s_length;
5373
5374 return s_buffer;
5375 }
5376
5377 return NULL;
5378 }
5379
5380 /*
5381 * Atomically swaps the olddext with newdext.
5382 * olddext will be unloaded, so it might be freed
5383 * after this call unless it was previously retained.
5384 *
5385 * If newdext is NULL, this unloads olddext and does not perform an upgrade
5386 */
5387 void
replaceDextInternal(OSKext * olddext,OSKext * newdext)5388 OSKext::replaceDextInternal(OSKext *olddext, OSKext *newdext)
5389 {
5390 OSReturn result;
5391 const OSSymbol * dextID = olddext->getIdentifier();
5392 OSData * oldDextUniqueIdentifier = olddext->getDextUniqueID();
5393 OSSharedPtr<OSArray> new_personalities;
5394 OSSharedPtr<OSString> kextIdentifier;
5395 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5396 assert(lock_held);
5397
5398 // The old dext will be unloaded and release dextID, so we need to retain dextID here
5399 dextID->retain();
5400
5401 if (newdext != NULL) {
5402 __assert_only bool eq = dextID->isEqualTo(newdext->getIdentifier());
5403 assert(eq);
5404 }
5405
5406 if (newdext != NULL) {
5407 /*
5408 * Swap the catalog personalities.
5409 */
5410 new_personalities = newdext->copyPersonalitiesArray();
5411 olddext->updatePersonalitiesInCatalog(new_personalities.get());
5412 }
5413
5414 if (NULL != oldDextUniqueIdentifier) {
5415 oldDextUniqueIdentifier->retain();
5416 }
5417
5418 /*
5419 * Unload the dext.
5420 */
5421 result = olddext->unload();
5422 if (result != kOSReturnSuccess) {
5423 OSKextLog(NULL,
5424 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5425 "Cannot unload dext for upgrade %s: %d\n",
5426 dextID->getCStringNoCopy(), result);
5427 }
5428
5429 if (newdext != NULL) {
5430 /*
5431 * Swap the dexts on the OSKext dictionary.
5432 * This might free the dext.
5433 */
5434 sKextsByID->setObject(dextID, newdext);
5435 } else {
5436 /*
5437 * Remove the old dext
5438 */
5439 removeKext(olddext, true);
5440 }
5441
5442 /*
5443 * Inform userspace.
5444 */
5445 if (newdext != NULL) {
5446 result = notifyDextUpgrade(OSDynamicCast(OSString, dextID), newdext->getDextUniqueID());
5447 if (result != kOSReturnSuccess) {
5448 OSKextLog(NULL,
5449 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5450 "Cannot send upgrade notification for %s\n",
5451 dextID->getCStringNoCopy());
5452 }
5453 } else {
5454 // notify dext removal
5455 queueKextNotification(kKextRequestPredicateUnloadNotification,
5456 OSDynamicCast(OSString, dextID), oldDextUniqueIdentifier);
5457 }
5458
5459 OSSafeReleaseNULL(dextID);
5460 OSSafeReleaseNULL(oldDextUniqueIdentifier);
5461 }
5462
5463 /*
5464 * To be called with sKextLock held.
5465 * NOTE: this could unload the olddext.
5466 */
5467 bool
upgradeDext(OSKext * olddext,OSKext * newdext)5468 OSKext::upgradeDext(OSKext *olddext, OSKext *newdext)
5469 {
5470 const char * dextIDCS = newdext->getIdentifierCString();
5471 __assert_only bool old_isDext = olddext->isDriverKit();
5472 __assert_only bool new_isDext = newdext->isDriverKit();
5473 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5474
5475 assert(old_isDext && new_isDext);
5476 assert(lock_held);
5477
5478 /*
5479 * New dext and old dext have the same ID.
5480 * We use this ID as key on the OSKext
5481 * dictionarys/arrays.
5482 */
5483 const OSSymbol * dextID = newdext->getIdentifier();
5484 __assert_only bool eq = dextID->isEqualTo(olddext->getIdentifier());
5485 assert(eq);
5486
5487 /*
5488 * Set this OSKect as to update.
5489 * Note that this flags will never be removed once set.
5490 * When a OSKext is marked, it will be substitued by a new
5491 * OSKext, and every subsystem having a reference on this
5492 * OSKext need to know they have check if they can use
5493 * this OSKext or look for a new one.
5494 */
5495 olddext->flags.dextToReplace = 1;
5496
5497 /*
5498 * Check if the current OSKext has any
5499 * userspace processes launched.
5500 * In this case we cannot upgrade and we have to
5501 * delay the upgrade until all processes
5502 * are done.
5503 */
5504 if (olddext->dextLaunchedCount == 0) {
5505 /*
5506 * Be sure that if there are no launched dexts, no
5507 * pending upgrades exist.
5508 * This is an error if it happens, as the decrement
5509 * should have removed the dext from sDriverKitToUpgradeByID
5510 * in case it reached 0.
5511 */
5512 OSObject *pending_upgdare = sDriverKitToUpgradeByID->getObject(dextID);
5513 if (pending_upgdare != NULL) {
5514 OSKextLog(NULL,
5515 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5516 "Pending upgrade found for %s but dextLaunchedCount is 0!\n",
5517 dextIDCS);
5518 goto out;
5519 }
5520
5521 replaceDextInternal(olddext, newdext);
5522 return true;
5523 }
5524
5525 out:
5526
5527 /*
5528 * Delay the upgrade.
5529 * Make the new dext available in sDriverKitToUpgradeByID.
5530 * In case there was already a pending upgrade, this will
5531 * overwrite it.
5532 */
5533 sDriverKitToUpgradeByID->setObject(dextID, newdext);
5534 return false;
5535 }
5536
5537 /*
5538 * To be called with sKextLock held.
5539 * NOTE: this could unload the dext.
5540 */
5541 bool
removeDext(OSKext * dext)5542 OSKext::removeDext(OSKext *dext)
5543 {
5544 __assert_only bool dext_isDext = dext->isDriverKit();
5545 __assert_only bool lock_held = IORecursiveLockHaveLock(sKextLock);
5546 IOReturn result;
5547
5548 assert(dext_isDext);
5549 assert(lock_held);
5550
5551 /*
5552 * Set this OSKext to be unloaded when all running instances exit.
5553 */
5554 dext->flags.dextToReplace = 1;
5555
5556 result = gIOCatalogue->terminateDriversForModule(
5557 dext->getIdentifierCString(), /* unload */ false, /* asynchronous */ true);
5558 if (result != kOSReturnSuccess) {
5559 OSKextLog(dext,
5560 kOSKextLogErrorLevel |
5561 kOSKextLogKextBookkeepingFlag,
5562 "%s services failed to terminate - 0x%x.",
5563 dext->getIdentifierCString(), result);
5564 }
5565
5566 dext->removePersonalitiesFromCatalog();
5567 sDriverKitToUpgradeByID->removeObject(dext->getIdentifier());
5568
5569 /*
5570 * Check if the current OSKext has any
5571 * userspace processes launched.
5572 * In this case we cannot unload and we have to
5573 * delay the unload until all processes
5574 * are done.
5575 */
5576 if (dext->dextLaunchedCount == 0) {
5577 replaceDextInternal(dext, NULL);
5578 return true;
5579 }
5580
5581 return false;
5582 }
5583
5584 bool
incrementDextLaunchCount(OSKext * dext,OSData * dextUniqueIDToMatch)5585 OSKext::incrementDextLaunchCount(OSKext *dext, OSData *dextUniqueIDToMatch)
5586 {
5587 bool ret = false;
5588 __assert_only bool isDext = dext->isDriverKit();
5589 assert(isDext);
5590
5591 const char * dextIDCS = dext->getIdentifierCString();
5592 OSData *myDextUniqueID = dext->getDextUniqueID();
5593
5594 if (!myDextUniqueID || !dextUniqueIDToMatch) {
5595 OSKextLog(dext,
5596 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5597 "Cannot find dext UniqueID for %s, cannot increment dext launches\n",
5598 dextIDCS);
5599 return ret;
5600 }
5601
5602 unsigned int dextUniqueIDCStringSize = 0, dextUniqueIDToMatchCStringSize = 0;
5603 const char *dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5604 const char *dextUniqueIDToMatchCString = getDextUniqueIDCString(dextUniqueIDToMatch, &dextUniqueIDToMatchCStringSize);
5605 assert(dextUniqueIDCString != NULL);
5606 assert(dextUniqueIDToMatchCString != NULL);
5607
5608 IORecursiveLockLock(sKextLock);
5609
5610 /*
5611 * Check that the dext we are referencing is the same
5612 * looked for the match.
5613 */
5614 if (myDextUniqueID->isEqualTo(dextUniqueIDToMatch)) {
5615 if (dext->flags.dextToReplace == 0 || dext->dextLaunchedCount > 0) {
5616 if (dext->dextLaunchedCount == kOSKextMaxDextLaunchedCount) {
5617 OSKextLog(dext,
5618 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5619 "Too many dexts launched for %s UniqueID %s\n",
5620 dextIDCS, dextUniqueIDCString);
5621 } else {
5622 dext->dextLaunchedCount++;
5623 ret = true;
5624
5625 OSKextLog(dext,
5626 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5627 "New dext launched for %s UniqueID %s",
5628 dextIDCS, dextUniqueIDCString);
5629 }
5630 } else {
5631 OSKextLog(dext,
5632 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5633 "Dext %s UniqueID %s requires update, cannot launch a new dext\n",
5634 dextIDCS, dextUniqueIDCString);
5635 }
5636 } else {
5637 OSKextLog(dext,
5638 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5639 "Dext %s: UniqueID %s does not match UniqueID looked for %s, cannot launch a new dext\n",
5640 dextIDCS, dextUniqueIDCString, dextUniqueIDToMatchCString);
5641 }
5642
5643 IORecursiveLockUnlock(sKextLock);
5644
5645 if (dextUniqueIDCString != NULL) {
5646 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5647 }
5648 if (dextUniqueIDToMatchCString != NULL) {
5649 kfree_data(dextUniqueIDToMatchCString, dextUniqueIDToMatchCStringSize);
5650 }
5651 return ret;
5652 }
5653
5654 bool
decrementDextLaunchCount(OSString * bundleID)5655 OSKext::decrementDextLaunchCount(OSString *bundleID)
5656 {
5657 bool ret = false;
5658 const char * dextIDCS;
5659 OSData *myDextUniqueID;
5660 unsigned int dextUniqueIDCStringSize = 0;
5661 const char * dextUniqueIDCString = NULL;
5662 OSKext* dext = NULL;
5663
5664 if (!bundleID) {
5665 return ret;
5666 }
5667 dextIDCS = bundleID->getCStringNoCopy();
5668
5669 IORecursiveLockLock(sKextLock);
5670
5671 /*
5672 * Look for the dext with the bundle it. This
5673 * call is triggered only if a previous increment was
5674 * performed. It means that the dext could have not
5675 * been upgraded as its dextLaunchedCount was at least 1.
5676 * Because of this it still needs to be available
5677 * in sKextsByID.
5678 */
5679 dext = OSDynamicCast(OSKext, sKextsByID->getObject(dextIDCS));
5680 if (!dext || !dext->isDriverKit()) {
5681 OSKextLog(NULL,
5682 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5683 "Cannot find dext for %s, cannot decrement dext launches\n",
5684 dextIDCS);
5685
5686 goto out_locked;
5687 }
5688
5689 myDextUniqueID = dext->getDextUniqueID();
5690 if (!myDextUniqueID) {
5691 OSKextLog(dext,
5692 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5693 "Cannot find dext UniqueID for %s, cannot decrement dext launches\n",
5694 dextIDCS);
5695
5696 goto out_locked;
5697 }
5698 dextUniqueIDCString = getDextUniqueIDCString(myDextUniqueID, &dextUniqueIDCStringSize);
5699 assert(dextUniqueIDCString != NULL);
5700
5701 if (dext->dextLaunchedCount == 0) {
5702 OSKextLog(dext,
5703 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5704 "Over decrementing dext launch for %s UniqueID %s\n",
5705 dextIDCS, dextUniqueIDCString);
5706
5707 goto out_locked;
5708 }
5709
5710 dext->dextLaunchedCount--;
5711
5712 OSKextLog(dext,
5713 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5714 "Dext terminated for %s UniqueID %s",
5715 dextIDCS, dextUniqueIDCString);
5716
5717 if (dext->dextLaunchedCount == 0 && dext->flags.dextToReplace == 1) {
5718 /*
5719 * Find the upgraded dext.
5720 */
5721 OSKext *newdext = OSDynamicCast(OSKext, sDriverKitToUpgradeByID->getObject(dextIDCS));
5722 if (newdext) {
5723 OSKextLog(dext,
5724 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5725 "Dext upgrade for %s UniqueID %s",
5726 dextIDCS, dextUniqueIDCString);
5727 replaceDextInternal(dext, newdext);
5728 /* NOTE dext could have been freed past this point */
5729
5730 sDriverKitToUpgradeByID->removeObject(dextIDCS);
5731 } else {
5732 OSKextLog(dext,
5733 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5734 "Dext unload for %s UniqueID %s",
5735 dextIDCS, dextUniqueIDCString);
5736 replaceDextInternal(dext, NULL);
5737 }
5738
5739 ret = true;
5740 }
5741 out_locked:
5742 IORecursiveLockUnlock(sKextLock);
5743
5744 if (dextUniqueIDCString != NULL) {
5745 kfree_data(dextUniqueIDCString, dextUniqueIDCStringSize);
5746 }
5747
5748 return ret;
5749 }
5750
5751 /*********************************************************************
5752 *********************************************************************/
5753 #if defined (__arm__)
5754 #include <arm/arch.h>
5755 #endif
5756
5757 #if defined (__x86_64__)
5758 #define ARCHNAME "x86_64"
5759 #elif defined (__arm64__)
5760 #define ARCHNAME "arm64"
5761 #elif defined (__arm__)
5762
5763 #if defined (__ARM_ARCH_7S__)
5764 #define ARCHNAME "armv7s"
5765 #elif defined (__ARM_ARCH_7F__)
5766 #define ARCHNAME "armv7f"
5767 #elif defined (__ARM_ARCH_7K__)
5768 #define ARCHNAME "armv7k"
5769 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
5770 #define ARCHNAME "armv7"
5771 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
5772 #define ARCHNAME "armv6"
5773 #endif
5774
5775 #elif defined (__arm64__)
5776 #define ARCHNAME "arm64"
5777 #else
5778 #error architecture not supported
5779 #endif
5780
5781 #define ARCH_SEPARATOR_CHAR '_'
5782
5783 static char *
makeHostArchKey(const char * key,size_t * keySizeOut)5784 makeHostArchKey(const char * key, size_t * keySizeOut)
5785 {
5786 char * result = NULL;
5787 size_t keyLength = strlen(key);
5788 size_t keySize;
5789
5790 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
5791 */
5792 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
5793 result = (char *)kalloc_data_tag(keySize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5794
5795 if (!result) {
5796 goto finish;
5797 }
5798 strlcpy(result, key, keySize);
5799 result[keyLength++] = ARCH_SEPARATOR_CHAR;
5800 result[keyLength] = '\0';
5801 strlcat(result, ARCHNAME, keySize);
5802 *keySizeOut = keySize;
5803
5804 finish:
5805 return result;
5806 }
5807
5808 /*********************************************************************
5809 *********************************************************************/
5810 OSObject *
getPropertyForHostArch(const char * key)5811 OSKext::getPropertyForHostArch(const char * key)
5812 {
5813 OSObject * result = NULL;// do not release
5814 size_t hostArchKeySize = 0;
5815 char * hostArchKey = NULL;// must kfree
5816
5817 if (!key || !infoDict) {
5818 goto finish;
5819 }
5820
5821 /* Some properties are not allowed to be arch-variant:
5822 * - Any CFBundle... property.
5823 * - OSBundleIsInterface.
5824 * - OSKernelResource.
5825 */
5826 if (STRING_HAS_PREFIX(key, "OS") ||
5827 STRING_HAS_PREFIX(key, "IO")) {
5828 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
5829 if (!hostArchKey) {
5830 OSKextLog(/* kext (this isn't about a kext) */ NULL,
5831 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
5832 "Allocation failure.");
5833 goto finish;
5834 }
5835 result = infoDict->getObject(hostArchKey);
5836 }
5837
5838 if (!result) {
5839 result = infoDict->getObject(key);
5840 }
5841
5842 finish:
5843 if (hostArchKey) {
5844 kfree_data(hostArchKey, hostArchKeySize);
5845 }
5846 return result;
5847 }
5848
5849 #if PRAGMA_MARK
5850 #pragma mark Load/Start/Stop/Unload
5851 #endif
5852
5853 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
5854
5855 /*********************************************************************
5856 * sExcludeListByID is a dictionary with keys / values of:
5857 * key = bundleID string of kext we will not allow to load
5858 * value = version string(s) of the kext that is to be denied loading.
5859 * The version strings can be comma delimited. For example if kext
5860 * com.foocompany.fookext has two versions that we want to deny
5861 * loading then the version strings might look like:
5862 * 1.0.0, 1.0.1
5863 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
5864 * not load the kext.
5865 *
5866 * Value may also be in the form of "LE 2.0.0" (version numbers
5867 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
5868 * number less than 2.0.0 will not load)
5869 *
5870 * NOTE - we cannot use the characters "<=" or "<" because we have code
5871 * that serializes plists and treats '<' as a special character.
5872 *********************************************************************/
5873 bool
isInExcludeList(void)5874 OSKext::isInExcludeList(void)
5875 {
5876 OSString * versionString = NULL; // do not release
5877 char * versionCString = NULL; // do not free
5878 size_t i;
5879 boolean_t wantLessThan = false;
5880 boolean_t wantLessThanEqualTo = false;
5881 boolean_t isInExcludeList = true;
5882 char myBuffer[32];
5883
5884 IORecursiveLockLock(sKextLock);
5885
5886 if (!sExcludeListByID) {
5887 isInExcludeList = false;
5888 } else {
5889 /* look up by bundleID in our exclude list and if found get version
5890 * string (or strings) that we will not allow to load
5891 */
5892 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
5893 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
5894 isInExcludeList = false;
5895 }
5896 }
5897
5898 IORecursiveLockUnlock(sKextLock);
5899
5900 if (!isInExcludeList) {
5901 return false;
5902 }
5903
5904 /* parse version strings */
5905 versionCString = (char *) versionString->getCStringNoCopy();
5906
5907 /* look for "LT" or "LE" form of version string, must be in first two
5908 * positions.
5909 */
5910 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
5911 wantLessThan = true;
5912 versionCString += 2;
5913 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
5914 wantLessThanEqualTo = true;
5915 versionCString += 2;
5916 }
5917
5918 for (i = 0; *versionCString != 0x00; versionCString++) {
5919 /* skip whitespace */
5920 if (isWhiteSpace(*versionCString)) {
5921 continue;
5922 }
5923
5924 /* peek ahead for version string separator or null terminator */
5925 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
5926 /* OK, we have a version string */
5927 myBuffer[i++] = *versionCString;
5928 myBuffer[i] = 0x00;
5929
5930 OSKextVersion excludeVers;
5931 excludeVers = OSKextParseVersionString(myBuffer);
5932
5933 if (wantLessThanEqualTo) {
5934 if (version <= excludeVers) {
5935 return true;
5936 }
5937 } else if (wantLessThan) {
5938 if (version < excludeVers) {
5939 return true;
5940 }
5941 } else if (version == excludeVers) {
5942 return true;
5943 }
5944
5945 /* reset for the next (if any) version string */
5946 i = 0;
5947 wantLessThan = false;
5948 wantLessThanEqualTo = false;
5949 } else {
5950 /* save valid version character */
5951 myBuffer[i++] = *versionCString;
5952
5953 /* make sure bogus version string doesn't overrun local buffer */
5954 if (i >= sizeof(myBuffer)) {
5955 break;
5956 }
5957 }
5958 }
5959
5960 return false;
5961 }
5962
5963 /*********************************************************************
5964 * sNonLoadableKextsByID is a dictionary with keys / values of:
5965 * key = bundleID string of kext we will not allow to load
5966 * value = boolean (true == loadable, false == not loadable)
5967 *
5968 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5969 * i.e., the value for the kext's bundleID will be false. All kexts in
5970 * the primary and system KCs will always be marked as "loadable."
5971 *
5972 * This list ultimately comes from kexts which have been uninstalled
5973 * in user space by deleting the kext from disk, but which have not
5974 * yet been removed from the AuxKC. Because the user could choose to
5975 * re-install the exact same version of the kext, we need to keep
5976 * a dictionary of boolean values so that user space only needs to
5977 * keep a simple list of "uninstalled" or "missing" bundles. When
5978 * a bundle is re-installed, the iokit daemon can use the
5979 * AucKCBundleAvailable predicate to set the individual kext's
5980 * availability to true.
5981 *********************************************************************/
5982 bool
isLoadable(void)5983 OSKext::isLoadable(void)
5984 {
5985 bool isLoadable = true;
5986
5987 if (kc_type != KCKindAuxiliary) {
5988 /* this filtering only applies to kexts in the auxkc */
5989 return true;
5990 }
5991
5992 IORecursiveLockLock(sKextLock);
5993
5994 if (sNonLoadableKextsByID) {
5995 /* look up by bundleID in our exclude list and if found get version
5996 * string (or strings) that we will not allow to load
5997 */
5998 OSBoolean *loadableVal;
5999 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
6000 if (loadableVal && !loadableVal->getValue()) {
6001 isLoadable = false;
6002 }
6003 }
6004 IORecursiveLockUnlock(sKextLock);
6005
6006 return isLoadable;
6007 }
6008
6009 /*********************************************************************
6010 *********************************************************************/
6011 /* static */
6012 OSReturn
loadKextWithIdentifier(const char * kextIdentifierCString,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6013 OSKext::loadKextWithIdentifier(
6014 const char * kextIdentifierCString,
6015 Boolean allowDeferFlag,
6016 Boolean delayAutounloadFlag,
6017 OSKextExcludeLevel startOpt,
6018 OSKextExcludeLevel startMatchingOpt,
6019 OSArray * personalityNames)
6020 {
6021 OSReturn result = kOSReturnError;
6022 OSSharedPtr<OSString> kextIdentifier;
6023
6024 kextIdentifier = OSString::withCString(kextIdentifierCString);
6025 if (!kextIdentifier) {
6026 result = kOSKextReturnNoMemory;
6027 goto finish;
6028 }
6029 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
6030 NULL /* kextRef */,
6031 allowDeferFlag, delayAutounloadFlag,
6032 startOpt, startMatchingOpt, personalityNames);
6033
6034 finish:
6035 return result;
6036 }
6037
6038 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSSharedPtr<OSObject> & kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6039 OSKext::loadKextWithIdentifier(
6040 OSString * kextIdentifier,
6041 OSSharedPtr<OSObject> &kextRef,
6042 Boolean allowDeferFlag,
6043 Boolean delayAutounloadFlag,
6044 OSKextExcludeLevel startOpt,
6045 OSKextExcludeLevel startMatchingOpt,
6046 OSArray * personalityNames)
6047 {
6048 OSObject * kextRefRaw = NULL;
6049 OSReturn result;
6050
6051 result = loadKextWithIdentifier(kextIdentifier,
6052 &kextRefRaw,
6053 allowDeferFlag,
6054 delayAutounloadFlag,
6055 startOpt,
6056 startMatchingOpt,
6057 personalityNames);
6058 if ((kOSReturnSuccess == result) && kextRefRaw) {
6059 kextRef.reset(kextRefRaw, OSNoRetain);
6060 }
6061 return result;
6062 }
6063
6064 /*********************************************************************
6065 *********************************************************************/
6066 OSReturn
loadKextWithIdentifier(OSString * kextIdentifier,OSObject ** kextRef,Boolean allowDeferFlag,Boolean delayAutounloadFlag,OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6067 OSKext::loadKextWithIdentifier(
6068 OSString * kextIdentifier,
6069 OSObject ** kextRef,
6070 Boolean allowDeferFlag,
6071 Boolean delayAutounloadFlag,
6072 OSKextExcludeLevel startOpt,
6073 OSKextExcludeLevel startMatchingOpt,
6074 OSArray * personalityNames)
6075 {
6076 OSReturn result = kOSReturnError;
6077 OSReturn pingResult = kOSReturnError;
6078 OSKext * theKext = NULL; // do not release
6079 OSSharedPtr<OSDictionary> loadRequest;
6080 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6081
6082 if (kextRef) {
6083 *kextRef = NULL;
6084 }
6085
6086 IORecursiveLockLock(sKextLock);
6087
6088 if (!kextIdentifier) {
6089 result = kOSKextReturnInvalidArgument;
6090 goto finish;
6091 }
6092
6093 OSKext::recordIdentifierRequest(kextIdentifier);
6094
6095 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
6096 if (!theKext) {
6097 if (!allowDeferFlag) {
6098 OSKextLog(/* kext */ NULL,
6099 kOSKextLogErrorLevel |
6100 kOSKextLogLoadFlag,
6101 "Can't load kext %s - not found.",
6102 kextIdentifier->getCStringNoCopy());
6103 goto finish;
6104 }
6105
6106 if (!sKernelRequestsEnabled) {
6107 OSKextLog(theKext,
6108 kOSKextLogErrorLevel |
6109 kOSKextLogLoadFlag,
6110 "Can't load kext %s - requests to user space are disabled.",
6111 kextIdentifier->getCStringNoCopy());
6112 result = kOSKextReturnDisabled;
6113 goto finish;
6114 }
6115
6116 /* Create a new request unless one is already sitting
6117 * in sKernelRequests for this bundle identifier
6118 */
6119 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6120 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6121 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
6122 loadRequest);
6123 if (result != kOSReturnSuccess) {
6124 goto finish;
6125 }
6126 if (!_OSKextSetRequestArgument(loadRequest.get(),
6127 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
6128 result = kOSKextReturnNoMemory;
6129 goto finish;
6130 }
6131 if (!sKernelRequests->setObject(loadRequest.get())) {
6132 result = kOSKextReturnNoMemory;
6133 goto finish;
6134 }
6135
6136 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6137 result = kOSKextReturnNoMemory;
6138 goto finish;
6139 }
6140
6141 OSKextLog(theKext,
6142 kOSKextLogDebugLevel |
6143 kOSKextLogLoadFlag,
6144 "Kext %s not found; queued load request to user space.",
6145 kextIdentifier->getCStringNoCopy());
6146 }
6147
6148 pingResult = OSKext::pingIOKitDaemon();
6149 if (pingResult == kOSKextReturnDisabled) {
6150 OSKextLog(/* kext */ NULL,
6151 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
6152 kOSKextLogLoadFlag,
6153 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
6154 kextIdentifier->getCStringNoCopy());
6155 }
6156
6157 result = kOSKextReturnDeferred;
6158 goto finish;
6159 }
6160
6161 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
6162
6163 if (result != kOSReturnSuccess) {
6164 OSKextLog(theKext,
6165 kOSKextLogErrorLevel |
6166 kOSKextLogLoadFlag,
6167 "Failed to load kext %s (error 0x%x).",
6168 kextIdentifier->getCStringNoCopy(), (int)result);
6169
6170 if (theKext->kc_type == KCKindUnknown) {
6171 OSKext::removeKext(theKext,
6172 /* terminateService/removePersonalities */ true);
6173 }
6174 goto finish;
6175 }
6176
6177 if (delayAutounloadFlag) {
6178 OSKextLog(theKext,
6179 kOSKextLogProgressLevel |
6180 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6181 "Setting delayed autounload for %s.",
6182 kextIdentifier->getCStringNoCopy());
6183 theKext->flags.delayAutounload = 1;
6184 }
6185
6186 finish:
6187 if ((kOSReturnSuccess == result) && kextRef) {
6188 *kextRef = theKext;
6189 theKext->matchingRefCount++;
6190 theKext->retain();
6191 }
6192
6193 IORecursiveLockUnlock(sKextLock);
6194
6195 return result;
6196 }
6197
6198 /*********************************************************************
6199 *********************************************************************/
6200 /* static */
6201 OSReturn
loadKextFromKC(OSKext * theKext,OSDictionary * requestDict)6202 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
6203 {
6204 OSReturn result = kOSReturnError;
6205
6206 OSBoolean *delayAutounloadBool = NULL; // do not release
6207 OSNumber *startKextExcludeNum = NULL; // do not release
6208 OSNumber *startMatchingExcludeNum = NULL; // do not release
6209 OSArray *personalityNames = NULL; // do not release
6210
6211 /*
6212 * Default values for these options:
6213 * regular autounload behavior
6214 * start the kext
6215 * send all personalities to the catalog
6216 */
6217 Boolean delayAutounload = false;
6218 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
6219 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
6220
6221 IORecursiveLockLock(sKextLock);
6222
6223 OSKextLog(/* kext */ NULL,
6224 kOSKextLogDebugLevel |
6225 kOSKextLogIPCFlag,
6226 "Received kext KC load request from user space.");
6227
6228 /* Regardless of processing, the fact that we have gotten here means some
6229 * user-space program is up and talking to us, so we'll switch our kext
6230 * registration to reflect that.
6231 */
6232 if (!sUserLoadsActive) {
6233 OSKextLog(/* kext */ NULL,
6234 kOSKextLogProgressLevel |
6235 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6236 "Switching to late startup (user-space) kext loading policy.");
6237 sUserLoadsActive = true;
6238 }
6239
6240 delayAutounloadBool = OSDynamicCast(OSBoolean,
6241 _OSKextGetRequestArgument(requestDict,
6242 kKextRequestArgumentDelayAutounloadKey));
6243 startKextExcludeNum = OSDynamicCast(OSNumber,
6244 _OSKextGetRequestArgument(requestDict,
6245 kKextRequestArgumentStartExcludeKey));
6246 startMatchingExcludeNum = OSDynamicCast(OSNumber,
6247 _OSKextGetRequestArgument(requestDict,
6248 kKextRequestArgumentStartMatchingExcludeKey));
6249 personalityNames = OSDynamicCast(OSArray,
6250 _OSKextGetRequestArgument(requestDict,
6251 kKextRequestArgumentPersonalityNamesKey));
6252
6253 if (delayAutounloadBool) {
6254 delayAutounload = delayAutounloadBool->getValue();
6255 }
6256 if (startKextExcludeNum) {
6257 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
6258 }
6259 if (startMatchingExcludeNum) {
6260 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
6261 }
6262
6263 OSKextLog(/* kext */ NULL,
6264 kOSKextLogProgressLevel |
6265 kOSKextLogIPCFlag,
6266 "Received request from user space to load KC kext %s.",
6267 theKext->getIdentifierCString());
6268
6269 /* this could be in the Auxiliary KC, so record the load request */
6270 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
6271
6272 /*
6273 * Load the kext
6274 */
6275 result = theKext->load(startKextExcludeLevel,
6276 startMatchingExcludeLevel, personalityNames);
6277
6278 if (result != kOSReturnSuccess) {
6279 OSKextLog(theKext,
6280 kOSKextLogErrorLevel |
6281 kOSKextLogLoadFlag,
6282 "Failed to load kext %s (error 0x%x).",
6283 theKext->getIdentifierCString(), (int)result);
6284
6285 OSKext::removeKext(theKext,
6286 /* terminateService/removePersonalities */ true);
6287 goto finish;
6288 } else {
6289 OSKextLog(theKext,
6290 kOSKextLogProgressLevel |
6291 kOSKextLogLoadFlag,
6292 "Kext %s Loaded successfully from %s KC",
6293 theKext->getIdentifierCString(), theKext->getKCTypeString());
6294 }
6295
6296 if (delayAutounload) {
6297 OSKextLog(theKext,
6298 kOSKextLogProgressLevel |
6299 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6300 "Setting delayed autounload for %s.",
6301 theKext->getIdentifierCString());
6302 theKext->flags.delayAutounload = 1;
6303 }
6304
6305 finish:
6306 IORecursiveLockUnlock(sKextLock);
6307
6308 return result;
6309 }
6310
6311 /*********************************************************************
6312 *********************************************************************/
6313 /* static */
6314 OSReturn
loadCodelessKext(OSString * kextIdentifier,OSDictionary * requestDict)6315 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
6316 {
6317 OSReturn result = kOSReturnError;
6318 OSDictionary *anInfoDict = NULL; // do not release
6319
6320 anInfoDict = OSDynamicCast(OSDictionary,
6321 _OSKextGetRequestArgument(requestDict,
6322 kKextRequestArgumentCodelessInfoKey));
6323 if (anInfoDict == NULL) {
6324 OSKextLog(/* kext */ NULL,
6325 kOSKextLogErrorLevel |
6326 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6327 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
6328 kextIdentifier->getCStringNoCopy());
6329 return kOSKextReturnInvalidArgument;
6330 }
6331
6332 IORecursiveLockLock(sKextLock);
6333
6334 OSKextLog(/* kext */ NULL,
6335 kOSKextLogProgressLevel |
6336 kOSKextLogIPCFlag,
6337 "Received request from user space to load codeless kext %s.",
6338 kextIdentifier->getCStringNoCopy());
6339
6340 {
6341 // instantiate a new kext, and don't hold a reference
6342 // (the kext subsystem will hold one implicitly)
6343 OSKextInitResult ret;
6344 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict, &ret);
6345 if (!newKext) {
6346 /*
6347 * We might have failed to create a new OSKext
6348 * because the old one should still be used.
6349 * Check if that is the case.
6350 */
6351 if (ret != kOSKextInitFailure) {
6352 result = kOSReturnSuccess;
6353 goto finish;
6354 }
6355 OSKextLog(/* kext */ NULL,
6356 kOSKextLogErrorLevel |
6357 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6358 "Could not instantiate codeless kext.");
6359 result = kOSKextReturnNotLoadable;
6360 goto finish;
6361 }
6362 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
6363 OSKextLog(/* kext */ NULL,
6364 kOSKextLogErrorLevel |
6365 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
6366 "Codeless kext identifiers don't match '%s' != '%s'",
6367 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
6368
6369 OSKext::removeKext(newKext.get(), false);
6370 result = kOSKextReturnInvalidArgument;
6371 goto finish;
6372 }
6373
6374 /* Record the request for the codeless kext */
6375 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
6376
6377 result = kOSReturnSuccess;
6378 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
6379 result = newKext->sendPersonalitiesToCatalog(true, NULL);
6380 }
6381
6382 finish:
6383 IORecursiveLockUnlock(sKextLock);
6384
6385 return result;
6386 }
6387
6388 /*********************************************************************
6389 *********************************************************************/
6390 /* static */
6391 void
dropMatchingReferences(OSSet * kexts)6392 OSKext::dropMatchingReferences(
6393 OSSet * kexts)
6394 {
6395 IORecursiveLockLock(sKextLock);
6396 kexts->iterateObjects(^bool (OSObject * obj) {
6397 OSKext * thisKext = OSDynamicCast(OSKext, obj);
6398 if (!thisKext) {
6399 return false;
6400 }
6401 thisKext->matchingRefCount--;
6402 return false;
6403 });
6404 IORecursiveLockUnlock(sKextLock);
6405 }
6406
6407 /*********************************************************************
6408 *********************************************************************/
6409 /* static */
6410 void
recordIdentifierRequest(OSString * kextIdentifier)6411 OSKext::recordIdentifierRequest(
6412 OSString * kextIdentifier)
6413 {
6414 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
6415 bool fail = false;
6416
6417 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
6418 goto finish;
6419 }
6420
6421 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
6422 if (!kextIdentifierSymbol) {
6423 // xxx - this is really a basic alloc failure
6424 fail = true;
6425 goto finish;
6426 }
6427
6428 IORecursiveLockLock(sKextLock);
6429 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
6430 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
6431 fail = true;
6432 } else {
6433 // xxx - need to find a way to associate this whole func w/the kext
6434 OSKextLog(/* kext */ NULL,
6435 // xxx - check level
6436 kOSKextLogStepLevel |
6437 kOSKextLogArchiveFlag,
6438 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
6439 kextIdentifier->getCStringNoCopy());
6440 }
6441 }
6442 IORecursiveLockUnlock(sKextLock);
6443
6444 finish:
6445
6446 if (fail) {
6447 OSKextLog(/* kext */ NULL,
6448 kOSKextLogErrorLevel |
6449 kOSKextLogArchiveFlag,
6450 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
6451 kextIdentifier->getCStringNoCopy());
6452 }
6453 return;
6454 }
6455
6456 /*********************************************************************
6457 *********************************************************************/
6458 OSReturn
load(OSKextExcludeLevel startOpt,OSKextExcludeLevel startMatchingOpt,OSArray * personalityNames)6459 OSKext::load(
6460 OSKextExcludeLevel startOpt,
6461 OSKextExcludeLevel startMatchingOpt,
6462 OSArray * personalityNames)
6463 {
6464 OSReturn result = kOSReturnError;
6465 OSKextExcludeLevel dependenciesStartOpt = startOpt;
6466 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
6467 unsigned int i, count;
6468 Boolean alreadyLoaded = false;
6469 OSKext * lastLoadedKext = NULL; // do not release
6470
6471 if (isInExcludeList()) {
6472 OSKextLog(this,
6473 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6474 kOSKextLogLoadFlag,
6475 "Kext %s is in exclude list, not loadable",
6476 getIdentifierCString());
6477
6478 result = kOSKextReturnNotLoadable;
6479 goto finish;
6480 }
6481 if (!isLoadable()) {
6482 OSKextLog(this,
6483 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
6484 kOSKextLogLoadFlag,
6485 "Kext %s is not loadable",
6486 getIdentifierCString());
6487
6488 result = kOSKextReturnNotLoadable;
6489 goto finish;
6490 }
6491
6492 if (isLoaded()) {
6493 alreadyLoaded = true;
6494 result = kOSReturnSuccess;
6495
6496 OSKextLog(this,
6497 kOSKextLogDebugLevel |
6498 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
6499 "Kext %s is already loaded.",
6500 getIdentifierCString());
6501 goto loaded;
6502 }
6503
6504 #if CONFIG_MACF
6505 /*
6506 * On kxld and on embedded, only call into the MAC hook when on a
6507 * user thread, for access control over userspace kextloads.
6508 *
6509 * On non-kxld systems, additionally check the MAC hook for kexts in
6510 * the Pageable and Aux KCs, regardless of whether we are on a user
6511 * thread or not. This means on Apple silicon devices that the MAC
6512 * hook will only be useful to block 3rd party kexts loaded via
6513 * matching, and any kexts loaded from userspace kextloads.
6514 *
6515 * Note that this should _not_ be called on kexts loaded from the
6516 * kernel bootstrap thread as the kernel proc's cred struct is not
6517 * yet initialized! This won't happen on macOS because all the kexts
6518 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
6519 */
6520 if (current_task() != kernel_task
6521 #if XNU_TARGET_OS_OSX && !CONFIG_KXLD
6522 || (kc_type != KCKindPrimary && kc_type != KCKindUnknown)
6523 #endif
6524 ) {
6525 int macCheckResult = 0;
6526 kauth_cred_t cred = NULL;
6527
6528 cred = kauth_cred_get_with_ref();
6529 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
6530 kauth_cred_unref(&cred);
6531
6532 if (macCheckResult != 0) {
6533 result = kOSReturnError;
6534 OSKextLog(this,
6535 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6536 "Failed to load kext %s (MAC policy error 0x%x).",
6537 getIdentifierCString(), macCheckResult);
6538 goto finish;
6539 }
6540 }
6541 #endif /* CONFIG_MACF */
6542
6543 if (!sLoadEnabled) {
6544 OSKextLog(this,
6545 kOSKextLogErrorLevel |
6546 kOSKextLogLoadFlag,
6547 "Kext loading is disabled (attempt to load kext %s).",
6548 getIdentifierCString());
6549 result = kOSKextReturnDisabled;
6550 goto finish;
6551 }
6552
6553 /* If we've pushed the next available load tag to the invalid value,
6554 * we can't load any more kexts.
6555 */
6556 if (sNextLoadTag == kOSKextInvalidLoadTag) {
6557 OSKextLog(this,
6558 kOSKextLogErrorLevel |
6559 kOSKextLogLoadFlag,
6560 "Can't load kext %s - no more load tags to assign.",
6561 getIdentifierCString());
6562 result = kOSKextReturnNoResources;
6563 goto finish;
6564 }
6565
6566 /* This is a bit of a hack, because we shouldn't be handling
6567 * personalities within the load function.
6568 */
6569 if (!declaresExecutable()) {
6570 /* There is a special case where a non-executable kext can be loaded: the
6571 * AppleKextExcludeList. Detect that special kext by bundle identifier and
6572 * load its metadata into the global data structures, if appropriate
6573 */
6574 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
6575 boolean_t updated = updateExcludeList(infoDict.get());
6576 if (updated) {
6577 OSKextLog(this,
6578 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
6579 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
6580 }
6581 }
6582
6583 if (isDriverKit()) {
6584 if (loadTag == 0) {
6585 sLoadedDriverKitKexts->setObject(this);
6586 loadTag = sNextLoadTag++;
6587 }
6588 }
6589 result = kOSReturnSuccess;
6590 goto loaded;
6591 }
6592
6593 /* Are we in safe boot?
6594 */
6595 if (sSafeBoot && !isLoadableInSafeBoot()) {
6596 OSKextLog(this,
6597 kOSKextLogErrorLevel |
6598 kOSKextLogLoadFlag,
6599 "Can't load kext %s - not loadable during safe boot.",
6600 getIdentifierCString());
6601 result = kOSKextReturnBootLevel;
6602 goto finish;
6603 }
6604
6605 OSKextLog(this,
6606 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
6607 "Loading kext %s.",
6608 getIdentifierCString());
6609
6610 #if !VM_MAPPED_KEXTS
6611 if (isPrelinked() == false) {
6612 OSKextLog(this,
6613 kOSKextLogErrorLevel |
6614 kOSKextLogLoadFlag,
6615 "Can't load kext %s - not in a kext collection.",
6616 getIdentifierCString());
6617 result = kOSKextReturnDisabled;
6618 goto finish;
6619 }
6620 #endif /* defined(__x86_64__) */
6621
6622 #if CONFIG_KXLD
6623 if (!sKxldContext) {
6624 kern_return_t kxldResult;
6625 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
6626 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
6627 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
6628 if (kxldResult) {
6629 OSKextLog(this,
6630 kOSKextLogErrorLevel |
6631 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6632 "Can't load kext %s - failed to create link context.",
6633 getIdentifierCString());
6634 result = kOSKextReturnNoMemory;
6635 goto finish;
6636 }
6637 }
6638 #endif // CONFIG_KXLD
6639
6640 /* We only need to resolve dependencies once for the whole graph, but
6641 * resolveDependencies will just return if there's no work to do, so it's
6642 * safe to call it more than once.
6643 */
6644 if (!resolveDependencies()) {
6645 // xxx - check resolveDependencies() for log msg
6646 OSKextLog(this,
6647 kOSKextLogErrorLevel |
6648 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6649 "Can't load kext %s - failed to resolve library dependencies.",
6650 getIdentifierCString());
6651 result = kOSKextReturnDependencies;
6652 goto finish;
6653 }
6654
6655 /* If we are excluding just the kext being loaded now (and not its
6656 * dependencies), drop the exclusion level to none so dependencies
6657 * start and/or add their personalities.
6658 */
6659 if (dependenciesStartOpt == kOSKextExcludeKext) {
6660 dependenciesStartOpt = kOSKextExcludeNone;
6661 }
6662
6663 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
6664 dependenciesStartMatchingOpt = kOSKextExcludeNone;
6665 }
6666
6667 /* Load the dependencies, recursively.
6668 */
6669 count = getNumDependencies();
6670 for (i = 0; i < count; i++) {
6671 OSKext * dependency = OSDynamicCast(OSKext,
6672 dependencies->getObject(i));
6673 if (dependency == NULL) {
6674 OSKextLog(this,
6675 kOSKextLogErrorLevel |
6676 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6677 "Internal error loading kext %s; dependency disappeared.",
6678 getIdentifierCString());
6679 result = kOSKextReturnInternalError;
6680 goto finish;
6681 }
6682
6683 /* Dependencies must be started accorting to the opt,
6684 * but not given the personality names of the main kext.
6685 */
6686 result = dependency->load(dependenciesStartOpt,
6687 dependenciesStartMatchingOpt,
6688 /* personalityNames */ NULL);
6689 if (result != KERN_SUCCESS) {
6690 OSKextLog(this,
6691 kOSKextLogErrorLevel |
6692 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6693 "Dependency %s of kext %s failed to load.",
6694 dependency->getIdentifierCString(),
6695 getIdentifierCString());
6696
6697 OSKext::removeKext(dependency,
6698 /* terminateService/removePersonalities */ true);
6699 result = kOSKextReturnDependencyLoadError;
6700
6701 goto finish;
6702 }
6703 }
6704
6705 result = loadExecutable();
6706 if (result != KERN_SUCCESS) {
6707 goto finish;
6708 }
6709
6710 pendingPgoHead.next = &pendingPgoHead;
6711 pendingPgoHead.prev = &pendingPgoHead;
6712
6713 // The kernel PRNG is not initialized when the first kext is
6714 // loaded, so use early random
6715 uuid_generate_early_random(instance_uuid);
6716 account = IOMallocType(OSKextAccount);
6717
6718 account->loadTag = kmod_info->id;
6719 account->site.refcount = 0;
6720 account->site.flags = VM_TAG_KMOD;
6721
6722 #if DEVELOPMENT || DEBUG
6723 /* Setup the task reference group. */
6724 (void)snprintf(account->task_refgrp_name, sizeof(account->task_refgrp_name),
6725 "task_%s", getIdentifierCString());
6726 account->task_refgrp.grp_name = account->task_refgrp_name;
6727 account->task_refgrp.grp_parent = &task_external_refgrp;
6728 account->task_refgrp.grp_flags = OS_REFGRP_F_ALWAYS_ENABLED;
6729 os_ref_log_init(&account->task_refgrp);
6730 #endif /* DEVELOPMENT || DEBUG */
6731
6732 account->kext = this;
6733 if (gIOSurfaceIdentifier == bundleID) {
6734 vm_tag_alloc(&account->site);
6735 gIOSurfaceTag = account->site.tag;
6736 }
6737
6738 flags.loaded = true;
6739
6740 /* Add the kext to the list of loaded kexts and update the kmod_info
6741 * struct to point to that of the last loaded kext (which is the way
6742 * it's always been done, though I'd rather do them in order now).
6743 */
6744 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
6745 sLoadedKexts->setObject(this);
6746
6747 /* Keep the kernel itself out of the kmod list.
6748 */
6749 if (lastLoadedKext->isKernel()) {
6750 lastLoadedKext = NULL;
6751 }
6752
6753 if (lastLoadedKext) {
6754 kmod_info->next = lastLoadedKext->kmod_info;
6755 }
6756
6757 notifyKextLoadObservers(this, kmod_info);
6758
6759 /* Make the global kmod list point at the just-loaded kext. Note that the
6760 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
6761 * although we do report it in kextstat these days by using the newer
6762 * OSArray of loaded kexts, which does contain it.
6763 *
6764 * (The OSKext object representing the kernel doesn't even have a kmod_info
6765 * struct, though I suppose we could stick a pointer to it from the
6766 * static struct in OSRuntime.cpp.)
6767 */
6768 kmod = kmod_info;
6769
6770 /* Save the list of loaded kexts in case we panic.
6771 */
6772 OSKext::saveLoadedKextPanicList();
6773
6774 if (isExecutable()) {
6775 OSKext::updateLoadedKextSummaries();
6776 savePanicString(/* isLoading */ true);
6777
6778 #if CONFIG_DTRACE
6779 registerWithDTrace();
6780 #else
6781 jettisonLinkeditSegment();
6782 #endif /* CONFIG_DTRACE */
6783
6784 #if !VM_MAPPED_KEXTS
6785 /* If there is a page (or more) worth of padding after the end
6786 * of the last data section but before the end of the data segment
6787 * then free it in the same manner the LinkeditSegment is freed
6788 */
6789 jettisonDATASegmentPadding();
6790 #endif
6791 }
6792
6793 loaded:
6794 if (isExecutable() && !flags.started) {
6795 if (startOpt == kOSKextExcludeNone) {
6796 result = start();
6797 if (result != kOSReturnSuccess) {
6798 OSKextLog(this,
6799 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6800 "Kext %s start failed (result 0x%x).",
6801 getIdentifierCString(), result);
6802 result = kOSKextReturnStartStopError;
6803 }
6804 }
6805 }
6806
6807 /* If not excluding matching, send the personalities to the kernel.
6808 * This never affects the result of the load operation.
6809 * This is a bit of a hack, because we shouldn't be handling
6810 * personalities within the load function.
6811 */
6812 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
6813 result = sendPersonalitiesToCatalog(true, personalityNames);
6814 }
6815
6816 finish:
6817
6818 if (result != kOSReturnSuccess) {
6819 OSKextLog(this,
6820 kOSKextLogErrorLevel |
6821 kOSKextLogLoadFlag,
6822 "Kext %s failed to load (0x%x).",
6823 getIdentifierCString(), (int)result);
6824 } else if (!alreadyLoaded) {
6825 OSKextLog(this,
6826 kOSKextLogProgressLevel |
6827 kOSKextLogLoadFlag,
6828 "Kext %s loaded.",
6829 getIdentifierCString());
6830
6831 queueKextNotification(kKextRequestPredicateLoadNotification,
6832 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
6833 }
6834 return result;
6835 }
6836
6837 #if CONFIG_KXLD
6838 /*********************************************************************
6839 *
6840 *********************************************************************/
6841 static char *
strdup(const char * string)6842 strdup(const char * string)
6843 {
6844 char * result = NULL;
6845 size_t size;
6846
6847 if (!string) {
6848 goto finish;
6849 }
6850
6851 size = 1 + strlen(string);
6852 result = (char *)kalloc_data_tag(size, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
6853 if (!result) {
6854 goto finish;
6855 }
6856
6857 memcpy(result, string, size);
6858
6859 finish:
6860 return result;
6861 }
6862 #endif // CONFIG_KXLD
6863
6864 /*********************************************************************
6865 *
6866 *********************************************************************/
6867
6868 kernel_section_t *
lookupSection(const char * segname,const char * secname)6869 OSKext::lookupSection(const char *segname, const char *secname)
6870 {
6871 kernel_section_t * found_section = NULL;
6872 kernel_mach_header_t * mh = NULL;
6873 kernel_segment_command_t * seg = NULL;
6874 kernel_section_t * sec = NULL;
6875
6876 if (!linkedExecutable) {
6877 return NULL;
6878 }
6879
6880 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6881
6882 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6883 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
6884 continue;
6885 }
6886
6887 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6888 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
6889 found_section = sec;
6890 goto out;
6891 }
6892 }
6893 }
6894
6895 out:
6896 return found_section;
6897 }
6898
6899 /*********************************************************************
6900 *
6901 *********************************************************************/
6902
6903 OSReturn
slidePrelinkedExecutable(bool doCoalescedSlides)6904 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
6905 {
6906 OSReturn result = kOSKextReturnBadData;
6907 kernel_mach_header_t * mh = NULL;
6908 kernel_segment_command_t * seg = NULL;
6909 kernel_segment_command_t * linkeditSeg = NULL;
6910 kernel_section_t * sec = NULL;
6911 char * linkeditBase = NULL;
6912 bool haveLinkeditBase = false;
6913 char * relocBase = NULL;
6914 bool haveRelocBase = false;
6915 struct dysymtab_command * dysymtab = NULL;
6916 struct linkedit_data_command * segmentSplitInfo = NULL;
6917 struct symtab_command * symtab = NULL;
6918 kernel_nlist_t * sym = NULL;
6919 struct relocation_info * reloc = NULL;
6920 uint32_t i = 0;
6921 int reloc_size;
6922 vm_offset_t new_kextsize;
6923 kc_format format = KCFormatUnknown;
6924
6925 if (linkedExecutable == NULL || flags.builtin) {
6926 result = kOSReturnSuccess;
6927 goto finish;
6928 }
6929
6930 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
6931 if (kernel_mach_header_is_in_fileset(mh)) {
6932 // kexts in filesets are slid as part of collection sliding
6933 result = kOSReturnSuccess;
6934 goto finish;
6935 }
6936
6937 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
6938
6939 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
6940 if (!seg->vmaddr) {
6941 continue;
6942 }
6943
6944 seg->vmaddr = ml_static_slide(seg->vmaddr);
6945
6946 #if KASLR_KEXT_DEBUG
6947 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
6948 seg->segname,
6949 (unsigned long)ml_static_unslide(seg->vmaddr),
6950 (unsigned long)seg->vmaddr);
6951 #endif
6952
6953 if (!haveRelocBase) {
6954 relocBase = (char *) seg->vmaddr;
6955 haveRelocBase = true;
6956 }
6957 if (!strcmp(seg->segname, "__LINKEDIT")) {
6958 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6959 haveLinkeditBase = true;
6960 linkeditSeg = seg;
6961 }
6962 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6963 sec->addr = ml_static_slide(sec->addr);
6964
6965 #if KASLR_KEXT_DEBUG
6966 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6967 sec->sectname,
6968 (unsigned long)ml_static_unslide(sec->addr),
6969 (unsigned long)sec->addr);
6970 #endif
6971 }
6972 }
6973
6974 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6975
6976 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6977
6978 if (symtab != NULL && doCoalescedSlides == false) {
6979 /* Some pseudo-kexts have symbol tables without segments.
6980 * Ignore them. */
6981 if (symtab->nsyms > 0 && haveLinkeditBase) {
6982 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6983 for (i = 0; i < symtab->nsyms; i++) {
6984 if (sym[i].n_type & N_STAB) {
6985 continue;
6986 }
6987 sym[i].n_value = ml_static_slide(sym[i].n_value);
6988
6989 #if KASLR_KEXT_DEBUG
6990 #define MAX_SYMS_TO_LOG 5
6991 if (i < MAX_SYMS_TO_LOG) {
6992 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6993 (unsigned long)ml_static_unslide(sym[i].n_value),
6994 (unsigned long)sym[i].n_value);
6995 }
6996 #endif
6997 }
6998 }
6999 }
7000
7001 if (dysymtab != NULL && doCoalescedSlides == false) {
7002 if (dysymtab->nextrel > 0) {
7003 OSKextLog(this,
7004 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7005 kOSKextLogLinkFlag,
7006 "Sliding kext %s: External relocations found.",
7007 getIdentifierCString());
7008 goto finish;
7009 }
7010
7011 if (dysymtab->nlocrel > 0) {
7012 if (!haveLinkeditBase) {
7013 OSKextLog(this,
7014 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7015 kOSKextLogLinkFlag,
7016 "Sliding kext %s: No linkedit segment.",
7017 getIdentifierCString());
7018 goto finish;
7019 }
7020
7021 if (!haveRelocBase) {
7022 OSKextLog(this,
7023 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7024 kOSKextLogLinkFlag,
7025 #if __x86_64__
7026 "Sliding kext %s: No writable segments.",
7027 #else
7028 "Sliding kext %s: No segments.",
7029 #endif
7030 getIdentifierCString());
7031 goto finish;
7032 }
7033
7034 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
7035 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
7036
7037 for (i = 0; i < dysymtab->nlocrel; i++) {
7038 if (reloc[i].r_extern != 0
7039 || reloc[i].r_type != 0
7040 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
7041 ) {
7042 OSKextLog(this,
7043 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7044 kOSKextLogLinkFlag,
7045 "Sliding kext %s: Unexpected relocation found.",
7046 getIdentifierCString());
7047 goto finish;
7048 }
7049 if (reloc[i].r_pcrel != 0) {
7050 continue;
7051 }
7052 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
7053 *relocAddr = ml_static_slide(*relocAddr);
7054
7055 #if KASLR_KEXT_DEBUG
7056 #define MAX_DYSYMS_TO_LOG 5
7057 if (i < MAX_DYSYMS_TO_LOG) {
7058 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
7059 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
7060 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
7061 }
7062 #endif
7063 }
7064
7065 /* We should free these relocations, not just delete the reference to them.
7066 * <rdar://problem/10535549> Free relocations from PIE kexts.
7067 *
7068 * For now, we do not free LINKEDIT for kexts with split segments.
7069 */
7070 new_kextsize = round_page(kmod_info->size - reloc_size);
7071 if (new_kextsize > UINT_MAX) {
7072 OSKextLog(this,
7073 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
7074 kOSKextLogLinkFlag,
7075 "Kext %s: new kext size is too large.",
7076 getIdentifierCString());
7077 goto finish;
7078 }
7079 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
7080 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
7081 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
7082 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
7083 size_t bytes_remaining = endofkext - endofrelocInfo;
7084 OSSharedPtr<OSData> new_osdata;
7085
7086 /* fix up symbol offsets if they are after the dsymtab local relocs */
7087 if (symtab) {
7088 if (dysymtab->locreloff < symtab->symoff) {
7089 symtab->symoff -= reloc_size;
7090 }
7091 if (dysymtab->locreloff < symtab->stroff) {
7092 symtab->stroff -= reloc_size;
7093 }
7094 }
7095 if (dysymtab->locreloff < dysymtab->extreloff) {
7096 dysymtab->extreloff -= reloc_size;
7097 }
7098
7099 /* move data behind reloc info down to new offset */
7100 if (endofrelocInfo < endofkext) {
7101 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
7102 }
7103
7104 /* Create a new OSData for the smaller kext object and reflect
7105 * new linkedit segment size.
7106 */
7107 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
7108 linkeditSeg->filesize = linkeditSeg->vmsize;
7109
7110 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
7111 if (new_osdata) {
7112 /* Fix up kmod info and linkedExecutable.
7113 */
7114 kmod_info->size = new_kextsize;
7115 /*
7116 * Fileset KCs are mapped as a whole by iBoot.
7117 * Individual kext executables should not be unmapped
7118 * by xnu.
7119 * Doing so may result in panics like rdar://85419651
7120 */
7121 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7122 new_osdata->setDeallocFunction(NULL);
7123 } else { // Not from a Fileset KC
7124 #if VM_MAPPED_KEXTS
7125 new_osdata->setDeallocFunction(osdata_kext_free);
7126 #else
7127 new_osdata->setDeallocFunction(osdata_phys_free);
7128 #endif
7129 }
7130 linkedExecutable->setDeallocFunction(NULL);
7131 linkedExecutable = os::move(new_osdata);
7132
7133 #if VM_MAPPED_KEXTS
7134 kext_free(new_endofkext, (endofkext - new_endofkext));
7135 #else
7136 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
7137 #endif
7138 }
7139 }
7140 dysymtab->nlocrel = 0;
7141 dysymtab->locreloff = 0;
7142 }
7143 }
7144
7145 result = kOSReturnSuccess;
7146 finish:
7147 return result;
7148 }
7149
7150 /*********************************************************************
7151 * called only by load()
7152 *********************************************************************/
7153 OSReturn
loadExecutable()7154 OSKext::loadExecutable()
7155 {
7156 OSReturn result = kOSReturnError;
7157 OSSharedPtr<OSArray> linkDependencies;
7158 uint32_t num_kmod_refs = 0;
7159 OSData * theExecutable = NULL; // do not release
7160 OSString * versString = NULL; // do not release
7161 const char * versCString = NULL; // do not free
7162 const char * string = NULL; // do not free
7163
7164 #if CONFIG_KXLD
7165 unsigned int i;
7166 uint32_t numDirectDependencies = 0;
7167 kern_return_t kxldResult;
7168 KXLDDependency * kxlddeps = NULL; // must kfree
7169 uint32_t num_kxlddeps = 0;
7170 struct mach_header ** kxldHeaderPtr = NULL; // do not free
7171 struct mach_header * kxld_header = NULL; // xxx - need to free here?
7172 #endif // CONFIG_KXLD
7173
7174 /* We need the version string for a variety of bits below.
7175 */
7176 versString = OSDynamicCast(OSString,
7177 getPropertyForHostArch(kCFBundleVersionKey));
7178 if (!versString) {
7179 goto finish;
7180 }
7181 versCString = versString->getCStringNoCopy();
7182
7183 if (isKernelComponent()) {
7184 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
7185 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
7186 OSKextLog(this,
7187 kOSKextLogErrorLevel |
7188 kOSKextLogLoadFlag,
7189 "Kernel component %s has incorrect version %s; "
7190 "expected %s.",
7191 getIdentifierCString(),
7192 versCString, KERNEL6_VERSION);
7193 result = kOSKextReturnInternalError;
7194 goto finish;
7195 } else if (strcmp(versCString, osrelease)) {
7196 OSKextLog(this,
7197 kOSKextLogErrorLevel |
7198 kOSKextLogLoadFlag,
7199 "Kernel component %s has incorrect version %s; "
7200 "expected %s.",
7201 getIdentifierCString(),
7202 versCString, osrelease);
7203 result = kOSKextReturnInternalError;
7204 goto finish;
7205 }
7206 }
7207 }
7208
7209 #if defined(__x86_64__) || defined(__i386__)
7210 if (flags.resetSegmentsFromVnode) {
7211 /* Fixup the chains and slide the mach headers */
7212 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
7213
7214 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
7215 result = kOSKextReturnValidation;
7216 goto finish;
7217 }
7218 }
7219 #endif //(__x86_64__) || defined(__i386__)
7220
7221 if (isPrelinked()) {
7222 goto register_kmod;
7223 }
7224
7225 /* <rdar://problem/21444003> all callers must be entitled */
7226 if (FALSE == IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement)) {
7227 OSKextLog(this,
7228 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7229 "Not entitled to link kext '%s'",
7230 getIdentifierCString());
7231 result = kOSKextReturnNotPrivileged;
7232 goto finish;
7233 }
7234
7235 theExecutable = getExecutable();
7236 if (!theExecutable) {
7237 if (declaresExecutable()) {
7238 OSKextLog(this,
7239 kOSKextLogErrorLevel |
7240 kOSKextLogLoadFlag,
7241 "Can't load kext %s - executable is missing.",
7242 getIdentifierCString());
7243 result = kOSKextReturnValidation;
7244 goto finish;
7245 }
7246 goto register_kmod;
7247 }
7248
7249 if (isInterface()) {
7250 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
7251 if (executableCopy) {
7252 setLinkedExecutable(executableCopy.get());
7253 }
7254 goto register_kmod;
7255 }
7256
7257 #if CONFIG_KXLD
7258 numDirectDependencies = getNumDependencies();
7259
7260 if (flags.hasBleedthrough) {
7261 linkDependencies = dependencies;
7262 } else {
7263 linkDependencies = OSArray::withArray(dependencies.get());
7264 if (!linkDependencies) {
7265 OSKextLog(this,
7266 kOSKextLogErrorLevel |
7267 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7268 "Can't allocate link dependencies to load kext %s.",
7269 getIdentifierCString());
7270 goto finish;
7271 }
7272
7273 for (i = 0; i < numDirectDependencies; ++i) {
7274 OSKext * dependencyKext = OSDynamicCast(OSKext,
7275 dependencies->getObject(i));
7276 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
7277 }
7278 }
7279
7280 num_kxlddeps = linkDependencies->getCount();
7281 if (!num_kxlddeps) {
7282 OSKextLog(this,
7283 kOSKextLogErrorLevel |
7284 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
7285 "Can't load kext %s - it has no library dependencies.",
7286 getIdentifierCString());
7287 goto finish;
7288 }
7289
7290 kxlddeps = kalloc_type_tag(KXLDDependency, num_kxlddeps, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
7291 if (!kxlddeps) {
7292 OSKextLog(this,
7293 kOSKextLogErrorLevel |
7294 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7295 "Can't allocate link context to load kext %s.",
7296 getIdentifierCString());
7297 goto finish;
7298 }
7299 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
7300
7301 for (i = 0; i < num_kxlddeps; ++i) {
7302 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
7303
7304 if (dependency->isInterface()) {
7305 OSKext *interfaceTargetKext = NULL; //do not release
7306 OSData * interfaceTarget = NULL; //do not release
7307
7308 if (dependency->isKernelComponent()) {
7309 interfaceTargetKext = sKernelKext;
7310 interfaceTarget = sKernelKext->linkedExecutable.get();
7311 } else {
7312 interfaceTargetKext = OSDynamicCast(OSKext,
7313 dependency->dependencies->getObject(0));
7314
7315 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
7316 }
7317
7318 if (!interfaceTarget) {
7319 // panic?
7320 goto finish;
7321 }
7322
7323 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
7324 * it will be useful to have them in the debugger.
7325 * strdup() failing isn't critical right here so we don't check that.
7326 */
7327 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
7328 kxlddeps[i].kext_size = interfaceTarget->getLength();
7329 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
7330
7331 if (dependency->linkedExecutable != NULL) {
7332 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7333 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
7334 } else {
7335 kxlddeps[i].interface = (u_char *) NULL;
7336 kxlddeps[i].interface_size = 0;
7337 }
7338 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
7339 } else {
7340 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
7341 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
7342 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
7343 }
7344
7345 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
7346 }
7347
7348 kxldHeaderPtr = &kxld_header;
7349
7350 #if DEBUG
7351 OSKextLog(this,
7352 kOSKextLogExplicitLevel |
7353 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
7354 "Kext %s - calling kxld_link_file:\n"
7355 " kxld_context: %p\n"
7356 " executable: %p executable_length: %d\n"
7357 " user_data: %p\n"
7358 " kxld_dependencies: %p num_dependencies: %d\n"
7359 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
7360 getIdentifierCString(), sKxldContext,
7361 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
7362 this, kxlddeps, num_kxlddeps,
7363 kxldHeaderPtr, &kmod_info);
7364 #endif
7365
7366 /* After this call, the linkedExecutable instance variable
7367 * should exist.
7368 */
7369 kxldResult = kxld_link_file(sKxldContext,
7370 (u_char *)theExecutable->getBytesNoCopy(),
7371 theExecutable->getLength(),
7372 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
7373 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
7374
7375 if (kxldResult != KERN_SUCCESS) {
7376 // xxx - add kxldResult here?
7377 OSKextLog(this,
7378 kOSKextLogErrorLevel |
7379 kOSKextLogLoadFlag,
7380 "Can't load kext %s - link failed.",
7381 getIdentifierCString());
7382 result = kOSKextReturnLinkError;
7383 goto finish;
7384 }
7385
7386 /* We've written data & instructions into kernel memory, so flush the data
7387 * cache and invalidate the instruction cache.
7388 * I/D caches are coherent on x86
7389 */
7390 #if !defined(__i386__) && !defined(__x86_64__)
7391 flush_dcache(kmod_info->address, kmod_info->size, false);
7392 invalidate_icache(kmod_info->address, kmod_info->size, false);
7393 #endif
7394
7395 #else // !CONFIG_KXLD
7396 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7397 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
7398 result = kOSKextReturnLinkError;
7399 goto finish;
7400 #endif // CONFIG_KXLD
7401
7402 register_kmod:
7403
7404 if (isInterface()) {
7405 /* Whip up a fake kmod_info entry for the interface kext.
7406 */
7407 kmod_info = kalloc_type(kmod_info_t, (zalloc_flags_t)(Z_WAITOK | Z_ZERO));
7408 if (!kmod_info) {
7409 result = KERN_MEMORY_ERROR;
7410 goto finish;
7411 }
7412
7413 /* A pseudokext has almost nothing in its kmod_info struct.
7414 */
7415 kmod_info->info_version = KMOD_INFO_VERSION;
7416
7417 /* An interface kext doesn't have a linkedExecutable, so save a
7418 * copy of the UUID out of the original executable via copyUUID()
7419 * while we still have the original executable.
7420 */
7421 interfaceUUID = copyUUID();
7422 }
7423
7424 kmod_info->id = loadTag = sNextLoadTag++;
7425 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
7426
7427 /* Stamp the bundle ID and version from the OSKext over anything
7428 * resident inside the kmod_info.
7429 */
7430 string = getIdentifierCString();
7431 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
7432
7433 string = versCString;
7434 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
7435
7436 /* Add the dependencies' kmod_info structs as kmod_references.
7437 */
7438 num_kmod_refs = getNumDependencies();
7439 if (num_kmod_refs) {
7440 kmod_info->reference_list = kalloc_type_tag(kmod_reference_t,
7441 num_kmod_refs, Z_WAITOK_ZERO, VM_KERN_MEMORY_OSKEXT);
7442 if (!kmod_info->reference_list) {
7443 result = KERN_MEMORY_ERROR;
7444 goto finish;
7445 }
7446 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7447 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7448 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
7449 ref->info = refKext->kmod_info;
7450 ref->info->reference_count++;
7451
7452 if (refIndex + 1 < num_kmod_refs) {
7453 ref->next = kmod_info->reference_list + refIndex + 1;
7454 }
7455 }
7456 }
7457
7458 if (kmod_info->hdr_size > UINT32_MAX) {
7459 OSKextLog(this,
7460 kOSKextLogErrorLevel |
7461 kOSKextLogLoadFlag,
7462 #if __LP64__
7463 "Kext %s header size is too large (%lu > UINT32_MAX).",
7464 #else
7465 "Kext %s header size is too large (%u > UINT32_MAX).",
7466 #endif
7467 kmod_info->name,
7468 kmod_info->hdr_size);
7469 result = KERN_FAILURE;
7470 goto finish;
7471 }
7472
7473 if (kmod_info->size > UINT32_MAX) {
7474 OSKextLog(this,
7475 kOSKextLogErrorLevel |
7476 kOSKextLogLoadFlag,
7477 #if __LP64__
7478 "Kext %s size is too large (%lu > UINT32_MAX).",
7479 #else
7480 "Kext %s size is too large (%u > UINT32_MAX).",
7481 #endif
7482 kmod_info->name,
7483 kmod_info->size);
7484 result = KERN_FAILURE;
7485 goto finish;
7486 }
7487
7488 if (!isInterface() && linkedExecutable) {
7489 OSKextLog(this,
7490 kOSKextLogProgressLevel |
7491 kOSKextLogLoadFlag,
7492 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
7493 kmod_info->name,
7494 (unsigned)kmod_info->size / PAGE_SIZE,
7495 (unsigned long)ml_static_unslide(kmod_info->address),
7496 (unsigned)kmod_info->id);
7497 }
7498
7499 /* VM protections and wiring for the Aux KC are done at collection loading time */
7500 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
7501 /* if prelinked and primary KC, VM protections are already set */
7502 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
7503 if (result != KERN_SUCCESS) {
7504 goto finish;
7505 }
7506 }
7507
7508 #if KASAN
7509 if (linkedExecutable) {
7510 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
7511 linkedExecutable->getLength(), getIdentifierCString());
7512 }
7513 #else
7514 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
7515 OSKextLog(this,
7516 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
7517 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
7518 getIdentifierCString()
7519 );
7520 result = KERN_FAILURE;
7521 goto finish;
7522 }
7523 #endif
7524
7525 result = kOSReturnSuccess;
7526
7527 finish:
7528
7529 #if CONFIG_KXLD
7530 /* Clear up locally allocated dependency info.
7531 */
7532 for (i = 0; i < num_kxlddeps; ++i) {
7533 size_t size;
7534
7535 if (kxlddeps[i].kext_name) {
7536 size = 1 + strlen(kxlddeps[i].kext_name);
7537 kfree_data(kxlddeps[i].kext_name, size);
7538 }
7539 if (kxlddeps[i].interface_name) {
7540 size = 1 + strlen(kxlddeps[i].interface_name);
7541 kfree_data(kxlddeps[i].interface_name, size);
7542 }
7543 }
7544 if (kxlddeps) {
7545 kfree_type(KXLDDependency, num_kxlddeps, kxlddeps);
7546 }
7547 #endif // CONFIG_KXLD
7548
7549 /* We no longer need the unrelocated executable (which the linker
7550 * has altered anyhow).
7551 */
7552 setExecutable(NULL);
7553
7554 if (result != kOSReturnSuccess) {
7555 OSKextLog(this,
7556 kOSKextLogErrorLevel |
7557 kOSKextLogLoadFlag,
7558 "Failed to load executable for kext %s.",
7559 getIdentifierCString());
7560
7561 if (kmod_info && kmod_info->reference_list) {
7562 kfree_type(kmod_reference_t, num_kmod_refs,
7563 kmod_info->reference_list);
7564 }
7565 if (isInterface()) {
7566 kfree_type(kmod_info_t, kmod_info);
7567 kmod_info = NULL;
7568 }
7569 if (kc_type == KCKindUnknown) {
7570 kmod_info = NULL;
7571 if (linkedExecutable) {
7572 linkedExecutable.reset();
7573 }
7574 }
7575 }
7576
7577 return result;
7578 }
7579
7580 /* static */
7581 void
jettisonFileSetLinkeditSegment(kernel_mach_header_t * mh)7582 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
7583 {
7584 kernel_segment_command_t *linkeditseg = NULL;
7585
7586 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
7587 if (linkeditseg == NULL) {
7588 panic("FileSet booted with no Linkedit segment");
7589 }
7590
7591 #if VM_MAPPED_KEXTS
7592 /* BootKC on x86_64 is not vm mapped */
7593 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
7594
7595 OSKextLog(/* kext */ NULL,
7596 kOSKextLogProgressLevel |
7597 kOSKextLogGeneralFlag,
7598 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7599 linkeditseg->vmaddr, linkeditseg->vmsize);
7600 #else
7601 /* BootKC on arm64 is not vm mapped, but is slid */
7602 #if !CONFIG_SPTM
7603 vm_offset_t linkedit_vmaddr = ml_static_ptovirt((vm_offset_t)(linkeditseg->vmaddr - gVirtBase + gPhysBase));
7604 #else
7605 vm_offset_t linkedit_vmaddr = linkeditseg->vmaddr;
7606 #endif
7607
7608 ml_static_mfree(linkedit_vmaddr, (vm_size_t)linkeditseg->vmsize);
7609
7610 OSKextLog(/* kext */ NULL,
7611 kOSKextLogProgressLevel |
7612 kOSKextLogGeneralFlag,
7613 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
7614 (unsigned long long)linkedit_vmaddr, (unsigned long long)linkeditseg->vmsize);
7615 #endif /* VM_MAPPED_KEXTS */
7616 }
7617
7618 /*********************************************************************
7619 * The linkedit segment is used by the kext linker for dependency
7620 * resolution, and by dtrace for probe initialization. We can free it
7621 * for non-library kexts, since no kexts depend on non-library kexts
7622 * by definition, once dtrace has been initialized.
7623 *********************************************************************/
7624 void
jettisonLinkeditSegment(void)7625 OSKext::jettisonLinkeditSegment(void)
7626 {
7627 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
7628 kernel_segment_command_t * linkedit = NULL;
7629 vm_offset_t start;
7630 vm_size_t linkeditsize, kextsize;
7631 OSSharedPtr<OSData> data;
7632 kc_format format = KCFormatUnknown;
7633
7634 if (isInFileset()) {
7635 return;
7636 }
7637
7638 #if NO_KEXTD
7639 /* We can free symbol tables for all embedded kexts because we don't
7640 * support runtime kext linking.
7641 */
7642 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7643 #else
7644 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
7645 #endif
7646 goto finish;
7647 }
7648
7649 /* Find the linkedit segment. If it's not the last segment, then freeing
7650 * it will fragment the kext into multiple VM regions, which OSKext is not
7651 * designed to handle, so we'll have to skip it.
7652 */
7653 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
7654 if (!linkedit) {
7655 goto finish;
7656 }
7657
7658 if (round_page(kmod_info->address + kmod_info->size) !=
7659 round_page(linkedit->vmaddr + linkedit->vmsize)) {
7660 goto finish;
7661 }
7662
7663 /* Create a new OSData for the smaller kext object.
7664 */
7665 linkeditsize = round_page(linkedit->vmsize);
7666 kextsize = kmod_info->size - linkeditsize;
7667 start = linkedit->vmaddr;
7668
7669 if (kextsize > UINT_MAX) {
7670 goto finish;
7671 }
7672 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
7673 if (!data) {
7674 goto finish;
7675 }
7676
7677 /* Fix the kmod info and linkedExecutable.
7678 */
7679 kmod_info->size = kextsize;
7680
7681 /*
7682 * Fileset KCs are mapped as a whole by iBoot.
7683 * Individual kext executables should not be unmapped by xnu
7684 * Doing so may result in panics like rdar://85419651
7685 */
7686 if (PE_get_kc_format(kc_type, &format) && (format == KCFormatFileset)) {
7687 data->setDeallocFunction(NULL);
7688 } else { // Not from a Fileset KC
7689 #if VM_MAPPED_KEXTS
7690 data->setDeallocFunction(osdata_kext_free);
7691 #else
7692 data->setDeallocFunction(osdata_phys_free);
7693 #endif
7694 }
7695 linkedExecutable->setDeallocFunction(NULL);
7696 linkedExecutable = os::move(data);
7697 flags.jettisonLinkeditSeg = 1;
7698
7699 /* Free the linkedit segment.
7700 */
7701 #if VM_MAPPED_KEXTS
7702 kext_free(start, linkeditsize);
7703 #else
7704 ml_static_mfree(start, linkeditsize);
7705 #endif
7706
7707 finish:
7708 return;
7709 }
7710
7711 /*********************************************************************
7712 * If there are whole pages that are unused betweem the last section
7713 * of the DATA segment and the end of the DATA segment then we can free
7714 * them
7715 *********************************************************************/
7716 void
7717 OSKext::jettisonDATASegmentPadding(void)
7718 {
7719 kernel_mach_header_t * mh;
7720 kernel_segment_command_t * dataSeg;
7721 kernel_section_t * sec, * lastSec;
7722 vm_offset_t dataSegEnd, lastSecEnd;
7723 vm_size_t padSize;
7724
7725 if (flags.builtin) {
7726 return;
7727 }
7728 mh = (kernel_mach_header_t *)kmod_info->address;
7729
7730 if (isInFileset()) {
7731 return;
7732 }
7733
7734 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
7735 if (dataSeg == NULL) {
7736 return;
7737 }
7738
7739 lastSec = NULL;
7740 sec = firstsect(dataSeg);
7741 while (sec != NULL) {
7742 lastSec = sec;
7743 sec = nextsect(dataSeg, sec);
7744 }
7745
7746 if (lastSec == NULL) {
7747 return;
7748 }
7749
7750 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
7751 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
7752 return;
7753 }
7754
7755 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
7756 lastSecEnd = round_page(lastSec->addr + lastSec->size);
7757
7758 if (dataSegEnd <= lastSecEnd) {
7759 return;
7760 }
7761
7762 padSize = dataSegEnd - lastSecEnd;
7763
7764 if (padSize >= PAGE_SIZE) {
7765 #if VM_MAPPED_KEXTS
7766 kext_free(lastSecEnd, padSize);
7767 #else
7768 ml_static_mfree(lastSecEnd, padSize);
7769 #endif
7770 }
7771 }
7772
7773 /*********************************************************************
7774 *********************************************************************/
7775 void
7776 OSKext::setLinkedExecutable(OSData * anExecutable)
7777 {
7778 if (linkedExecutable) {
7779 panic("Attempt to set linked executable on kext "
7780 "that already has one (%s).\n",
7781 getIdentifierCString());
7782 }
7783 linkedExecutable.reset(anExecutable, OSRetain);
7784 return;
7785 }
7786
7787 #if CONFIG_DTRACE
7788 /*********************************************************************
7789 * Go through all loaded kexts and tell them to register with dtrace.
7790 * The instance method only registers if necessary.
7791 *********************************************************************/
7792 /* static */
7793 void
7794 OSKext::registerKextsWithDTrace(void)
7795 {
7796 uint32_t count = sLoadedKexts->getCount();
7797 uint32_t i;
7798
7799 IORecursiveLockLock(sKextLock);
7800
7801 for (i = 0; i < count; i++) {
7802 OSKext * thisKext = NULL; // do not release
7803
7804 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
7805 if (!thisKext || !thisKext->isExecutable()) {
7806 continue;
7807 }
7808
7809 thisKext->registerWithDTrace();
7810 }
7811
7812 IORecursiveLockUnlock(sKextLock);
7813
7814 return;
7815 }
7816
7817 extern "C" {
7818 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
7819 extern int (*dtrace_modunload)(struct kmod_info *);
7820 };
7821
7822 /*********************************************************************
7823 *********************************************************************/
7824 void
7825 OSKext::registerWithDTrace(void)
7826 {
7827 /* Register kext with dtrace. A dtrace_modload failure should not
7828 * prevent a kext from loading, so we ignore the return code.
7829 */
7830 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
7831 uint32_t modflag = 0;
7832 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
7833
7834 if (!sKeepSymbols && kc_type == KCKindPrimary) {
7835 if (forceInit == kOSBooleanTrue) {
7836 OSKextLog(this,
7837 kOSKextLogBasicLevel |
7838 kOSKextLogGeneralFlag,
7839 "Ignoring OSBundleForceDTraceInit for Boot KC Kext %s",
7840 getIdentifierCString());
7841 forceInit = kOSBooleanFalse;
7842 }
7843 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
7844 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
7845 }
7846
7847 if (forceInit == kOSBooleanTrue) {
7848 modflag |= KMOD_DTRACE_FORCE_INIT;
7849 }
7850 if (flags.builtin) {
7851 modflag |= KMOD_DTRACE_STATIC_KEXT;
7852 }
7853
7854 (void)(*dtrace_modload)(kmod_info, modflag);
7855 flags.dtraceInitialized = true;
7856 jettisonLinkeditSegment();
7857 }
7858 return;
7859 }
7860 /*********************************************************************
7861 *********************************************************************/
7862 void
7863 OSKext::unregisterWithDTrace(void)
7864 {
7865 /* Unregister kext with dtrace. A dtrace_modunload failure should not
7866 * prevent a kext from loading, so we ignore the return code.
7867 */
7868 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
7869 (void)(*dtrace_modunload)(kmod_info);
7870 flags.dtraceInitialized = false;
7871 }
7872 return;
7873 }
7874 #endif /* CONFIG_DTRACE */
7875
7876
7877 /*********************************************************************
7878 * called only by loadExecutable()
7879 *********************************************************************/
7880 #if !VM_MAPPED_KEXTS
7881 #if defined(__arm__) || defined(__arm64__)
7882 static inline kern_return_t
7883 OSKext_protect(
7884 kernel_mach_header_t *kext_mh,
7885 vm_map_t map,
7886 vm_map_offset_t start,
7887 vm_map_size_t size,
7888 vm_prot_t new_prot,
7889 boolean_t set_max,
7890 kc_kind_t kc_type)
7891 {
7892 vm_map_offset_t end = start + size;
7893
7894 #pragma unused(kext_mh,map,kc_type)
7895 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
7896 assert(start <= end);
7897 if (start >= end) {
7898 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
7899 } else if (set_max) {
7900 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
7901 } else {
7902 return ml_static_protect(start, size, new_prot);
7903 }
7904 }
7905
7906 static inline kern_return_t
7907 OSKext_wire(
7908 kernel_mach_header_t *kext_mh,
7909 vm_map_t map,
7910 vm_map_offset_t start,
7911 vm_map_offset_t end,
7912 vm_prot_t access_type,
7913 boolean_t user_wire,
7914 kc_kind_t kc_type)
7915 {
7916 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
7917 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
7918 }
7919 #else
7920 #error Unrecognized architecture
7921 #endif
7922 #else
7923 static inline kern_return_t
7924 OSKext_protect(
7925 kernel_mach_header_t *kext_mh,
7926 vm_map_t map,
7927 vm_map_offset_t start,
7928 vm_map_size_t size,
7929 vm_prot_t new_prot,
7930 boolean_t set_max,
7931 kc_kind_t kc_type)
7932 {
7933 vm_map_offset_t end = start + size;
7934
7935 if (start == end) { // 10538581
7936 return KERN_SUCCESS;
7937 }
7938 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7939 /*
7940 * XXX: This will probably need to be different for AuxKC and
7941 * pageableKC!
7942 */
7943 return ml_static_protect(start, size, new_prot);
7944 }
7945 return mach_vm_protect(map, start, size, set_max, new_prot);
7946 }
7947
7948 static inline kern_return_t
7949 OSKext_wire(
7950 kernel_mach_header_t *kext_mh,
7951 vm_map_t map,
7952 vm_map_offset_t start,
7953 vm_map_offset_t end,
7954 vm_prot_t access_type,
7955 boolean_t user_wire,
7956 kc_kind_t kc_type)
7957 {
7958 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
7959 /* TODO: we may need to hook this for the pageableKC */
7960 return KERN_SUCCESS;
7961 }
7962 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
7963 }
7964 #endif
7965
7966 OSReturn
7967 OSKext::setVMAttributes(bool protect, bool wire)
7968 {
7969 vm_map_t kext_map = NULL;
7970 kernel_segment_command_t * seg = NULL;
7971 vm_map_offset_t start_protect = 0;
7972 vm_map_offset_t start_wire = 0;
7973 vm_map_offset_t end_protect = 0;
7974 vm_map_size_t size_protect = 0;
7975 vm_map_offset_t end_wire = 0;
7976 OSReturn result = kOSReturnError;
7977
7978 if (isInterface() || !declaresExecutable() || flags.builtin) {
7979 result = kOSReturnSuccess;
7980 goto finish;
7981 }
7982
7983 /* Get the kext's vm map */
7984 kext_map = kext_get_vm_map(kmod_info);
7985 if (!kext_map) {
7986 result = KERN_MEMORY_ERROR;
7987 goto finish;
7988 }
7989
7990 #if !VM_MAPPED_KEXTS
7991 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7992 /* This is a split kext in a prelinked kernelcache; we'll let the
7993 * platform code take care of protecting it. It is already wired.
7994 */
7995 /* TODO: Should this still allow protections for the first segment
7996 * to go through, in the event that we have a mix of split and
7997 * unsplit kexts?
7998 */
7999 result = KERN_SUCCESS;
8000 goto finish;
8001 }
8002
8003 if (isInFileset() && kc_type != KCKindPageable) {
8004 // kexts in filesets have protections setup as part of collection loading
8005 result = KERN_SUCCESS;
8006 goto finish;
8007 }
8008 #endif
8009
8010 /* Protect the headers as read-only; they do not need to be wired */
8011 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8012 kext_map, kmod_info->address,
8013 kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
8014 : KERN_SUCCESS;
8015 if (result != KERN_SUCCESS) {
8016 goto finish;
8017 }
8018
8019 /* Set the VM protections and wire down each of the segments */
8020 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8021 while (seg) {
8022 #if __arm__
8023 /* We build all ARM kexts, so we can ensure they are aligned */
8024 assert((seg->vmaddr & PAGE_MASK) == 0);
8025 assert((seg->vmsize & PAGE_MASK) == 0);
8026 #endif
8027
8028 /*
8029 * For the non page aligned segments, the range calculation for protection
8030 * and wiring differ as follows:
8031 *
8032 * Protection: The non page aligned data at the start or at the end of the
8033 * segment is excluded from the protection. This exclusion is needed to make
8034 * sure OSKext_protect is not called twice on same page, if the page is shared
8035 * between two segments.
8036 *
8037 * Wiring: The non page aligned data at the start or at the end of the
8038 * segment is included in the wiring range, this inclusion is needed to make sure
8039 * all the data of the segment is wired.
8040 */
8041 start_protect = round_page(seg->vmaddr);
8042 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
8043 size_protect = end_protect - start_protect;
8044
8045 start_wire = trunc_page(seg->vmaddr);
8046 end_wire = round_page(seg->vmaddr + seg->vmsize);
8047
8048 /*
8049 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
8050 * across kexts and data from kexts is not page aligned
8051 */
8052 if (protect && (end_protect > start_protect) &&
8053 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
8054 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
8055 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
8056 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8057 kext_map, start_protect, size_protect, seg->maxprot, TRUE, kc_type);
8058 if (result != KERN_SUCCESS) {
8059 OSKextLog(this,
8060 kOSKextLogErrorLevel |
8061 kOSKextLogLoadFlag,
8062 "Kext %s failed to set maximum VM protections "
8063 "for segment %s - 0x%x.",
8064 getIdentifierCString(), seg->segname, (int)result);
8065 goto finish;
8066 }
8067
8068 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
8069 kext_map, start_protect, size_protect, seg->initprot, FALSE, kc_type);
8070 if (result != KERN_SUCCESS) {
8071 OSKextLog(this,
8072 kOSKextLogErrorLevel |
8073 kOSKextLogLoadFlag,
8074 "Kext %s failed to set initial VM protections "
8075 "for segment %s - 0x%x.",
8076 getIdentifierCString(), seg->segname, (int)result);
8077 goto finish;
8078 }
8079 }
8080
8081 if (segmentShouldBeWired(seg) && wire) {
8082 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
8083 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
8084 if (result != KERN_SUCCESS) {
8085 goto finish;
8086 }
8087 }
8088
8089 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8090 }
8091
8092 finish:
8093 return result;
8094 }
8095
8096 /*********************************************************************
8097 *********************************************************************/
8098 boolean_t
8099 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
8100 {
8101 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
8102 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
8103 }
8104
8105 /*********************************************************************
8106 *********************************************************************/
8107 OSReturn
8108 OSKext::validateKextMapping(bool startFlag)
8109 {
8110 OSReturn result = kOSReturnError;
8111 const char * whichOp = startFlag ? "start" : "stop";
8112 kern_return_t kern_result = 0;
8113 vm_map_t kext_map = NULL;
8114 kernel_segment_command_t * seg = NULL;
8115 mach_vm_address_t address = 0;
8116 mach_vm_size_t size = 0;
8117 uint32_t depth = 0;
8118 uint64_t kext_segbase = 0;
8119 uint64_t kext_segsize = 0;
8120 mach_msg_type_number_t count;
8121 vm_region_submap_short_info_data_64_t info;
8122 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
8123
8124 if (flags.builtin) {
8125 return kOSReturnSuccess;
8126 }
8127
8128 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
8129 bzero(&info, sizeof(info));
8130
8131 // xxx - do we need a distinct OSReturn value for these or is "bad data"
8132 // xxx - sufficient?
8133
8134 /* Verify that the kmod_info and start/stop pointers are non-NULL.
8135 */
8136 if (!kmod_info) {
8137 OSKextLog(this,
8138 kOSKextLogErrorLevel |
8139 kOSKextLogLoadFlag,
8140 "Kext %s - NULL kmod_info pointer.",
8141 getIdentifierCString());
8142 result = kOSKextReturnBadData;
8143 goto finish;
8144 }
8145
8146 if (startFlag) {
8147 address = (mach_vm_address_t)kmod_info->start;
8148 } else {
8149 address = (mach_vm_address_t)kmod_info->stop;
8150 }
8151
8152 if (!address) {
8153 OSKextLog(this,
8154 kOSKextLogErrorLevel |
8155 kOSKextLogLoadFlag,
8156 "Kext %s - NULL module %s pointer.",
8157 getIdentifierCString(), whichOp);
8158 result = kOSKextReturnBadData;
8159 goto finish;
8160 }
8161
8162 kext_map = kext_get_vm_map(kmod_info);
8163 depth = (kernel_map == kext_map) ? 1 : 2;
8164 if (isInFileset()) {
8165 #if defined(HAS_APPLE_PAC)
8166 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
8167 #endif /* defined(HAS_APPLE_PAC) */
8168 }
8169
8170 /* Verify that the start/stop function lies within the kext's address range.
8171 */
8172 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
8173 isInFileset()) {
8174 /* This will likely be how we deal with split kexts; walk the segments to
8175 * check that the function lies inside one of the segments of this kext.
8176 */
8177 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8178 seg != NULL;
8179 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
8180 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
8181 kext_segbase = seg->vmaddr;
8182 kext_segsize = seg->vmsize;
8183 break;
8184 }
8185 }
8186
8187 if (!seg) {
8188 OSKextLog(this,
8189 kOSKextLogErrorLevel |
8190 kOSKextLogLoadFlag,
8191 "Kext %s module %s pointer is outside of kext range "
8192 "(%s %p - kext starts at %p).",
8193 getIdentifierCString(),
8194 whichOp,
8195 whichOp,
8196 (void *)(((uintptr_t)address) - kext_slide),
8197 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
8198 result = kOSKextReturnBadData;
8199 goto finish;
8200 }
8201
8202 seg = NULL;
8203 } else {
8204 if (address < kmod_info->address + kmod_info->hdr_size ||
8205 kmod_info->address + kmod_info->size <= address) {
8206 OSKextLog(this,
8207 kOSKextLogErrorLevel |
8208 kOSKextLogLoadFlag,
8209 "Kext %s module %s pointer is outside of kext range "
8210 "(%s %p - kext at %p-%p).",
8211 getIdentifierCString(),
8212 whichOp,
8213 whichOp,
8214 (void *)(((uintptr_t)address) - kext_slide),
8215 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
8216 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
8217 result = kOSKextReturnBadData;
8218 goto finish;
8219 }
8220 }
8221
8222 /* Only do these checks before calling the start function;
8223 * If anything goes wrong with the mapping while the kext is running,
8224 * we'll likely have panicked well before any attempt to stop the kext.
8225 */
8226 if (startFlag) {
8227 if (!isInFileset() || kc_type != KCKindPrimary) {
8228 /*
8229 * Verify that the start/stop function is executable.
8230 */
8231 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
8232 (vm_region_recurse_info_t)&info, &count);
8233 if (kern_result != KERN_SUCCESS) {
8234 OSKextLog(this,
8235 kOSKextLogErrorLevel |
8236 kOSKextLogLoadFlag,
8237 "Kext %s - bad %s pointer %p.",
8238 getIdentifierCString(),
8239 whichOp, (void *)ml_static_unslide(address));
8240 result = kOSKextReturnBadData;
8241 goto finish;
8242 }
8243 } else {
8244 /*
8245 * Since kexts loaded from the primary KC are held in memory
8246 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
8247 * discover that memory's protection flags. Instead, we need to
8248 * get that information from the kernel pmap itself. Above, we
8249 * (potentially) saved the size of the segment in which the address
8250 * in question was located. If we have a non-zero size, verify
8251 * that all pages in the (address, address + kext_segsize) range
8252 * are marked executable. If we somehow did not record the size
8253 * (or the base) just verify the single page that includes the address.
8254 */
8255 if (kext_segbase == 0 || kext_segsize == 0) {
8256 kext_segbase = address & ~(uint64_t)PAGE_MASK;
8257 kext_segsize = PAGE_SIZE;
8258 }
8259 }
8260
8261 #if VM_MAPPED_KEXTS
8262 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
8263 ((isInFileset() && kc_type == KCKindPrimary) &&
8264 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
8265 OSKextLog(this,
8266 kOSKextLogErrorLevel |
8267 kOSKextLogLoadFlag,
8268 "Kext %s - memory region containing module %s function "
8269 "is not executable.",
8270 getIdentifierCString(), whichOp);
8271 result = kOSKextReturnBadData;
8272 goto finish;
8273 }
8274 #endif
8275
8276 /* Verify that the kext's segments are backed by physical memory.
8277 */
8278 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8279 while (seg) {
8280 if (!verifySegmentMapping(seg)) {
8281 result = kOSKextReturnBadData;
8282 goto finish;
8283 }
8284
8285 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8286 }
8287 }
8288
8289 result = kOSReturnSuccess;
8290 finish:
8291 return result;
8292 }
8293
8294 /*********************************************************************
8295 *********************************************************************/
8296 boolean_t
8297 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
8298 {
8299 mach_vm_address_t address = 0;
8300
8301 if (seg->vmsize > UINT32_MAX) {
8302 return false;
8303 }
8304
8305 if (!segmentShouldBeWired(seg)) {
8306 return true;
8307 }
8308
8309 for (address = seg->vmaddr;
8310 address < round_page(seg->vmaddr + seg->vmsize);
8311 address += PAGE_SIZE) {
8312 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
8313 OSKextLog(this,
8314 kOSKextLogErrorLevel |
8315 kOSKextLogLoadFlag,
8316 "Kext %s - page %p is not backed by physical memory.",
8317 getIdentifierCString(),
8318 (void *)address);
8319 return false;
8320 }
8321 }
8322
8323 return true;
8324 }
8325
8326 /*********************************************************************
8327 *********************************************************************/
8328 static void
8329 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
8330 {
8331 uint64_t stamp = 0;
8332 firehose_tracepoint_id_u trace_id;
8333 struct firehose_trace_uuid_info_s uuid_info_s;
8334 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
8335 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
8336 OSSharedPtr<OSData> uuid_data;
8337
8338 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
8339 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
8340
8341 uuid_data = aKext->copyTextUUID();
8342 if (uuid_data) {
8343 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
8344 }
8345
8346 uuid_info->ftui_size = size;
8347 if (aKext->isDriverKit()) {
8348 uuid_info->ftui_address = address;
8349 } else {
8350 uuid_info->ftui_address = ml_static_unslide(address);
8351 }
8352 os_log_encoded_metadata(trace_id, stamp, uuid_info, uuid_info_len);
8353 return;
8354 }
8355
8356 void
8357 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
8358 {
8359 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
8360 }
8361
8362 /*********************************************************************
8363 *********************************************************************/
8364 OSReturn
8365 OSKext::start(bool startDependenciesFlag)
8366 {
8367 OSReturn result = kOSReturnError;
8368 kern_return_t (* startfunc)(kmod_info_t *, void *);
8369 unsigned int i, count;
8370 void * kmodStartData = NULL;
8371
8372 if (isStarted() || isInterface() || isKernelComponent()) {
8373 result = kOSReturnSuccess;
8374 goto finish;
8375 }
8376
8377 if (!isLoaded()) {
8378 OSKextLog(this,
8379 kOSKextLogErrorLevel |
8380 kOSKextLogLoadFlag,
8381 "Attempt to start nonloaded kext %s.",
8382 getIdentifierCString());
8383 result = kOSKextReturnInvalidArgument;
8384 goto finish;
8385 }
8386
8387 if (!sLoadEnabled) {
8388 OSKextLog(this,
8389 kOSKextLogErrorLevel |
8390 kOSKextLogLoadFlag,
8391 "Kext loading is disabled (attempt to start kext %s).",
8392 getIdentifierCString());
8393 result = kOSKextReturnDisabled;
8394 goto finish;
8395 }
8396
8397 result = validateKextMapping(/* start? */ true);
8398 if (result != kOSReturnSuccess) {
8399 goto finish;
8400 }
8401
8402 startfunc = kmod_info->start;
8403
8404 count = getNumDependencies();
8405 for (i = 0; i < count; i++) {
8406 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
8407 if (dependency == NULL) {
8408 OSKextLog(this,
8409 kOSKextLogErrorLevel |
8410 kOSKextLogLoadFlag,
8411 "Kext %s start - internal error, dependency disappeared.",
8412 getIdentifierCString());
8413 goto finish;
8414 }
8415 if (!dependency->isStarted()) {
8416 if (startDependenciesFlag) {
8417 OSReturn dependencyResult =
8418 dependency->start(startDependenciesFlag);
8419 if (dependencyResult != KERN_SUCCESS) {
8420 OSKextLog(this,
8421 kOSKextLogErrorLevel |
8422 kOSKextLogLoadFlag,
8423 "Kext %s start - dependency %s failed to start (error 0x%x).",
8424 getIdentifierCString(),
8425 dependency->getIdentifierCString(),
8426 dependencyResult);
8427 goto finish;
8428 }
8429 } else {
8430 OSKextLog(this,
8431 kOSKextLogErrorLevel |
8432 kOSKextLogLoadFlag,
8433 "Not starting %s - dependency %s not started yet.",
8434 getIdentifierCString(),
8435 dependency->getIdentifierCString());
8436 result = kOSKextReturnStartStopError; // xxx - make new return?
8437 goto finish;
8438 }
8439 }
8440 }
8441
8442 OSKextLog(this,
8443 kOSKextLogDetailLevel |
8444 kOSKextLogLoadFlag,
8445 "Kext %s calling module start function.",
8446 getIdentifierCString());
8447
8448 flags.starting = 1;
8449
8450 // Drop a log message so logd can grab the needed information to decode this kext
8451 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
8452 result = OSRuntimeInitializeCPP(this);
8453 if (result == KERN_SUCCESS) {
8454 result = startfunc(kmod_info, kmodStartData);
8455 }
8456
8457 flags.starting = 0;
8458
8459 /* On success overlap the setting of started/starting. On failure just
8460 * clear starting.
8461 */
8462 if (result == KERN_SUCCESS) {
8463 flags.started = 1;
8464
8465 // xxx - log start error from kernel?
8466 OSKextLog(this,
8467 kOSKextLogProgressLevel |
8468 kOSKextLogLoadFlag,
8469 "Kext %s is now started.",
8470 getIdentifierCString());
8471 } else {
8472 invokeOrCancelRequestCallbacks(
8473 /* result not actually used */ kOSKextReturnStartStopError,
8474 /* invokeFlag */ false);
8475 OSKextLog(this,
8476 kOSKextLogWarningLevel |
8477 kOSKextLogLoadFlag,
8478 "Kext %s did not start (return code 0x%x).",
8479 getIdentifierCString(), result);
8480 }
8481
8482 finish:
8483 return result;
8484 }
8485
8486 /*********************************************************************
8487 *********************************************************************/
8488 /* static */
8489 bool
8490 OSKext::canUnloadKextWithIdentifier(
8491 OSString * kextIdentifier,
8492 bool checkClassesFlag)
8493 {
8494 bool result = false;
8495 OSKext * aKext = NULL; // do not release
8496
8497 IORecursiveLockLock(sKextLock);
8498
8499 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
8500
8501 if (!aKext) {
8502 goto finish; // can't unload what's not loaded
8503 }
8504
8505 if (aKext->isLoaded()) {
8506 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
8507 goto finish;
8508 }
8509 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
8510 goto finish;
8511 }
8512 }
8513
8514 result = true;
8515
8516 finish:
8517 IORecursiveLockUnlock(sKextLock);
8518 return result;
8519 }
8520
8521 /*********************************************************************
8522 *********************************************************************/
8523 OSReturn
8524 OSKext::stop(void)
8525 {
8526 OSReturn result = kOSReturnError;
8527 kern_return_t (*stopfunc)(kmod_info_t *, void *);
8528
8529 if (!isStarted() || isInterface()) {
8530 result = kOSReturnSuccess;
8531 goto finish;
8532 }
8533
8534 if (!isLoaded()) {
8535 OSKextLog(this,
8536 kOSKextLogErrorLevel |
8537 kOSKextLogLoadFlag,
8538 "Attempt to stop nonloaded kext %s.",
8539 getIdentifierCString());
8540 result = kOSKextReturnInvalidArgument;
8541 goto finish;
8542 }
8543
8544 /* Refuse to stop if we have clients or instances. It is up to
8545 * the caller to make sure those aren't true.
8546 */
8547 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8548 OSKextLog(this,
8549 kOSKextLogErrorLevel |
8550 kOSKextLogLoadFlag,
8551 "Kext %s - C++ instances; can't stop.",
8552 getIdentifierCString());
8553 result = kOSKextReturnInUse;
8554 goto finish;
8555 }
8556
8557 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8558 OSKextLog(this,
8559 kOSKextLogErrorLevel |
8560 kOSKextLogLoadFlag,
8561 "Kext %s - has references (linkage or tracking object); "
8562 "can't stop.",
8563 getIdentifierCString());
8564 result = kOSKextReturnInUse;
8565 goto finish;
8566 }
8567
8568 /* Note: If validateKextMapping fails on the stop & unload path,
8569 * we are in serious trouble and a kernel panic is likely whether
8570 * we stop & unload the kext or not.
8571 */
8572 result = validateKextMapping(/* start? */ false);
8573 if (result != kOSReturnSuccess) {
8574 goto finish;
8575 }
8576
8577 stopfunc = kmod_info->stop;
8578 if (stopfunc) {
8579 OSKextLog(this,
8580 kOSKextLogDetailLevel |
8581 kOSKextLogLoadFlag,
8582 "Kext %s calling module stop function.",
8583 getIdentifierCString());
8584
8585 flags.stopping = 1;
8586
8587 result = stopfunc(kmod_info, /* userData */ NULL);
8588 if (result == KERN_SUCCESS) {
8589 result = OSRuntimeFinalizeCPP(this);
8590 }
8591
8592 flags.stopping = 0;
8593
8594 if (result == KERN_SUCCESS) {
8595 flags.started = 0;
8596
8597 OSKextLog(this,
8598 kOSKextLogDetailLevel |
8599 kOSKextLogLoadFlag,
8600 "Kext %s is now stopped and ready to unload.",
8601 getIdentifierCString());
8602 } else {
8603 OSKextLog(this,
8604 kOSKextLogErrorLevel |
8605 kOSKextLogLoadFlag,
8606 "Kext %s did not stop (return code 0x%x).",
8607 getIdentifierCString(), result);
8608 result = kOSKextReturnStartStopError;
8609 }
8610 }
8611
8612 finish:
8613 // Drop a log message so logd can update this kext's metadata
8614 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
8615 return result;
8616 }
8617
8618 /*********************************************************************
8619 *********************************************************************/
8620 OSReturn
8621 OSKext::unload(void)
8622 {
8623 OSReturn result = kOSReturnError;
8624 unsigned int index;
8625 uint32_t num_kmod_refs = 0;
8626 OSKextAccount * freeAccount;
8627 bool in_fileset = false;
8628
8629 if (!sUnloadEnabled) {
8630 OSKextLog(this,
8631 kOSKextLogErrorLevel |
8632 kOSKextLogLoadFlag,
8633 "Kext unloading is disabled (%s).",
8634 this->getIdentifierCString());
8635
8636 result = kOSKextReturnDisabled;
8637 goto finish;
8638 }
8639
8640 // cache this result so we don't need to access the kmod_info after
8641 // it's been potentially free'd
8642 in_fileset = isInFileset();
8643
8644 /* Refuse to unload if we have clients or instances. It is up to
8645 * the caller to make sure those aren't true.
8646 */
8647 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
8648 // xxx - Don't log under errors? this is more of an info thing
8649 OSKextLog(this,
8650 kOSKextLogErrorLevel |
8651 kOSKextLogKextBookkeepingFlag,
8652 "Can't unload kext %s; outstanding references %d (linkage or tracking object).",
8653 getIdentifierCString(), getRetainCount());
8654 result = kOSKextReturnInUse;
8655 goto finish;
8656 }
8657
8658 if (isDriverKit()) {
8659 index = sLoadedDriverKitKexts->getNextIndexOfObject(this, 0);
8660 if (index != (unsigned int)-1) {
8661 sLoadedDriverKitKexts->removeObject(index);
8662 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
8663 loadTag = 0;
8664 }
8665 }
8666
8667 if (!isLoaded()) {
8668 result = kOSReturnSuccess;
8669 goto finish;
8670 }
8671
8672 if (isKernelComponent()) {
8673 result = kOSKextReturnInvalidArgument;
8674 goto finish;
8675 }
8676
8677 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
8678 OSKextLog(this,
8679 kOSKextLogErrorLevel |
8680 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8681 "Can't unload kext %s; classes have instances:",
8682 getIdentifierCString());
8683 reportOSMetaClassInstances(kOSKextLogErrorLevel |
8684 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
8685 result = kOSKextReturnInUse;
8686 goto finish;
8687 }
8688
8689 /* Note that the kext is unloading before running any code that
8690 * might be in the kext (request callbacks, module stop function).
8691 * We will deny certain requests made against a kext in the process
8692 * of unloading.
8693 */
8694 flags.unloading = 1;
8695
8696 /* Update the string describing the last kext to unload in case we panic.
8697 */
8698 savePanicString(/* isLoading */ false);
8699
8700 if (isStarted()) {
8701 result = stop();
8702 if (result != KERN_SUCCESS) {
8703 OSKextLog(this,
8704 kOSKextLogErrorLevel |
8705 kOSKextLogLoadFlag,
8706 "Kext %s can't unload - module stop returned 0x%x.",
8707 getIdentifierCString(), (unsigned)result);
8708 result = kOSKextReturnStartStopError;
8709 goto finish;
8710 }
8711 }
8712
8713 OSKextLog(this,
8714 kOSKextLogProgressLevel |
8715 kOSKextLogLoadFlag,
8716 "Kext %s unloading.",
8717 getIdentifierCString());
8718
8719 {
8720 struct list_head *p;
8721 struct list_head *prev;
8722 struct list_head *next;
8723 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
8724 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
8725 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
8726 prev = p->prev;
8727 next = p->next;
8728 prev->next = next;
8729 next->prev = prev;
8730 p->prev = p;
8731 p->next = p;
8732 IORecursiveLockWakeup(sKextLock, s, false);
8733 }
8734 }
8735
8736
8737 /* Even if we don't call the stop function, we want to be sure we
8738 * have no OSMetaClass references before unloading the kext executable
8739 * from memory. OSMetaClasses may have pointers into the kext executable
8740 * and that would cause a panic on OSKext::free() when metaClasses is freed.
8741 */
8742 if (metaClasses) {
8743 metaClasses->flushCollection();
8744 }
8745 (void) OSRuntimeFinalizeCPP(this);
8746
8747 /* Remove the kext from the list of loaded kexts, patch the gap
8748 * in the kmod_info_t linked list, and reset "kmod" to point to the
8749 * last loaded kext that isn't the fake kernel kext (sKernelKext).
8750 */
8751 index = sLoadedKexts->getNextIndexOfObject(this, 0);
8752 if (index != (unsigned int)-1) {
8753 sLoadedKexts->removeObject(index);
8754
8755 OSKext * nextKext = OSDynamicCast(OSKext,
8756 sLoadedKexts->getObject(index));
8757
8758 if (nextKext) {
8759 if (index > 0) {
8760 OSKext * gapKext = OSDynamicCast(OSKext,
8761 sLoadedKexts->getObject(index - 1));
8762
8763 nextKext->kmod_info->next = gapKext->kmod_info;
8764 } else { /* index == 0 */
8765 nextKext->kmod_info->next = NULL;
8766 }
8767 }
8768
8769 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
8770 if (lastKext && !lastKext->isKernel()) {
8771 kmod = lastKext->kmod_info;
8772 } else {
8773 kmod = NULL; // clear the global kmod variable
8774 }
8775 }
8776
8777 /* Clear out the kmod references that we're keeping for compatibility
8778 * with current panic backtrace code & kgmacros.
8779 * xxx - will want to update those bits sometime and remove this.
8780 */
8781 num_kmod_refs = getNumDependencies();
8782 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
8783 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
8784 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
8785 ref->info->reference_count--;
8786 }
8787 kfree_type(kmod_reference_t, num_kmod_refs,
8788 kmod_info->reference_list);
8789 }
8790
8791 #if CONFIG_DTRACE
8792 unregisterWithDTrace();
8793 #endif /* CONFIG_DTRACE */
8794
8795 notifyKextUnloadObservers(this);
8796
8797 freeAccount = NULL;
8798 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
8799 account->kext = NULL;
8800 if (account->site.tag) {
8801 account->site.flags |= VM_TAG_UNLOAD;
8802 } else {
8803 freeAccount = account;
8804 }
8805
8806 #if DEVELOPMENT || DEBUG
8807 assertf(account->task_refgrp.grp_count == 0,
8808 "unloading a kext with active task references");
8809 #endif /* DEVELOPMENT || DEBUG */
8810
8811 lck_ticket_unlock(sKextAccountsLock);
8812 if (freeAccount) {
8813 IOFreeType(freeAccount, OSKextAccount);
8814 }
8815
8816 /* Unwire and free the linked executable.
8817 */
8818 if (linkedExecutable) {
8819 #if KASAN
8820 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
8821 #endif
8822
8823 #if VM_MAPPED_KEXTS
8824 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
8825 kernel_segment_command_t *seg = NULL;
8826 vm_map_t kext_map = kext_get_vm_map(kmod_info);
8827
8828 if (!kext_map) {
8829 OSKextLog(this,
8830 kOSKextLogErrorLevel |
8831 kOSKextLogLoadFlag,
8832 "Failed to free kext %s; couldn't find the kext map.",
8833 getIdentifierCString());
8834 result = kOSKextReturnInternalError;
8835 goto finish;
8836 }
8837
8838 OSKextLog(this,
8839 kOSKextLogProgressLevel |
8840 kOSKextLogLoadFlag,
8841 "Kext %s unwiring and unmapping linked executable.",
8842 getIdentifierCString());
8843
8844 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
8845 while (seg) {
8846 if (segmentShouldBeWired(seg)) {
8847 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
8848 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
8849
8850 result = vm_map_unwire(kext_map, start_wire,
8851 end_wire, FALSE);
8852 if (result != KERN_SUCCESS) {
8853 OSKextLog(this,
8854 kOSKextLogErrorLevel |
8855 kOSKextLogLoadFlag,
8856 "Failed to unwire kext %s.",
8857 getIdentifierCString());
8858 result = kOSKextReturnInternalError;
8859 goto finish;
8860 }
8861 }
8862
8863 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
8864 }
8865 #if defined(__x86_64__) || defined(__i386__)
8866 if (in_fileset && flags.resetSegmentsFromVnode) {
8867 IORecursiveLockLock(sKextLock);
8868 resetKCFileSetSegments();
8869 IORecursiveLockUnlock(sKextLock);
8870 }
8871 #endif // (__x86_64__) || defined(__i386__)
8872 }
8873 #endif /* VM_MAPPED_KEXTS */
8874 if (flags.resetSegmentsFromImmutableCopy) {
8875 result = resetMutableSegments();
8876 if (result != kOSReturnSuccess) {
8877 OSKextLog(this,
8878 kOSKextLogErrorLevel |
8879 kOSKextLogLoadFlag,
8880 "Failed to reset kext %s.",
8881 getIdentifierCString());
8882 result = kOSKextReturnInternalError;
8883 goto finish;
8884 }
8885 }
8886 if (kc_type == KCKindUnknown) {
8887 linkedExecutable.reset();
8888 }
8889 }
8890
8891 /* An interface kext has a fake kmod_info that was allocated,
8892 * so we have to free it.
8893 */
8894 if (isInterface()) {
8895 kfree_type(kmod_info_t, kmod_info);
8896 kmod_info = NULL;
8897 }
8898
8899 if (!in_fileset) {
8900 kmod_info = NULL;
8901 }
8902
8903 flags.loaded = false;
8904 flushDependencies();
8905
8906 /* save a copy of the bundle ID for us to check when deciding to
8907 * rebuild the kernel cache file. If a kext was already in the kernel
8908 * cache and unloaded then later loaded we do not need to rebuild the
8909 * kernel cache. 9055303
8910 */
8911 if (isPrelinked()) {
8912 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
8913 IORecursiveLockLock(sKextLock);
8914 if (sUnloadedPrelinkedKexts) {
8915 sUnloadedPrelinkedKexts->setObject(bundleID.get());
8916 }
8917 IORecursiveLockUnlock(sKextLock);
8918 }
8919 }
8920
8921 OSKextLog(this,
8922 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8923 "Kext %s unloaded.", getIdentifierCString());
8924
8925 queueKextNotification(kKextRequestPredicateUnloadNotification,
8926 OSDynamicCast(OSString, bundleID.get()), getDextUniqueID());
8927
8928 finish:
8929 OSKext::saveLoadedKextPanicList();
8930 OSKext::updateLoadedKextSummaries();
8931
8932 flags.unloading = 0;
8933 return result;
8934 }
8935
8936 /*********************************************************************
8937 * Assumes sKextLock is held.
8938 *********************************************************************/
8939 /* static */
8940 OSReturn
8941 OSKext::queueKextNotification(
8942 const char * notificationName,
8943 OSString * kextIdentifier,
8944 OSData * dextUniqueIdentifier)
8945 {
8946 OSReturn result = kOSReturnError;
8947 OSSharedPtr<OSDictionary> loadRequest;
8948
8949 if (!kextIdentifier) {
8950 result = kOSKextReturnInvalidArgument;
8951 goto finish;
8952 }
8953
8954 /* Create a new request unless one is already sitting
8955 * in sKernelRequests for this bundle identifier
8956 */
8957 result = _OSKextCreateRequest(notificationName, loadRequest);
8958 if (result != kOSReturnSuccess) {
8959 goto finish;
8960 }
8961 if (!_OSKextSetRequestArgument(loadRequest.get(),
8962 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
8963 result = kOSKextReturnNoMemory;
8964 goto finish;
8965 }
8966 if (NULL != dextUniqueIdentifier) {
8967 if (!_OSKextSetRequestArgument(loadRequest.get(),
8968 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
8969 result = kOSKextReturnNoMemory;
8970 goto finish;
8971 }
8972 }
8973 if (!sKernelRequests->setObject(loadRequest.get())) {
8974 result = kOSKextReturnNoMemory;
8975 goto finish;
8976 }
8977
8978 /* We might want to only queue the notification if the IOKit daemon is active,
8979 * but that wouldn't work for embedded. Note that we don't care if
8980 * the ping immediately succeeds here so don't do anything with the
8981 * result of this call.
8982 */
8983 OSKext::pingIOKitDaemon();
8984
8985 result = kOSReturnSuccess;
8986
8987 finish:
8988 return result;
8989 }
8990
8991
8992 #if CONFIG_KXLD
8993 /*********************************************************************
8994 *********************************************************************/
8995 static void
8996 _OSKextConsiderDestroyingLinkContext(
8997 __unused thread_call_param_t p0,
8998 __unused thread_call_param_t p1)
8999 {
9000 /* Take multiple locks in the correct order.
9001 */
9002 IORecursiveLockLock(sKextLock);
9003 IORecursiveLockLock(sKextInnerLock);
9004
9005 /* The first time we destroy the kxldContext is in the first
9006 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
9007 * before calling this function. Thereafter any call to this function
9008 * will actually destroy the context.
9009 */
9010 if (sConsiderUnloadsCalled && sKxldContext) {
9011 kxld_destroy_context(sKxldContext);
9012 sKxldContext = NULL;
9013 }
9014
9015 /* Free the thread_call that was allocated to execute this function.
9016 */
9017 if (sDestroyLinkContextThread) {
9018 if (!thread_call_free(sDestroyLinkContextThread)) {
9019 OSKextLog(/* kext */ NULL,
9020 kOSKextLogErrorLevel |
9021 kOSKextLogGeneralFlag,
9022 "thread_call_free() failed for kext link context.");
9023 }
9024 sDestroyLinkContextThread = NULL;
9025 }
9026
9027 IORecursiveLockUnlock(sKextInnerLock);
9028 IORecursiveLockUnlock(sKextLock);
9029
9030 return;
9031 }
9032
9033 /*********************************************************************
9034 * Destroying the kxldContext requires checking variables under both
9035 * sKextInnerLock and sKextLock, so we do it on a separate thread
9036 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
9037 * call relationship.
9038 *
9039 * This function must be invoked with sKextInnerLock held.
9040 * Do not call any function that takes sKextLock here!
9041 *********************************************************************/
9042 /* static */
9043 void
9044 OSKext::considerDestroyingLinkContext(void)
9045 {
9046 IORecursiveLockLock(sKextInnerLock);
9047
9048 /* If we have already queued a thread to destroy the link context,
9049 * don't bother resetting; that thread will take care of it.
9050 */
9051 if (sDestroyLinkContextThread) {
9052 goto finish;
9053 }
9054
9055 /* The function to be invoked in the thread will deallocate
9056 * this thread_call, so don't share it around.
9057 */
9058 sDestroyLinkContextThread = thread_call_allocate(
9059 &_OSKextConsiderDestroyingLinkContext, NULL);
9060 if (!sDestroyLinkContextThread) {
9061 OSKextLog(/* kext */ NULL,
9062 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
9063 "Can't create thread to destroy kext link context.");
9064 goto finish;
9065 }
9066
9067 thread_call_enter(sDestroyLinkContextThread);
9068
9069 finish:
9070 IORecursiveLockUnlock(sKextInnerLock);
9071 return;
9072 }
9073
9074 #else // !CONFIG_KXLD
9075
9076 /* static */
9077 void
9078 OSKext::considerDestroyingLinkContext(void)
9079 {
9080 return;
9081 }
9082
9083 #endif // CONFIG_KXLD
9084
9085 #if PRAGMA_MARK
9086 #pragma mark Autounload
9087 #endif
9088 /*********************************************************************
9089 * This is a static method because the kext will be deallocated if it
9090 * does unload!
9091 *********************************************************************/
9092 /* static */
9093 OSReturn
9094 OSKext::autounloadKext(OSKext * aKext)
9095 {
9096 OSReturn result = kOSKextReturnInUse;
9097
9098 #if NO_KEXTD
9099 /*
9100 * Do not unload prelinked kexts on platforms that do not have an
9101 * IOKit daemon as there is no way to reload the kext or restart
9102 * matching.
9103 */
9104 if (aKext->isPrelinked()) {
9105 goto finish;
9106 }
9107 #endif /* defined(__x86_64__) */
9108
9109 /* Check for external references to this kext (usu. dependents),
9110 * instances of defined classes (or classes derived from them),
9111 * outstanding requests.
9112 */
9113 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
9114 !aKext->flags.autounloadEnabled ||
9115 aKext->isKernelComponent()) {
9116 goto finish;
9117 }
9118
9119 /* Skip a delay-autounload kext, once.
9120 */
9121 if (aKext->flags.delayAutounload) {
9122 OSKextLog(aKext,
9123 kOSKextLogProgressLevel |
9124 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
9125 "Kext %s has delayed autounload set; skipping and clearing flag.",
9126 aKext->getIdentifierCString());
9127 aKext->flags.delayAutounload = 0;
9128 goto finish;
9129 }
9130
9131 if (aKext->hasOSMetaClassInstances() ||
9132 aKext->countRequestCallbacks()) {
9133 goto finish;
9134 }
9135
9136 result = OSKext::removeKext(aKext);
9137
9138 finish:
9139 return result;
9140 }
9141
9142 /*********************************************************************
9143 *********************************************************************/
9144 void
9145 _OSKextConsiderUnloads(
9146 __unused thread_call_param_t p0,
9147 __unused thread_call_param_t p1)
9148 {
9149 bool didUnload = false;
9150 unsigned int count, i;
9151
9152 /* Take multiple locks in the correct order
9153 * (note also sKextSummaries lock further down).
9154 */
9155 IORecursiveLockLock(sKextLock);
9156 IORecursiveLockLock(sKextInnerLock);
9157
9158 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
9159
9160 /* If the system is powering down, don't try to unload anything.
9161 */
9162 if (sSystemSleep) {
9163 goto finish;
9164 }
9165
9166 OSKextLog(/* kext */ NULL,
9167 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
9168 "Checking for unused kexts to autounload.");
9169
9170 /*****
9171 * Remove any request callbacks marked as stale,
9172 * and mark as stale any currently in flight.
9173 */
9174 count = sRequestCallbackRecords->getCount();
9175 if (count) {
9176 i = count - 1;
9177 do {
9178 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
9179 sRequestCallbackRecords->getObject(i));
9180 if (callbackRecord) {
9181 OSBoolean * stale = OSDynamicCast(OSBoolean,
9182 callbackRecord->getObject(kKextRequestStaleKey));
9183
9184 if (stale == kOSBooleanTrue) {
9185 OSKext::invokeRequestCallback(callbackRecord,
9186 kOSKextReturnTimeout);
9187 } else {
9188 callbackRecord->setObject(kKextRequestStaleKey,
9189 kOSBooleanTrue);
9190 }
9191 }
9192 } while (i--);
9193 }
9194
9195 /*****
9196 * Make multiple passes through the array of loaded kexts until
9197 * we don't unload any. This handles unwinding of dependency
9198 * chains. We have to go *backwards* through the array because
9199 * kexts are removed from it when unloaded, and we cannot make
9200 * a copy or we'll mess up the retain counts we rely on to
9201 * check whether a kext will unload. If only we could have
9202 * nonretaining collections like CF has....
9203 */
9204 do {
9205 didUnload = false;
9206
9207 count = sLoadedKexts->getCount();
9208 if (count) {
9209 i = count - 1;
9210 do {
9211 OSKext * thisKext = OSDynamicCast(OSKext,
9212 sLoadedKexts->getObject(i));
9213 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
9214 } while (i--);
9215 }
9216 } while (didUnload);
9217
9218 finish:
9219 sConsiderUnloadsPending = false;
9220 sConsiderUnloadsExecuted = true;
9221
9222 (void) OSKext::considerRebuildOfPrelinkedKernel();
9223
9224 IORecursiveLockUnlock(sKextInnerLock);
9225 IORecursiveLockUnlock(sKextLock);
9226
9227 return;
9228 }
9229
9230 /*********************************************************************
9231 * Do not call any function that takes sKextLock here!
9232 *********************************************************************/
9233 void
9234 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
9235 {
9236 AbsoluteTime when;
9237
9238 IORecursiveLockLock(sKextInnerLock);
9239
9240 if (!sUnloadCallout) {
9241 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
9242 }
9243
9244 /* we only reset delay value for unloading if we already have something
9245 * pending. rescheduleOnlyFlag should not start the count down.
9246 */
9247 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
9248 goto finish;
9249 }
9250
9251 thread_call_cancel(sUnloadCallout);
9252 if (OSKext::getAutounloadEnabled() && !sSystemSleep
9253 #if !NO_KEXTD
9254 && sIOKitDaemonActive
9255 #endif
9256 ) {
9257 clock_interval_to_deadline(sConsiderUnloadDelay,
9258 1000 * 1000 * 1000, &when);
9259
9260 OSKextLog(/* kext */ NULL,
9261 kOSKextLogProgressLevel |
9262 kOSKextLogLoadFlag,
9263 "%scheduling %sscan for unused kexts in %lu seconds.",
9264 sConsiderUnloadsPending ? "Res" : "S",
9265 sConsiderUnloadsCalled ? "" : "initial ",
9266 (unsigned long)sConsiderUnloadDelay);
9267
9268 sConsiderUnloadsPending = true;
9269 thread_call_enter_delayed(sUnloadCallout, when);
9270 }
9271
9272 finish:
9273 /* The kxld context should be reused throughout boot. We mark the end of
9274 * period as the first time considerUnloads() is called, and we destroy
9275 * the first kxld context in that function. Afterwards, it will be
9276 * destroyed in flushNonloadedKexts.
9277 */
9278 if (!sConsiderUnloadsCalled) {
9279 sConsiderUnloadsCalled = true;
9280 OSKext::considerDestroyingLinkContext();
9281 }
9282
9283 IORecursiveLockUnlock(sKextInnerLock);
9284 return;
9285 }
9286
9287 /*********************************************************************
9288 * Do not call any function that takes sKextLock here!
9289 *********************************************************************/
9290 extern "C" {
9291 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
9292 IOReturn
9293 OSKextSystemSleepOrWake(UInt32 messageType)
9294 {
9295 IORecursiveLockLock(sKextInnerLock);
9296
9297 /* If the system is going to sleep, cancel the reaper thread timer,
9298 * and note that we're in a sleep state in case it just fired but hasn't
9299 * taken the lock yet. If we are coming back from sleep, just
9300 * clear the sleep flag; IOService's normal operation will cause
9301 * unloads to be considered soon enough.
9302 */
9303 if (messageType == kIOMessageSystemWillSleep) {
9304 if (sUnloadCallout) {
9305 thread_call_cancel(sUnloadCallout);
9306 }
9307 sSystemSleep = true;
9308 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
9309 } else if (messageType == kIOMessageSystemHasPoweredOn) {
9310 sSystemSleep = false;
9311 clock_get_uptime(&sLastWakeTime);
9312 }
9313 IORecursiveLockUnlock(sKextInnerLock);
9314
9315 return kIOReturnSuccess;
9316 }
9317 };
9318
9319
9320 #if PRAGMA_MARK
9321 #pragma mark Prelinked Kernel
9322 #endif
9323
9324 #ifdef CONFIG_KXLD
9325 /*********************************************************************
9326 * Do not access sConsiderUnloads... variables other than
9327 * sConsiderUnloadsExecuted in this function. They are guarded by a
9328 * different lock.
9329 *********************************************************************/
9330 /* static */
9331 void
9332 OSKext::considerRebuildOfPrelinkedKernel(void)
9333 {
9334 static bool requestedPrelink = false;
9335 OSReturn checkResult = kOSReturnError;
9336 OSSharedPtr<OSDictionary> prelinkRequest;
9337 OSSharedPtr<OSCollectionIterator> kextIterator;
9338 const OSSymbol * thisID = NULL; // do not release
9339 bool doRebuild = false;
9340 AbsoluteTime my_abstime;
9341 UInt64 my_ns;
9342 SInt32 delta_secs;
9343
9344 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
9345 if (requestedPrelink || !sPrelinkBoot) {
9346 return;
9347 }
9348
9349 /* no direct return from this point */
9350 IORecursiveLockLock(sKextLock);
9351
9352 /* We need to wait for the IOKit daemon to get up and running with unloads already done
9353 * and any new startup kexts loaded.
9354 */
9355 if (!sConsiderUnloadsExecuted ||
9356 !sDeferredLoadSucceeded) {
9357 goto finish;
9358 }
9359
9360 /* we really only care about boot / system start up related kexts so bail
9361 * if we're here after REBUILD_MAX_TIME.
9362 */
9363 if (!_OSKextInPrelinkRebuildWindow()) {
9364 OSKextLog(/* kext */ NULL,
9365 kOSKextLogArchiveFlag,
9366 "%s prebuild rebuild has expired",
9367 __FUNCTION__);
9368 requestedPrelink = true;
9369 goto finish;
9370 }
9371
9372 /* we do not want to trigger a rebuild if we get here too close to waking
9373 * up. (see radar 10233768)
9374 */
9375 IORecursiveLockLock(sKextInnerLock);
9376
9377 clock_get_uptime(&my_abstime);
9378 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
9379 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
9380 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
9381 absolutetime_to_nanoseconds(my_abstime, &my_ns);
9382 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
9383 }
9384 IORecursiveLockUnlock(sKextInnerLock);
9385
9386 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
9387 /* too close to time of last wake from sleep */
9388 goto finish;
9389 }
9390 requestedPrelink = true;
9391
9392 /* Now it's time to see if we have a reason to rebuild. We may have done
9393 * some loads and unloads but the kernel cache didn't actually change.
9394 * We will rebuild if any kext is not marked prelinked AND is not in our
9395 * list of prelinked kexts that got unloaded. (see radar 9055303)
9396 */
9397 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
9398 if (!kextIterator) {
9399 goto finish;
9400 }
9401
9402 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
9403 OSKext * thisKext; // do not release
9404
9405 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
9406 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
9407 continue;
9408 }
9409
9410 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
9411 continue;
9412 }
9413 /* kext is loaded and was not in current kernel cache so let's rebuild
9414 */
9415 doRebuild = true;
9416 OSKextLog(/* kext */ NULL,
9417 kOSKextLogArchiveFlag,
9418 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
9419 thisKext->bundleID->getCStringNoCopy());
9420 break;
9421 }
9422 sUnloadedPrelinkedKexts->flushCollection();
9423
9424 if (!doRebuild) {
9425 goto finish;
9426 }
9427
9428 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
9429 prelinkRequest);
9430 if (checkResult != kOSReturnSuccess) {
9431 goto finish;
9432 }
9433
9434 if (!sKernelRequests->setObject(prelinkRequest.get())) {
9435 goto finish;
9436 }
9437
9438 OSKext::pingIOKitDaemon();
9439
9440 finish:
9441 IORecursiveLockUnlock(sKextLock);
9442
9443 return;
9444 }
9445
9446 #else /* !CONFIG_KXLD */
9447
9448 void
9449 OSKext::considerRebuildOfPrelinkedKernel(void)
9450 {
9451 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
9452 return;
9453 }
9454
9455 #endif /* CONFIG_KXLD */
9456
9457 #if PRAGMA_MARK
9458 #pragma mark Dependencies
9459 #endif
9460 /*********************************************************************
9461 *********************************************************************/
9462 bool
9463 OSKext::resolveDependencies(
9464 OSArray * loopStack)
9465 {
9466 bool result = false;
9467 OSSharedPtr<OSArray> localLoopStack;
9468 bool addedToLoopStack = false;
9469 OSDictionary * libraries = NULL; // do not release
9470 OSSharedPtr<OSCollectionIterator> libraryIterator;
9471 OSString * libraryID = NULL; // do not release
9472 OSKext * libraryKext = NULL; // do not release
9473 bool hasRawKernelDependency = false;
9474 bool hasKernelDependency = false;
9475 bool hasKPIDependency = false;
9476 bool hasPrivateKPIDependency = false;
9477 unsigned int count;
9478
9479 #if CONFIG_KXLD
9480 OSString * infoString = NULL; // do not release
9481 OSString * readableString = NULL; // do not release
9482 #endif // CONFIG_KXLD
9483
9484 /* A kernel component will automatically have this flag set,
9485 * and a loaded kext should also have it set (as should all its
9486 * loaded dependencies).
9487 */
9488 if (flags.hasAllDependencies) {
9489 result = true;
9490 goto finish;
9491 }
9492
9493 /* Check for loops in the dependency graph.
9494 */
9495 if (loopStack) {
9496 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
9497 OSKextLog(this,
9498 kOSKextLogErrorLevel |
9499 kOSKextLogDependenciesFlag,
9500 "Kext %s has a dependency loop; can't resolve dependencies.",
9501 getIdentifierCString());
9502 goto finish;
9503 }
9504 } else {
9505 OSKextLog(this,
9506 kOSKextLogStepLevel |
9507 kOSKextLogDependenciesFlag,
9508 "Kext %s resolving dependencies.",
9509 getIdentifierCString());
9510
9511 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
9512 if (!localLoopStack) {
9513 OSKextLog(this,
9514 kOSKextLogErrorLevel |
9515 kOSKextLogDependenciesFlag,
9516 "Kext %s can't create bookkeeping stack to resolve dependencies.",
9517 getIdentifierCString());
9518 goto finish;
9519 }
9520 loopStack = localLoopStack.get();
9521 }
9522 if (!loopStack->setObject(this)) {
9523 OSKextLog(this,
9524 kOSKextLogErrorLevel |
9525 kOSKextLogDependenciesFlag,
9526 "Kext %s - internal error resolving dependencies.",
9527 getIdentifierCString());
9528 goto finish;
9529 }
9530 addedToLoopStack = true;
9531
9532 /* Purge any existing kexts in the dependency list and start over.
9533 */
9534 flushDependencies();
9535 if (dependencies) {
9536 OSKextLog(this,
9537 kOSKextLogErrorLevel |
9538 kOSKextLogDependenciesFlag,
9539 "Kext %s - internal error resolving dependencies.",
9540 getIdentifierCString());
9541 }
9542
9543 libraries = OSDynamicCast(OSDictionary,
9544 getPropertyForHostArch(kOSBundleLibrariesKey));
9545 if (libraries == NULL || libraries->getCount() == 0) {
9546 OSKextLog(this,
9547 kOSKextLogErrorLevel |
9548 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9549 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
9550 getIdentifierCString(), kOSBundleLibrariesKey);
9551 goto finish;
9552 }
9553
9554 /* Make a new array to hold the dependencies (flush freed the old one).
9555 */
9556 dependencies = OSArray::withCapacity(libraries->getCount());
9557 if (!dependencies) {
9558 OSKextLog(this,
9559 kOSKextLogErrorLevel |
9560 kOSKextLogDependenciesFlag,
9561 "Kext %s - can't allocate dependencies array.",
9562 getIdentifierCString());
9563 goto finish;
9564 }
9565
9566 // xxx - compat: We used to add an implicit dependency on kernel 6.0
9567 // xxx - compat: if none were declared.
9568
9569 libraryIterator = OSCollectionIterator::withCollection(libraries);
9570 if (!libraryIterator) {
9571 OSKextLog(this,
9572 kOSKextLogErrorLevel |
9573 kOSKextLogDependenciesFlag,
9574 "Kext %s - can't allocate dependencies iterator.",
9575 getIdentifierCString());
9576 goto finish;
9577 }
9578
9579 while ((libraryID = OSDynamicCast(OSString,
9580 libraryIterator->getNextObject()))) {
9581 const char * library_id = libraryID->getCStringNoCopy();
9582
9583 OSString * libraryVersion = OSDynamicCast(OSString,
9584 libraries->getObject(libraryID));
9585 if (libraryVersion == NULL) {
9586 OSKextLog(this,
9587 kOSKextLogErrorLevel |
9588 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9589 "Kext %s - illegal type in OSBundleLibraries.",
9590 getIdentifierCString());
9591 goto finish;
9592 }
9593
9594 OSKextVersion libraryVers =
9595 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
9596 if (libraryVers == -1) {
9597 OSKextLog(this,
9598 kOSKextLogErrorLevel |
9599 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9600 "Kext %s - invalid library version %s.",
9601 getIdentifierCString(),
9602 libraryVersion->getCStringNoCopy());
9603 goto finish;
9604 }
9605
9606 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
9607 if (libraryKext == NULL) {
9608 OSKextLog(this,
9609 kOSKextLogErrorLevel |
9610 kOSKextLogDependenciesFlag,
9611 "Kext %s - library kext %s not found.",
9612 getIdentifierCString(), library_id);
9613 goto finish;
9614 }
9615
9616 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
9617 OSKextLog(this,
9618 kOSKextLogErrorLevel |
9619 kOSKextLogDependenciesFlag,
9620 "Kext %s - library kext %s not compatible "
9621 "with requested version %s.",
9622 getIdentifierCString(), library_id,
9623 libraryVersion->getCStringNoCopy());
9624 goto finish;
9625 }
9626
9627 /* If a nonprelinked library somehow got into the mix for a
9628 * prelinked kext, at any point in the chain, we must fail
9629 * because the prelinked relocs for the library will be all wrong.
9630 */
9631 if (this->isPrelinked() &&
9632 libraryKext->declaresExecutable() &&
9633 !libraryKext->isPrelinked()) {
9634 OSKextLog(this,
9635 kOSKextLogErrorLevel |
9636 kOSKextLogDependenciesFlag,
9637 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
9638 getIdentifierCString(), library_id,
9639 libraryVersion->getCStringNoCopy());
9640 goto finish;
9641 }
9642
9643 if (!libraryKext->resolveDependencies(loopStack)) {
9644 goto finish;
9645 }
9646
9647 /* Add the library directly only if it has an executable to link.
9648 * Otherwise it's just used to collect other dependencies, so put
9649 * *its* dependencies on the list for this kext.
9650 */
9651 // xxx - We are losing info here; would like to make fake entries or
9652 // xxx - keep these in the dependency graph for loaded kexts.
9653 // xxx - I really want to make kernel components not a special case!
9654 if (libraryKext->declaresExecutable() ||
9655 libraryKext->isInterface()) {
9656 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
9657 dependencies->setObject(libraryKext);
9658
9659 OSKextLog(this,
9660 kOSKextLogDetailLevel |
9661 kOSKextLogDependenciesFlag,
9662 "Kext %s added dependency %s.",
9663 getIdentifierCString(),
9664 libraryKext->getIdentifierCString());
9665 }
9666 } else {
9667 int numLibDependencies = libraryKext->getNumDependencies();
9668 OSArray * libraryDependencies = libraryKext->getDependencies();
9669 int index;
9670
9671 if (numLibDependencies) {
9672 // xxx - this msg level should be 1 lower than the per-kext one
9673 OSKextLog(this,
9674 kOSKextLogDetailLevel |
9675 kOSKextLogDependenciesFlag,
9676 "Kext %s pulling %d dependencies from codeless library %s.",
9677 getIdentifierCString(),
9678 numLibDependencies,
9679 libraryKext->getIdentifierCString());
9680 }
9681 for (index = 0; index < numLibDependencies; index++) {
9682 OSKext * thisLibDependency = OSDynamicCast(OSKext,
9683 libraryDependencies->getObject(index));
9684 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
9685 dependencies->setObject(thisLibDependency);
9686 OSKextLog(this,
9687 kOSKextLogDetailLevel |
9688 kOSKextLogDependenciesFlag,
9689 "Kext %s added dependency %s from codeless library %s.",
9690 getIdentifierCString(),
9691 thisLibDependency->getIdentifierCString(),
9692 libraryKext->getIdentifierCString());
9693 }
9694 }
9695 }
9696
9697 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
9698 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
9699 hasRawKernelDependency = true;
9700 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
9701 hasKernelDependency = true;
9702 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
9703 hasKPIDependency = true;
9704 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
9705 hasPrivateKPIDependency = true;
9706 }
9707 }
9708 }
9709
9710 if (hasRawKernelDependency) {
9711 OSKextLog(this,
9712 kOSKextLogErrorLevel |
9713 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9714 "Error - kext %s declares a dependency on %s, which is not permitted.",
9715 getIdentifierCString(), KERNEL_LIB);
9716 goto finish;
9717 }
9718 #if __LP64__
9719 if (hasKernelDependency) {
9720 OSKextLog(this,
9721 kOSKextLogErrorLevel |
9722 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
9723 "Error - kext %s declares %s dependencies. "
9724 "Only %s* dependencies are supported for 64-bit kexts.",
9725 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9726 goto finish;
9727 }
9728 if (!hasKPIDependency) {
9729 OSKextLog(this,
9730 kOSKextLogWarningLevel |
9731 kOSKextLogDependenciesFlag,
9732 "Warning - kext %s declares no %s* dependencies. "
9733 "If it uses any KPIs, the link may fail with undefined symbols.",
9734 getIdentifierCString(), KPI_LIB_PREFIX);
9735 }
9736 #else /* __LP64__ */
9737 // xxx - will change to flatly disallow "kernel" dependencies at some point
9738 // xxx - is it invalid to do both "com.apple.kernel" and any
9739 // xxx - "com.apple.kernel.*"?
9740
9741 if (hasKernelDependency && hasKPIDependency) {
9742 OSKextLog(this,
9743 kOSKextLogWarningLevel |
9744 kOSKextLogDependenciesFlag,
9745 "Warning - kext %s has immediate dependencies on both "
9746 "%s* and %s* components; use only one style.",
9747 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
9748 }
9749
9750 if (!hasKernelDependency && !hasKPIDependency) {
9751 // xxx - do we want to use validation flag for these too?
9752 OSKextLog(this,
9753 kOSKextLogWarningLevel |
9754 kOSKextLogDependenciesFlag,
9755 "Warning - %s declares no kernel dependencies; using %s.",
9756 getIdentifierCString(), KERNEL6_LIB);
9757 OSKext * kernelKext = OSDynamicCast(OSKext,
9758 sKextsByID->getObject(KERNEL6_LIB));
9759 if (kernelKext) {
9760 dependencies->setObject(kernelKext);
9761 } else {
9762 OSKextLog(this,
9763 kOSKextLogErrorLevel |
9764 kOSKextLogDependenciesFlag,
9765 "Error - Library %s not found for %s.",
9766 KERNEL6_LIB, getIdentifierCString());
9767 }
9768 }
9769
9770 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
9771 * its indirect dependencies to simulate old-style linking. XXX - Should
9772 * check for duplicates.
9773 */
9774 if (!hasKPIDependency) {
9775 unsigned int i;
9776
9777 flags.hasBleedthrough = true;
9778
9779 count = getNumDependencies();
9780
9781 /* We add to the dependencies array in this loop, but do not iterate
9782 * past its original count.
9783 */
9784 for (i = 0; i < count; i++) {
9785 OSKext * dependencyKext = OSDynamicCast(OSKext,
9786 dependencies->getObject(i));
9787 dependencyKext->addBleedthroughDependencies(dependencies.get());
9788 }
9789 }
9790 #endif /* __LP64__ */
9791
9792 #if CONFIG_KXLD
9793 /*
9794 * If we're not dynamically linking kexts, then we don't need to check
9795 * copyright strings. The linker in user space has already done this.
9796 */
9797 if (hasPrivateKPIDependency) {
9798 bool hasApplePrefix = false;
9799 bool infoCopyrightIsValid = false;
9800 bool readableCopyrightIsValid = false;
9801
9802 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
9803 APPLE_KEXT_PREFIX);
9804
9805 infoString = OSDynamicCast(OSString,
9806 getPropertyForHostArch("CFBundleGetInfoString"));
9807 if (infoString) {
9808 infoCopyrightIsValid =
9809 kxld_validate_copyright_string(infoString->getCStringNoCopy());
9810 }
9811
9812 readableString = OSDynamicCast(OSString,
9813 getPropertyForHostArch("NSHumanReadableCopyright"));
9814 if (readableString) {
9815 readableCopyrightIsValid =
9816 kxld_validate_copyright_string(readableString->getCStringNoCopy());
9817 }
9818
9819 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
9820 OSKextLog(this,
9821 kOSKextLogErrorLevel |
9822 kOSKextLogDependenciesFlag,
9823 "Error - kext %s declares a dependency on %s. "
9824 "Only Apple kexts may declare a dependency on %s.",
9825 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
9826 goto finish;
9827 }
9828 }
9829 #endif // CONFIG_KXLD
9830
9831 result = true;
9832 flags.hasAllDependencies = 1;
9833
9834 finish:
9835
9836 if (addedToLoopStack) {
9837 count = loopStack->getCount();
9838 if (count > 0 && (this == loopStack->getObject(count - 1))) {
9839 loopStack->removeObject(count - 1);
9840 } else {
9841 OSKextLog(this,
9842 kOSKextLogErrorLevel |
9843 kOSKextLogDependenciesFlag,
9844 "Kext %s - internal error resolving dependencies.",
9845 getIdentifierCString());
9846 }
9847 }
9848
9849 if (result && localLoopStack) {
9850 OSKextLog(this,
9851 kOSKextLogStepLevel |
9852 kOSKextLogDependenciesFlag,
9853 "Kext %s successfully resolved dependencies.",
9854 getIdentifierCString());
9855 }
9856
9857 return result;
9858 }
9859
9860 /*********************************************************************
9861 *********************************************************************/
9862 bool
9863 OSKext::addBleedthroughDependencies(OSArray * anArray)
9864 {
9865 bool result = false;
9866 unsigned int dependencyIndex, dependencyCount;
9867
9868 dependencyCount = getNumDependencies();
9869
9870 for (dependencyIndex = 0;
9871 dependencyIndex < dependencyCount;
9872 dependencyIndex++) {
9873 OSKext * dependency = OSDynamicCast(OSKext,
9874 dependencies->getObject(dependencyIndex));
9875 if (!dependency) {
9876 OSKextLog(this,
9877 kOSKextLogErrorLevel |
9878 kOSKextLogDependenciesFlag,
9879 "Kext %s - internal error propagating compatibility dependencies.",
9880 getIdentifierCString());
9881 goto finish;
9882 }
9883 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
9884 anArray->setObject(dependency);
9885 }
9886 dependency->addBleedthroughDependencies(anArray);
9887 }
9888
9889 result = true;
9890
9891 finish:
9892 return result;
9893 }
9894
9895 /*********************************************************************
9896 *********************************************************************/
9897 bool
9898 OSKext::flushDependencies(bool forceFlag)
9899 {
9900 bool result = false;
9901
9902 /* Only clear the dependencies if the kext isn't loaded;
9903 * we need the info for loaded kexts to track references.
9904 */
9905 if (!isLoaded() || forceFlag) {
9906 if (dependencies) {
9907 // xxx - check level
9908 OSKextLog(this,
9909 kOSKextLogProgressLevel |
9910 kOSKextLogDependenciesFlag,
9911 "Kext %s flushing dependencies.",
9912 getIdentifierCString());
9913 dependencies.reset();
9914 }
9915 if (!isKernelComponent()) {
9916 flags.hasAllDependencies = 0;
9917 }
9918 result = true;
9919 }
9920
9921 return result;
9922 }
9923
9924 /*********************************************************************
9925 *********************************************************************/
9926 uint32_t
9927 OSKext::getNumDependencies(void)
9928 {
9929 if (!dependencies) {
9930 return 0;
9931 }
9932 return dependencies->getCount();
9933 }
9934
9935 /*********************************************************************
9936 *********************************************************************/
9937 OSArray *
9938 OSKext::getDependencies(void)
9939 {
9940 return dependencies.get();
9941 }
9942
9943 bool
9944 OSKext::hasDependency(const OSSymbol * depID)
9945 {
9946 bool result __block;
9947
9948 if (depID == getIdentifier()) {
9949 return true;
9950 }
9951 if (!dependencies) {
9952 return false;
9953 }
9954 result = false;
9955 dependencies->iterateObjects(^bool (OSObject * obj) {
9956 OSKext * kext;
9957 kext = OSDynamicCast(OSKext, obj);
9958 if (!kext) {
9959 return false;
9960 }
9961 result = (depID == kext->getIdentifier());
9962 return result;
9963 });
9964 return result;
9965 }
9966
9967 #if PRAGMA_MARK
9968 #pragma mark OSMetaClass Support
9969 #endif
9970 /*********************************************************************
9971 *********************************************************************/
9972 OSReturn
9973 OSKext::addClass(
9974 OSMetaClass * aClass,
9975 uint32_t numClasses)
9976 {
9977 OSReturn result = kOSMetaClassNoInsKModSet;
9978
9979 if (!metaClasses) {
9980 metaClasses = OSSet::withCapacity(numClasses);
9981 if (!metaClasses) {
9982 goto finish;
9983 }
9984 }
9985
9986 if (metaClasses->containsObject(aClass)) {
9987 OSKextLog(this,
9988 kOSKextLogWarningLevel |
9989 kOSKextLogLoadFlag,
9990 "Notice - kext %s has already registered class %s.",
9991 getIdentifierCString(),
9992 aClass->getClassName());
9993 result = kOSReturnSuccess;
9994 goto finish;
9995 }
9996
9997 if (!metaClasses->setObject(aClass)) {
9998 goto finish;
9999 } else {
10000 OSKextLog(this,
10001 kOSKextLogDetailLevel |
10002 kOSKextLogLoadFlag,
10003 "Kext %s registered class %s.",
10004 getIdentifierCString(),
10005 aClass->getClassName());
10006 }
10007
10008 if (!flags.autounloadEnabled) {
10009 const OSMetaClass * metaScan = NULL; // do not release
10010
10011 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
10012 if (metaScan == OSTypeID(IOService)) {
10013 OSKextLog(this,
10014 kOSKextLogProgressLevel |
10015 kOSKextLogLoadFlag,
10016 "Kext %s has IOService subclass %s; enabling autounload.",
10017 getIdentifierCString(),
10018 aClass->getClassName());
10019
10020 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
10021 break;
10022 }
10023 }
10024 }
10025
10026 notifyAddClassObservers(this, aClass, flags);
10027
10028 result = kOSReturnSuccess;
10029
10030 finish:
10031 if (result != kOSReturnSuccess) {
10032 OSKextLog(this,
10033 kOSKextLogErrorLevel |
10034 kOSKextLogLoadFlag,
10035 "Kext %s failed to register class %s.",
10036 getIdentifierCString(),
10037 aClass->getClassName());
10038 }
10039
10040 return result;
10041 }
10042
10043 /*********************************************************************
10044 *********************************************************************/
10045 OSReturn
10046 OSKext::removeClass(
10047 OSMetaClass * aClass)
10048 {
10049 OSReturn result = kOSMetaClassNoKModSet;
10050
10051 if (!metaClasses) {
10052 goto finish;
10053 }
10054
10055 if (!metaClasses->containsObject(aClass)) {
10056 OSKextLog(this,
10057 kOSKextLogWarningLevel |
10058 kOSKextLogLoadFlag,
10059 "Notice - kext %s asked to unregister unknown class %s.",
10060 getIdentifierCString(),
10061 aClass->getClassName());
10062 result = kOSReturnSuccess;
10063 goto finish;
10064 }
10065
10066 OSKextLog(this,
10067 kOSKextLogDetailLevel |
10068 kOSKextLogLoadFlag,
10069 "Kext %s unregistering class %s.",
10070 getIdentifierCString(),
10071 aClass->getClassName());
10072
10073 metaClasses->removeObject(aClass);
10074
10075 notifyRemoveClassObservers(this, aClass, flags);
10076
10077 result = kOSReturnSuccess;
10078
10079 finish:
10080 if (result != kOSReturnSuccess) {
10081 OSKextLog(this,
10082 kOSKextLogErrorLevel |
10083 kOSKextLogLoadFlag,
10084 "Failed to unregister kext %s class %s.",
10085 getIdentifierCString(),
10086 aClass->getClassName());
10087 }
10088 return result;
10089 }
10090
10091 /*********************************************************************
10092 *********************************************************************/
10093 OSSet *
10094 OSKext::getMetaClasses(void)
10095 {
10096 return metaClasses.get();
10097 }
10098
10099 /*********************************************************************
10100 *********************************************************************/
10101 bool
10102 OSKext::hasOSMetaClassInstances(void)
10103 {
10104 bool result = false;
10105 OSSharedPtr<OSCollectionIterator> classIterator;
10106 OSMetaClass * checkClass = NULL; // do not release
10107
10108 if (!metaClasses) {
10109 goto finish;
10110 }
10111
10112 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10113 if (!classIterator) {
10114 // xxx - log alloc failure?
10115 goto finish;
10116 }
10117 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10118 if (checkClass->getInstanceCount()) {
10119 result = true;
10120 goto finish;
10121 }
10122 }
10123
10124 finish:
10125 return result;
10126 }
10127
10128 /*********************************************************************
10129 *********************************************************************/
10130 /* static */
10131 void
10132 OSKext::reportOSMetaClassInstances(
10133 const char * kextIdentifier,
10134 OSKextLogSpec msgLogSpec)
10135 {
10136 OSSharedPtr<OSKext> theKext;
10137
10138 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
10139 if (!theKext) {
10140 goto finish;
10141 }
10142
10143 theKext->reportOSMetaClassInstances(msgLogSpec);
10144 finish:
10145 return;
10146 }
10147
10148 /*********************************************************************
10149 *********************************************************************/
10150 void
10151 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
10152 {
10153 OSSharedPtr<OSCollectionIterator> classIterator;
10154 OSMetaClass * checkClass = NULL; // do not release
10155
10156 if (!metaClasses) {
10157 goto finish;
10158 }
10159
10160 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
10161 if (!classIterator) {
10162 goto finish;
10163 }
10164 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
10165 if (checkClass->getInstanceCount()) {
10166 OSKextLog(this,
10167 msgLogSpec,
10168 " Kext %s class %s has %d instance%s.",
10169 getIdentifierCString(),
10170 checkClass->getClassName(),
10171 checkClass->getInstanceCount(),
10172 checkClass->getInstanceCount() == 1 ? "" : "s");
10173 }
10174 }
10175
10176 finish:
10177 return;
10178 }
10179
10180 #if PRAGMA_MARK
10181 #pragma mark User-Space Requests
10182 #endif
10183
10184 static kern_return_t
10185 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
10186 {
10187 OSReturn result = kOSReturnSuccess;
10188 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
10189 OSDictionary * request = NULL; //do not release
10190 IOUserServerCheckInToken * token = NULL; //do not release
10191 OSString * requestPredicate = NULL; //do not release
10192 OSSharedPtr<OSNumber> portNameNumber;
10193 mach_port_name_t portName = 0;
10194 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
10195 if (!request) {
10196 OSKextLog(/* kext */ NULL,
10197 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10198 "Elements of request should be of type OSDictionary");
10199 result = kOSKextReturnInternalError;
10200 goto finish;
10201 }
10202 requestPredicate = _OSKextGetRequestPredicate(request);
10203 if (!requestPredicate) {
10204 OSKextLog(/* kext */ NULL,
10205 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10206 "Failed to get request predicate");
10207 result = kOSKextReturnInternalError;
10208 goto finish;
10209 }
10210 // is this a dext launch?
10211 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
10212 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
10213 if (!token) {
10214 OSKextLog(/* kext */ NULL,
10215 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10216 "Could not find a IOUserServerCheckInToken in daemon launch request.");
10217 result = kOSKextReturnInternalError;
10218 goto finish;
10219 }
10220 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
10221 if (portName == 0 || portName == MACH_PORT_DEAD) {
10222 OSKextLog(/* kext */ NULL,
10223 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10224 "Could not create send right for object.");
10225 result = kOSKextReturnInternalError;
10226 goto finish;
10227 }
10228 // Store the mach port name as a OSNumber
10229 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
10230 if (!portNameNumber) {
10231 OSKextLog(/* kext */ NULL,
10232 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10233 "Could not create OSNumber object.");
10234 result = kOSKextReturnNoMemory;
10235 goto finish;
10236 }
10237 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
10238 OSKextLog(/* kext */ NULL,
10239 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10240 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
10241 result = kOSKextReturnNoMemory;
10242 goto finish;
10243 }
10244 }
10245 finish:
10246 if (result != kOSReturnSuccess) {
10247 break;
10248 }
10249 }
10250 return result;
10251 }
10252
10253 bool
10254 OSKext::iokitDaemonActive()
10255 {
10256 bool result;
10257 IORecursiveLockLock(sKextLock);
10258 result = sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot;
10259 IORecursiveLockUnlock(sKextLock);
10260 return result;
10261 }
10262
10263 /*********************************************************************
10264 * XXX - this function is a big ugly mess
10265 *********************************************************************/
10266 /* static */
10267 OSReturn
10268 OSKext::handleRequest(
10269 host_priv_t hostPriv,
10270 OSKextLogSpec clientLogFilter,
10271 char * requestBuffer,
10272 uint32_t requestLength,
10273 char ** responseOut,
10274 uint32_t * responseLengthOut,
10275 char ** logInfoOut,
10276 uint32_t * logInfoLengthOut)
10277 {
10278 OSReturn result = kOSReturnError;
10279 kern_return_t kmem_result = KERN_FAILURE;
10280
10281 char * response = NULL; // returned by reference
10282 uint32_t responseLength = 0;
10283
10284 bool taskCanManageAllKCs = false;
10285 bool taskOnlyManagesBootKC = false;
10286
10287 OSSharedPtr<OSObject> parsedXML;
10288 OSDictionary * requestDict = NULL; // do not release
10289 OSSharedPtr<OSString> errorString;
10290
10291 OSSharedPtr<OSObject> responseObject;
10292
10293 OSSharedPtr<OSSerialize> serializer;
10294
10295 OSSharedPtr<OSArray> logInfoArray;
10296
10297 OSString * predicate = NULL; // do not release
10298 OSString * kextIdentifier = NULL; // do not release
10299 OSArray * kextIdentifiers = NULL; // do not release
10300 OSKext * theKext = NULL; // do not release
10301 OSBoolean * boolArg = NULL; // do not release
10302
10303
10304 IORecursiveLockLock(sKextLock);
10305
10306 if (responseOut) {
10307 *responseOut = NULL;
10308 *responseLengthOut = 0;
10309 }
10310 if (logInfoOut) {
10311 *logInfoOut = NULL;
10312 *logInfoLengthOut = 0;
10313 }
10314
10315 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
10316
10317 /* XML must be nul-terminated.
10318 */
10319 if (requestBuffer[requestLength - 1] != '\0') {
10320 OSKextLog(/* kext */ NULL,
10321 kOSKextLogErrorLevel |
10322 kOSKextLogIPCFlag,
10323 "Invalid request from user space (not nul-terminated).");
10324 result = kOSKextReturnBadData;
10325 goto finish;
10326 }
10327 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
10328 if (parsedXML) {
10329 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
10330 }
10331 if (!requestDict) {
10332 const char * errorCString = "(unknown error)";
10333
10334 if (errorString && errorString->getCStringNoCopy()) {
10335 errorCString = errorString->getCStringNoCopy();
10336 } else if (parsedXML) {
10337 errorCString = "not a dictionary";
10338 }
10339 OSKextLog(/* kext */ NULL,
10340 kOSKextLogErrorLevel |
10341 kOSKextLogIPCFlag,
10342 "Error unserializing request from user space: %s.",
10343 errorCString);
10344 result = kOSKextReturnSerialization;
10345 goto finish;
10346 }
10347
10348 predicate = _OSKextGetRequestPredicate(requestDict);
10349 if (!predicate) {
10350 OSKextLog(/* kext */ NULL,
10351 kOSKextLogErrorLevel |
10352 kOSKextLogIPCFlag,
10353 "Recieved kext request from user space with no predicate.");
10354 result = kOSKextReturnInvalidArgument;
10355 goto finish;
10356 }
10357 OSKextLog(/* kext */ NULL,
10358 kOSKextLogDebugLevel |
10359 kOSKextLogIPCFlag,
10360 "Received '%s' request from user space.",
10361 predicate->getCStringNoCopy());
10362
10363 /*
10364 * All management of file sets requires an entitlement
10365 */
10366 result = kOSKextReturnNotPrivileged;
10367 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
10368 predicate->isEqualTo(kKextRequestPredicateStart) ||
10369 predicate->isEqualTo(kKextRequestPredicateStop) ||
10370 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10371 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10372 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10373 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10374 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
10375 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10376 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10377 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10378 if (!iokitDaemonAvailable()) {
10379 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
10380 }
10381 if (hostPriv == HOST_PRIV_NULL) {
10382 OSKextLog(/* kext */ NULL,
10383 kOSKextLogErrorLevel |
10384 kOSKextLogIPCFlag,
10385 "Access Failure - must be root user.");
10386 goto finish;
10387 }
10388 taskCanManageAllKCs = IOCurrentTaskHasEntitlement(kOSKextCollectionManagementEntitlement) == TRUE;
10389 taskOnlyManagesBootKC = IOCurrentTaskHasEntitlement(kOSKextOnlyBootKCManagementEntitlement) == TRUE;
10390
10391 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
10392 OSKextLog(/* kext */ NULL,
10393 kOSKextLogErrorLevel |
10394 kOSKextLogIPCFlag,
10395 "Access Failure - client not entitled to manage file sets.");
10396 goto finish;
10397 }
10398
10399 /*
10400 * The OnlyBootKC entitlement restricts the
10401 * collection-management entitlement to only managing kexts in
10402 * the BootKC. All other predicates that alter global state or
10403 * add new KCs are disallowed.
10404 */
10405 if (taskOnlyManagesBootKC &&
10406 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
10407 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
10408 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
10409 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
10410 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
10411 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
10412 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
10413 OSKextLog(/* kext */ NULL,
10414 kOSKextLogErrorLevel |
10415 kOSKextLogIPCFlag,
10416 "Access Failure - client not entitled to manage non-primary KCs");
10417 goto finish;
10418 }
10419
10420 /*
10421 * If we get here, then the process either has the full KC
10422 * management entitlement, or it has the BootKC-only
10423 * entitlement and the request is about the BootKC.
10424 */
10425 }
10426
10427 /* Get common args in anticipation of use.
10428 */
10429 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
10430 requestDict, kKextRequestArgumentBundleIdentifierKey));
10431 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
10432 requestDict, kKextRequestArgumentBundleIdentifierKey));
10433 if (kextIdentifier) {
10434 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
10435 }
10436 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
10437 requestDict, kKextRequestArgumentValueKey));
10438
10439 if (taskOnlyManagesBootKC &&
10440 theKext &&
10441 theKext->isInFileset() &&
10442 theKext->kc_type != KCKindPrimary) {
10443 OSKextLog(/* kext */ NULL,
10444 kOSKextLogErrorLevel |
10445 kOSKextLogIPCFlag,
10446 "Access Failure - client not entitled to manage kext in non-primary KC");
10447 result = kOSKextReturnNotPrivileged;
10448 goto finish;
10449 }
10450 result = kOSKextReturnInvalidArgument;
10451
10452 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
10453 if (!kextIdentifier) {
10454 OSKextLog(/* kext */ NULL,
10455 kOSKextLogErrorLevel |
10456 kOSKextLogIPCFlag,
10457 "Invalid arguments to kext start request.");
10458 } else if (!theKext) {
10459 OSKextLog(/* kext */ NULL,
10460 kOSKextLogErrorLevel |
10461 kOSKextLogIPCFlag,
10462 "Kext %s not found for start request.",
10463 kextIdentifier->getCStringNoCopy());
10464 result = kOSKextReturnNotFound;
10465 } else {
10466 result = theKext->start();
10467 }
10468 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
10469 if (!kextIdentifier) {
10470 OSKextLog(/* kext */ NULL,
10471 kOSKextLogErrorLevel |
10472 kOSKextLogIPCFlag,
10473 "Invalid arguments to kext stop request.");
10474 } else if (!theKext) {
10475 OSKextLog(/* kext */ NULL,
10476 kOSKextLogErrorLevel |
10477 kOSKextLogIPCFlag,
10478 "Kext %s not found for stop request.",
10479 kextIdentifier->getCStringNoCopy());
10480 result = kOSKextReturnNotFound;
10481 } else {
10482 result = theKext->stop();
10483 }
10484 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
10485 result = OSKext::setMissingAuxKCBundles(requestDict);
10486 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
10487 if (!kextIdentifier) {
10488 OSKextLog(/* kext */ NULL,
10489 kOSKextLogErrorLevel |
10490 kOSKextLogIPCFlag,
10491 "Invalid arguments to AuxKC Bundle Available request.");
10492 } else {
10493 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
10494 }
10495 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
10496 if (!kextIdentifier) {
10497 OSKextLog(/* kext */ NULL,
10498 kOSKextLogErrorLevel |
10499 kOSKextLogIPCFlag,
10500 "Invalid arguments to kext load from KC request.");
10501 } else if (!theKext) {
10502 OSKextLog(/* kext */ NULL,
10503 kOSKextLogErrorLevel |
10504 kOSKextLogIPCFlag,
10505 "Kext %s not found for load from KC request.",
10506 kextIdentifier->getCStringNoCopy());
10507 result = kOSKextReturnNotFound;
10508 } else if (!theKext->isInFileset()) {
10509 OSKextLog(/* kext */ NULL,
10510 kOSKextLogErrorLevel |
10511 kOSKextLogIPCFlag,
10512 "Kext %s does not exist in a KC: refusing to load.",
10513 kextIdentifier->getCStringNoCopy());
10514 result = kOSKextReturnNotLoadable;
10515 } else {
10516 result = OSKext::loadKextFromKC(theKext, requestDict);
10517 }
10518 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
10519 if (!kextIdentifier) {
10520 OSKextLog(/* kext */ NULL,
10521 kOSKextLogErrorLevel |
10522 kOSKextLogIPCFlag,
10523 "Invalid arguments to codeless kext load interface (missing identifier).");
10524 } else {
10525 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
10526 }
10527 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
10528 if (!kextIdentifier) {
10529 OSKextLog(/* kext */ NULL,
10530 kOSKextLogErrorLevel |
10531 kOSKextLogIPCFlag,
10532 "Invalid arguments to kext unload request.");
10533 } else if (!theKext) {
10534 OSKextLog(/* kext */ NULL,
10535 kOSKextLogErrorLevel |
10536 kOSKextLogIPCFlag,
10537 "Kext %s not found for unload request.",
10538 kextIdentifier->getCStringNoCopy());
10539 result = kOSKextReturnNotFound;
10540 } else {
10541 if (theKext->isDriverKit()) {
10542 result = OSKext::removeDext(theKext);
10543 } else {
10544 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
10545 _OSKextGetRequestArgument(requestDict,
10546 kKextRequestArgumentTerminateIOServicesKey));
10547 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
10548 }
10549 }
10550 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
10551 result = OSKext::dispatchResource(requestDict);
10552 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
10553 OSNumber *lookupNum = NULL;
10554 lookupNum = OSDynamicCast(OSNumber,
10555 _OSKextGetRequestArgument(requestDict,
10556 kKextRequestArgumentLookupAddressKey));
10557
10558 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
10559 if (responseObject) {
10560 result = kOSReturnSuccess;
10561 } else {
10562 goto finish;
10563 }
10564 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
10565 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
10566 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection) ||
10567 predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10568 OSBoolean * delayAutounloadBool = NULL;
10569 OSObject * infoKeysRaw = NULL;
10570 OSArray * infoKeys = NULL;
10571 uint32_t infoKeysCount = 0;
10572
10573 delayAutounloadBool = OSDynamicCast(OSBoolean,
10574 _OSKextGetRequestArgument(requestDict,
10575 kKextRequestArgumentDelayAutounloadKey));
10576
10577 /* If asked to delay autounload, reset the timer if it's currently set.
10578 * (That is, don't schedule an unload if one isn't already pending.
10579 */
10580 if (delayAutounloadBool == kOSBooleanTrue) {
10581 OSKext::considerUnloads(/* rescheduleOnly? */ true);
10582 }
10583
10584 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
10585 kKextRequestArgumentInfoKeysKey);
10586 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
10587 if (infoKeysRaw && !infoKeys) {
10588 OSKextLog(/* kext */ NULL,
10589 kOSKextLogErrorLevel |
10590 kOSKextLogIPCFlag,
10591 "Invalid arguments to kext info request.");
10592 goto finish;
10593 }
10594
10595 if (infoKeys) {
10596 infoKeysCount = infoKeys->getCount();
10597 for (uint32_t i = 0; i < infoKeysCount; i++) {
10598 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
10599 OSKextLog(/* kext */ NULL,
10600 kOSKextLogErrorLevel |
10601 kOSKextLogIPCFlag,
10602 "Invalid arguments to kext info request.");
10603 goto finish;
10604 }
10605 }
10606 }
10607
10608 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
10609 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
10610 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
10611 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
10612 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
10613 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
10614 } else if (predicate->isEqualTo(kKextRequestPredicateGetDexts)) {
10615 responseObject = OSKext::copyDextsInfo(kextIdentifiers, infoKeys);
10616 }
10617
10618 if (!responseObject) {
10619 result = kOSKextReturnInternalError;
10620 } else {
10621 OSKextLog(/* kext */ NULL,
10622 kOSKextLogDebugLevel |
10623 kOSKextLogIPCFlag,
10624 "Returning loaded kext info.");
10625 result = kOSReturnSuccess;
10626 }
10627 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10628 /* Hand the current sKernelRequests array to the caller
10629 * (who must release it), and make a new one.
10630 */
10631 responseObject = os::move(sKernelRequests);
10632 sKernelRequests = OSArray::withCapacity(0);
10633 sPostedKextLoadIdentifiers->flushCollection();
10634 OSKextLog(/* kext */ NULL,
10635 kOSKextLogDebugLevel |
10636 kOSKextLogIPCFlag,
10637 "Returning kernel requests.");
10638 result = kOSReturnSuccess;
10639 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
10640 /* Return the set of all requested bundle identifiers */
10641 responseObject = sAllKextLoadIdentifiers;
10642 OSKextLog(/* kext */ NULL,
10643 kOSKextLogDebugLevel |
10644 kOSKextLogIPCFlag,
10645 "Returning load requests.");
10646 result = kOSReturnSuccess;
10647 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
10648 printf("KextLog: Loading FileSet KC(s)\n");
10649 result = OSKext::loadFileSetKexts(requestDict);
10650 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
10651 bool active = iokitDaemonActive();
10652 printf("KextLog: " kIOKitDaemonName " is %s\n", active ? "active" : "not active");
10653 if (sOSKextWasResetAfterUserspaceReboot) {
10654 printf("KextLog: was reset after userspace reboot\n");
10655 }
10656 result = active ? kOSReturnSuccess : kIOReturnNotReady;
10657 } else {
10658 OSKextLog(/* kext */ NULL,
10659 kOSKextLogDebugLevel |
10660 kOSKextLogIPCFlag,
10661 "Received '%s' invalid request from user space.",
10662 predicate->getCStringNoCopy());
10663 goto finish;
10664 }
10665
10666 /**********
10667 * Now we have handle the request, or not. Gather up the response & logging
10668 * info to ship to user space.
10669 *********/
10670
10671 /* Note: Nothing in OSKext is supposed to retain requestDict,
10672 * but you never know....
10673 */
10674 if (requestDict->getRetainCount() > 1) {
10675 OSKextLog(/* kext */ NULL,
10676 kOSKextLogWarningLevel |
10677 kOSKextLogIPCFlag,
10678 "Request from user space still retained by a kext; "
10679 "probable memory leak.");
10680 }
10681
10682 if (responseOut && responseObject) {
10683 serializer = OSSerialize::withCapacity(0);
10684 if (!serializer) {
10685 result = kOSKextReturnNoMemory;
10686 goto finish;
10687 }
10688 /*
10689 * Before serializing the kernel requests, patch the dext launch requests so
10690 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
10691 * IOUserServerCheckInToken kernel object.
10692 */
10693 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
10694 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
10695 task_t calling_task = current_task();
10696 if (!requests) {
10697 OSKextLog(/* kext */ NULL,
10698 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10699 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
10700 result = kOSKextReturnInternalError;
10701 goto finish;
10702 }
10703 result = patchDextLaunchRequests(calling_task, requests);
10704 if (result != kOSReturnSuccess) {
10705 OSKextLog(/* kext */ NULL,
10706 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10707 "Failed to patch dext launch requests.");
10708 goto finish;
10709 }
10710 }
10711
10712 if (!responseObject->serialize(serializer.get())) {
10713 OSKextLog(/* kext */ NULL,
10714 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
10715 "Failed to serialize response to request from user space.");
10716 result = kOSKextReturnSerialization;
10717 goto finish;
10718 }
10719
10720 response = (char *)serializer->text();
10721 responseLength = serializer->getLength();
10722 }
10723
10724 if (responseOut && response) {
10725 char * buffer;
10726
10727 /* This kmem_alloc sets the return value of the function.
10728 */
10729 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
10730 round_page(responseLength), KMA_DATA, VM_KERN_MEMORY_OSKEXT);
10731 if (kmem_result != KERN_SUCCESS) {
10732 OSKextLog(/* kext */ NULL,
10733 kOSKextLogErrorLevel |
10734 kOSKextLogIPCFlag,
10735 "Failed to copy response to request from user space.");
10736 result = kmem_result;
10737 goto finish;
10738 } else {
10739 /* 11981737 - clear uninitialized data in last page */
10740 bzero((void *)(buffer + responseLength),
10741 (round_page(responseLength) - responseLength));
10742 memcpy(buffer, response, responseLength);
10743 *responseOut = buffer;
10744 *responseLengthOut = responseLength;
10745 }
10746 }
10747
10748 finish:
10749
10750 /* Gather up the collected log messages for user space. Any messages
10751 * messages past this call will not make it up as log messages but
10752 * will be in the system log. Note that we ignore the return of the
10753 * serialize; it has no bearing on the operation at hand even if we
10754 * fail to get the log messages.
10755 */
10756 logInfoArray = OSKext::clearUserSpaceLogFilter();
10757
10758 if (logInfoArray && logInfoOut && logInfoLengthOut) {
10759 (void)OSKext::serializeLogInfo(logInfoArray.get(),
10760 logInfoOut, logInfoLengthOut);
10761 }
10762
10763 IORecursiveLockUnlock(sKextLock);
10764
10765 return result;
10766 }
10767
10768 #if PRAGMA_MARK
10769 #pragma mark Linked Kext Collection Support
10770 #endif
10771
10772 static int
10773 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
10774 {
10775 for (int i = 0; i < segCount; i++) {
10776 vm_offset_t segStart = segAddrs[i];
10777 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
10778
10779 if (theAddr >= segStart && theAddr < segEnd) {
10780 return i;
10781 }
10782 }
10783 return -1;
10784 }
10785
10786 static void
10787 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
10788 kernel_segment_command_t *kextTextSeg,
10789 OSData *kaslrOffsets)
10790 {
10791 static const char *plk_segNames[] = {
10792 "__TEXT",
10793 "__TEXT_EXEC",
10794 "__DATA",
10795 "__DATA_CONST",
10796 "__LINKEDIT",
10797 "__PRELINK_TEXT",
10798 "__PLK_TEXT_EXEC",
10799 "__PRELINK_DATA",
10800 "__PLK_DATA_CONST",
10801 "__PLK_LLVM_COV",
10802 "__PLK_LINKEDIT",
10803 "__PRELINK_INFO"
10804 };
10805 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
10806
10807 unsigned long plk_segSizes[num_plk_seg];
10808 vm_offset_t plk_segAddrs[num_plk_seg];
10809
10810 for (size_t i = 0; i < num_plk_seg; i++) {
10811 plk_segSizes[i] = 0;
10812 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
10813 }
10814
10815 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
10816
10817 int slidKextAddrCount = 0;
10818 int badSlideAddr = 0;
10819 int badSlideTarget = 0;
10820
10821 struct kaslrPackedOffsets {
10822 uint32_t count; /* number of offsets */
10823 uint32_t offsetsArray[]; /* offsets to slide */
10824 };
10825 const struct kaslrPackedOffsets *myOffsets = NULL;
10826 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
10827
10828 for (uint32_t j = 0; j < myOffsets->count; j++) {
10829 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
10830 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
10831 int slideAddrSegIndex = -1;
10832 int addrToSlideSegIndex = -1;
10833
10834 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10835 if (slideAddrSegIndex >= 0) {
10836 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
10837 if (addrToSlideSegIndex < 0) {
10838 badSlideTarget++;
10839 continue;
10840 }
10841 } else {
10842 badSlideAddr++;
10843 continue;
10844 }
10845
10846 slidKextAddrCount++;
10847 *slideAddr = ml_static_slide(*slideAddr);
10848 } // for ...
10849 }
10850
10851
10852
10853 /********************************************************************
10854 * addKextsFromKextCollection
10855 *
10856 * Input: MachO header of kext collection. The MachO is assumed to
10857 * have a section named 'info_seg_name,info_sect_name' that
10858 * contains a serialized XML info dictionary. This dictionary
10859 * contains a UUID, possibly a set of relocations (for older
10860 * kxld-built binaries), and an array of kext personalities.
10861 *
10862 ********************************************************************/
10863 bool
10864 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10865 OSDictionary *infoDict, const char *text_seg_name,
10866 OSData **kcUUID, kc_kind_t type)
10867 {
10868 bool result = false;
10869
10870 OSArray *kextArray = NULL; // do not release
10871 OSData *infoDictKCUUID = NULL; // do not release
10872 OSData *kaslrOffsets = NULL; // do not release
10873
10874 IORegistryEntry *registryRoot = NULL; // do not release
10875 OSSharedPtr<OSNumber> kcKextCount;
10876
10877 /* extract the KC UUID from the dictionary */
10878 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10879 if (infoDictKCUUID) {
10880 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
10881 panic("kcUUID length is %d, expected %lu",
10882 infoDictKCUUID->getLength(), sizeof(uuid_t));
10883 }
10884 }
10885
10886 /* locate the array of kext dictionaries */
10887 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
10888 if (!kextArray) {
10889 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10890 "The given KC has no kext info dictionaries");
10891 goto finish;
10892 }
10893
10894 /*
10895 * old-style KASLR offsets may be present in the info dictionary. If
10896 * we find them, use them and eventually slide them.
10897 */
10898 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
10899
10900 /*
10901 * Before processing any kexts, locate the special kext bundle which
10902 * contains a list of kexts that we are to prevent from loading.
10903 */
10904 createExcludeListFromPrelinkInfo(kextArray);
10905
10906 /*
10907 * Create OSKext objects for each kext we find in the array of kext
10908 * info plist dictionaries.
10909 */
10910 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
10911 OSDictionary *kextDict = NULL;
10912 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
10913 if (!kextDict) {
10914 OSKextLog(/* kext */ NULL,
10915 kOSKextLogErrorLevel |
10916 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10917 "Kext info dictionary for kext #%d isn't a dictionary?", i);
10918 continue;
10919 }
10920
10921 /*
10922 * Create the kext for the entry, then release it, because the
10923 * kext system keeps a reference around until the kext is
10924 * explicitly removed. Any creation/registration failures are
10925 * already logged for us.
10926 */
10927 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
10928 }
10929
10930 /*
10931 * slide old-style kxld relocations
10932 * NOTE: this is still used on embedded KCs built with kcgen
10933 * TODO: Remove this once we use the new kext linker everywhere!
10934 */
10935 if (kaslrOffsets && vm_kernel_slide > 0) {
10936 kernel_segment_command_t *text_segment = NULL;
10937 text_segment = getsegbynamefromheader(mh, text_seg_name);
10938 if (!text_segment) {
10939 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10940 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
10941 goto finish;
10942 }
10943
10944 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
10945 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
10946 setAllVMAttributes();
10947 }
10948
10949 /* Store the number of prelinked kexts in the registry so we can tell
10950 * when the system has been started from a prelinked kernel.
10951 */
10952 registryRoot = IORegistryEntry::getRegistryRoot();
10953 assert(registryRoot);
10954
10955 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
10956 assert(kcKextCount);
10957 if (kcKextCount) {
10958 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
10959 OSNumber *num;
10960 num = OSDynamicCast(OSNumber, prop.get());
10961 if (num) {
10962 kcKextCount->addValue(num->unsigned64BitValue());
10963 }
10964 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
10965 }
10966
10967 OSKextLog(/* kext */ NULL,
10968 kOSKextLogProgressLevel |
10969 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
10970 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
10971 "%u prelinked kexts", infoDict->getCount());
10972
10973
10974 if (kcUUID && infoDictKCUUID) {
10975 *kcUUID = OSData::withData(infoDictKCUUID).detach();
10976 }
10977
10978 result = true;
10979
10980 finish:
10981 return result;
10982 }
10983
10984 bool
10985 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
10986 OSDictionary *infoDict, const char *text_seg_name,
10987 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
10988 {
10989 OSData *result = NULL;
10990 bool success = addKextsFromKextCollection(mh,
10991 infoDict,
10992 text_seg_name,
10993 &result,
10994 type);
10995 if (success) {
10996 kcUUID.reset(result, OSNoRetain);
10997 }
10998 return success;
10999 }
11000
11001 static OSSharedPtr<OSObject> deferredAuxKCXML;
11002 bool
11003 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
11004 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
11005 {
11006 if (type != KCKindAuxiliary) {
11007 return false;
11008 }
11009
11010 kernel_mach_header_t *_mh;
11011 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
11012 if (!_mh || _mh != mh) {
11013 return false;
11014 }
11015
11016 if (deferredAuxKCXML) {
11017 /* only allow this to be called once */
11018 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11019 "An Aux KC has already been registered for deferred processing.");
11020 return false;
11021 }
11022
11023 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11024 if (!infoDict) {
11025 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11026 "The Aux KC has info dictionary");
11027 return false;
11028 }
11029
11030 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
11031 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
11032 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11033 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
11034 return false;
11035 }
11036
11037 /*
11038 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
11039 * sysctl can return the UUID to user space which will check this
11040 * value for errors.
11041 */
11042 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
11043 kcUUID->getLength());
11044 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
11045 auxkc_uuid_valid = TRUE;
11046
11047 deferredAuxKCXML = parsedXML;
11048
11049 return true;
11050 }
11051
11052 OSSharedPtr<OSObject>
11053 OSKext::consumeDeferredKextCollection(kc_kind_t type)
11054 {
11055 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
11056 return NULL;
11057 }
11058
11059 return os::move(deferredAuxKCXML);
11060 }
11061
11062 #if PRAGMA_MARK
11063 #pragma mark Profile-Guided-Optimization Support
11064 #endif
11065
11066 // #include <InstrProfiling.h>
11067 extern "C" {
11068 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
11069 const char *DataEnd,
11070 const char *CountersBegin,
11071 const char *CountersEnd,
11072 const char *NamesBegin,
11073 const char *NamesEnd);
11074 int __llvm_profile_write_buffer_internal(char *Buffer,
11075 const char *DataBegin,
11076 const char *DataEnd,
11077 const char *CountersBegin,
11078 const char *CountersEnd,
11079 const char *NamesBegin,
11080 const char *NamesEnd);
11081 }
11082
11083
11084 static
11085 void
11086 OSKextPgoMetadataPut(char *pBuffer,
11087 size_t *position,
11088 size_t bufferSize,
11089 uint32_t *num_pairs,
11090 const char *key,
11091 const char *value)
11092 {
11093 size_t strlen_key = strlen(key);
11094 size_t strlen_value = strlen(value);
11095 size_t len = strlen(key) + 1 + strlen(value) + 1;
11096 char *pos = pBuffer + *position;
11097 *position += len;
11098 if (pBuffer && bufferSize && *position <= bufferSize) {
11099 memcpy(pos, key, strlen_key); pos += strlen_key;
11100 *(pos++) = '=';
11101 memcpy(pos, value, strlen_value); pos += strlen_value;
11102 *(pos++) = 0;
11103 if (num_pairs) {
11104 (*num_pairs)++;
11105 }
11106 }
11107 }
11108
11109
11110 static
11111 void
11112 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
11113 {
11114 *position += strlen(key) + 1 + value_max + 1;
11115 }
11116
11117
11118 static
11119 void
11120 OSKextPgoMetadataPutAll(OSKext *kext,
11121 uuid_t instance_uuid,
11122 char *pBuffer,
11123 size_t *position,
11124 size_t bufferSize,
11125 uint32_t *num_pairs)
11126 {
11127 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
11128 //log_10 2^16 ≈ 4.82
11129 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
11130 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
11131
11132 if (!pBuffer) {
11133 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
11134 OSKextPgoMetadataPutMax(position, "UUID", 36);
11135 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
11136 } else {
11137 uuid_string_t instance_uuid_string;
11138 uuid_unparse(instance_uuid, instance_uuid_string);
11139 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11140 "INSTANCE", instance_uuid_string);
11141
11142 OSSharedPtr<OSData> uuid_data;
11143 uuid_t uuid;
11144 uuid_string_t uuid_string;
11145 uuid_data = kext->copyUUID();
11146 if (uuid_data) {
11147 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
11148 uuid_unparse(uuid, uuid_string);
11149 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11150 "UUID", uuid_string);
11151 }
11152
11153 clock_sec_t secs;
11154 clock_usec_t usecs;
11155 clock_get_calendar_microtime(&secs, &usecs);
11156 assert(usecs < 1000000);
11157 char timestamp[max_timestamp_string_size + 1];
11158 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
11159 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
11160 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11161 "TIMESTAMP", timestamp);
11162 }
11163
11164 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11165 "NAME", kext->getIdentifierCString());
11166
11167 char versionCString[kOSKextVersionMaxLength];
11168 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
11169 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
11170 "VERSION", versionCString);
11171 }
11172
11173 static
11174 size_t
11175 OSKextPgoMetadataSize(OSKext *kext)
11176 {
11177 size_t position = 0;
11178 uuid_t fakeuuid = {};
11179 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
11180 return position;
11181 }
11182
11183 int
11184 OSKextGrabPgoDataLocked(OSKext *kext,
11185 bool metadata,
11186 uuid_t instance_uuid,
11187 uint64_t *pSize,
11188 char *pBuffer,
11189 uint64_t bufferSize)
11190 {
11191 int err = 0;
11192
11193 kernel_section_t *sect_prf_data = NULL;
11194 kernel_section_t *sect_prf_name = NULL;
11195 kernel_section_t *sect_prf_cnts = NULL;
11196 uint64_t size;
11197 size_t metadata_size = 0;
11198 size_t offset_to_pairs = 0;
11199
11200 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
11201 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
11202 if (!sect_prf_name) {
11203 // kextcache sometimes truncates the section name to 15 chars
11204 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
11205 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
11206 }
11207 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11208
11209 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
11210 err = ENOTSUP;
11211 goto out;
11212 }
11213
11214 size = __llvm_profile_get_size_for_buffer_internal(
11215 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11216 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11217 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11218
11219 if (metadata) {
11220 metadata_size = OSKextPgoMetadataSize(kext);
11221 size += metadata_size;
11222 size += sizeof(pgo_metadata_footer);
11223 }
11224
11225
11226 if (pSize) {
11227 *pSize = size;
11228 }
11229
11230 if (pBuffer && bufferSize) {
11231 if (bufferSize < size) {
11232 err = ERANGE;
11233 goto out;
11234 }
11235
11236 err = __llvm_profile_write_buffer_internal(
11237 pBuffer,
11238 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
11239 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
11240 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
11241
11242 if (err) {
11243 err = EIO;
11244 goto out;
11245 }
11246
11247 if (metadata) {
11248 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
11249 if (offset_to_pairs > UINT32_MAX) {
11250 err = E2BIG;
11251 goto out;
11252 }
11253
11254 char *end_of_buffer = pBuffer + size;
11255 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
11256 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
11257
11258 size_t metadata_position = 0;
11259 uint32_t num_pairs = 0;
11260 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
11261 while (metadata_position < metadata_size) {
11262 metadata_buffer[metadata_position++] = 0;
11263 }
11264
11265 struct pgo_metadata_footer footer;
11266 footer.magic = htonl(0x6d657461);
11267 footer.number_of_pairs = htonl( num_pairs );
11268 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
11269 memcpy(footerp, &footer, sizeof(footer));
11270 }
11271 }
11272
11273 out:
11274 return err;
11275 }
11276
11277
11278 int
11279 OSKextGrabPgoData(uuid_t uuid,
11280 uint64_t *pSize,
11281 char *pBuffer,
11282 uint64_t bufferSize,
11283 int wait_for_unload,
11284 int metadata)
11285 {
11286 int err = 0;
11287 OSSharedPtr<OSKext> kext;
11288
11289
11290 IORecursiveLockLock(sKextLock);
11291
11292 kext = OSKext::lookupKextWithUUID(uuid);
11293 if (!kext) {
11294 err = ENOENT;
11295 goto out;
11296 }
11297
11298 if (wait_for_unload) {
11299 OSKextGrabPgoStruct s;
11300
11301 s.metadata = metadata;
11302 s.pSize = pSize;
11303 s.pBuffer = pBuffer;
11304 s.bufferSize = bufferSize;
11305 s.err = EINTR;
11306
11307 struct list_head *prev = &kext->pendingPgoHead;
11308 struct list_head *next = kext->pendingPgoHead.next;
11309
11310 s.list_head.prev = prev;
11311 s.list_head.next = next;
11312
11313 prev->next = &s.list_head;
11314 next->prev = &s.list_head;
11315
11316 kext.reset();
11317
11318 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
11319
11320 prev = s.list_head.prev;
11321 next = s.list_head.next;
11322
11323 prev->next = next;
11324 next->prev = prev;
11325
11326 err = s.err;
11327 } else {
11328 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
11329 }
11330
11331 out:
11332
11333 IORecursiveLockUnlock(sKextLock);
11334
11335 return err;
11336 }
11337
11338 void
11339 OSKextResetPgoCountersLock()
11340 {
11341 IORecursiveLockLock(sKextLock);
11342 }
11343
11344 void
11345 OSKextResetPgoCountersUnlock()
11346 {
11347 IORecursiveLockUnlock(sKextLock);
11348 }
11349
11350
11351 extern unsigned int not_in_kdp;
11352
11353 void
11354 OSKextResetPgoCounters()
11355 {
11356 assert(!not_in_kdp);
11357 uint32_t count = sLoadedKexts->getCount();
11358 for (uint32_t i = 0; i < count; i++) {
11359 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
11360 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
11361 if (!sect_prf_cnts) {
11362 continue;
11363 }
11364 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
11365 }
11366 }
11367
11368 OSSharedPtr<OSDictionary>
11369 OSKext::copyLoadedKextInfoByUUID(
11370 OSArray * kextIdentifiers,
11371 OSArray * infoKeys)
11372 {
11373 OSSharedPtr<OSDictionary> result;
11374 OSSharedPtr<OSDictionary> kextInfo;
11375 uint32_t max_count, i, j;
11376 uint32_t idCount = 0;
11377 uint32_t idIndex = 0;
11378 IORecursiveLockLock(sKextLock);
11379 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
11380 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
11381
11382 #if CONFIG_MACF
11383 /* Is the calling process allowed to query kext info? */
11384 if (current_task() != kernel_task) {
11385 int macCheckResult = 0;
11386 kauth_cred_t cred = NULL;
11387
11388 cred = kauth_cred_get_with_ref();
11389 macCheckResult = mac_kext_check_query(cred);
11390 kauth_cred_unref(&cred);
11391
11392 if (macCheckResult != 0) {
11393 OSKextLog(/* kext */ NULL,
11394 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11395 "Failed to query kext info (MAC policy error 0x%x).",
11396 macCheckResult);
11397 goto finish;
11398 }
11399 }
11400 #endif
11401
11402 /* Empty list of UUIDs is equivalent to no list (get all).
11403 */
11404 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11405 kextIdentifiers = NULL;
11406 } else if (kextIdentifiers) {
11407 idCount = kextIdentifiers->getCount();
11408 }
11409
11410 /* Same for keys.
11411 */
11412 if (infoKeys && !infoKeys->getCount()) {
11413 infoKeys = NULL;
11414 }
11415
11416 max_count = count[0] + count[1];
11417 result = OSDictionary::withCapacity(max_count);
11418 if (!result) {
11419 goto finish;
11420 }
11421
11422 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
11423 for (i = 0; i < count[j]; i++) {
11424 OSKext *thisKext = NULL; // do not release
11425 Boolean includeThis = true;
11426 uuid_t thisKextUUID;
11427 uuid_t thisKextTextUUID;
11428 OSSharedPtr<OSData> uuid_data;
11429 uuid_string_t uuid_key;
11430
11431 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
11432 if (!thisKext) {
11433 continue;
11434 }
11435
11436 uuid_data = thisKext->copyUUID();
11437 if (!uuid_data) {
11438 continue;
11439 }
11440
11441 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
11442
11443 uuid_unparse(thisKextUUID, uuid_key);
11444
11445 uuid_data = thisKext->copyTextUUID();
11446 if (!uuid_data) {
11447 continue;
11448 }
11449 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
11450
11451 /* Skip current kext if we have a list of UUIDs and
11452 * it isn't in the list.
11453 */
11454 if (kextIdentifiers) {
11455 includeThis = false;
11456
11457 for (idIndex = 0; idIndex < idCount; idIndex++) {
11458 const OSString* wantedUUID = OSDynamicCast(OSString,
11459 kextIdentifiers->getObject(idIndex));
11460
11461 uuid_t uuid;
11462 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
11463
11464 if ((0 == uuid_compare(uuid, thisKextUUID))
11465 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
11466 includeThis = true;
11467 /* Only need to find the first kext if multiple match,
11468 * ie. asking for the kernel uuid does not need to find
11469 * interface kexts or builtin static kexts.
11470 */
11471 kextIdentifiers->removeObject(idIndex);
11472 uuid_unparse(uuid, uuid_key);
11473 break;
11474 }
11475 }
11476 }
11477
11478 if (!includeThis) {
11479 continue;
11480 }
11481
11482 kextInfo = thisKext->copyInfo(infoKeys);
11483 if (kextInfo) {
11484 result->setObject(uuid_key, kextInfo.get());
11485 }
11486
11487 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11488 goto finish;
11489 }
11490 }
11491 }
11492
11493 finish:
11494 IORecursiveLockUnlock(sKextLock);
11495
11496 return result;
11497 }
11498
11499 /*********************************************************************
11500 *********************************************************************/
11501 /* static */
11502 OSSharedPtr<OSDictionary>
11503 OSKext::copyKextCollectionInfo(
11504 OSDictionary *requestDict,
11505 OSArray *infoKeys)
11506 {
11507 OSSharedPtr<OSDictionary> result;
11508 OSString *collectionType = NULL;
11509 OSObject *rawLoadedState = NULL;
11510 OSString *loadedState = NULL;
11511
11512 kc_kind_t kc_request_kind = KCKindUnknown;
11513 bool onlyLoaded = false;
11514 bool onlyUnloaded = false;
11515
11516 #if CONFIG_MACF
11517 /* Is the calling process allowed to query kext info? */
11518 if (current_task() != kernel_task) {
11519 int macCheckResult = 0;
11520 kauth_cred_t cred = NULL;
11521
11522 cred = kauth_cred_get_with_ref();
11523 macCheckResult = mac_kext_check_query(cred);
11524 kauth_cred_unref(&cred);
11525
11526 if (macCheckResult != 0) {
11527 OSKextLog(/* kext */ NULL,
11528 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11529 "Failed to query kext info (MAC policy error 0x%x).",
11530 macCheckResult);
11531 goto finish;
11532 }
11533 }
11534 #endif
11535
11536 if (infoKeys && !infoKeys->getCount()) {
11537 infoKeys = NULL;
11538 }
11539
11540 collectionType = OSDynamicCast(OSString,
11541 _OSKextGetRequestArgument(requestDict,
11542 kKextRequestArgumentCollectionTypeKey));
11543 if (!collectionType) {
11544 OSKextLog(/* kext */ NULL,
11545 kOSKextLogErrorLevel |
11546 kOSKextLogIPCFlag,
11547 "Invalid '%s' argument to kext collection info request.",
11548 kKextRequestArgumentCollectionTypeKey);
11549 goto finish;
11550 }
11551 if (collectionType->isEqualTo(kKCTypePrimary)) {
11552 kc_request_kind = KCKindPrimary;
11553 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
11554 kc_request_kind = KCKindPageable;
11555 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
11556 kc_request_kind = KCKindAuxiliary;
11557 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
11558 kc_request_kind = KCKindNone;
11559 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
11560 OSKextLog(/* kext */ NULL,
11561 kOSKextLogErrorLevel |
11562 kOSKextLogIPCFlag,
11563 "Invalid '%s' argument value '%s' to kext collection info request.",
11564 kKextRequestArgumentCollectionTypeKey,
11565 collectionType->getCStringNoCopy());
11566 goto finish;
11567 }
11568
11569 rawLoadedState = _OSKextGetRequestArgument(requestDict,
11570 kKextRequestArgumentLoadedStateKey);
11571 if (rawLoadedState) {
11572 loadedState = OSDynamicCast(OSString, rawLoadedState);
11573 if (!loadedState) {
11574 OSKextLog(/* kext */ NULL,
11575 kOSKextLogErrorLevel |
11576 kOSKextLogIPCFlag,
11577 "Invalid '%s' argument to kext collection info request.",
11578 kKextRequestArgumentLoadedStateKey);
11579 goto finish;
11580 }
11581 }
11582 if (loadedState) {
11583 if (loadedState->isEqualTo("Loaded")) {
11584 onlyLoaded = true;
11585 } else if (loadedState->isEqualTo("Unloaded")) {
11586 onlyUnloaded = true;
11587 } else if (!loadedState->isEqualTo("Any")) {
11588 OSKextLog(/* kext */ NULL,
11589 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11590 "Invalid '%s' argument value '%s' for '%s' collection info",
11591 kKextRequestArgumentLoadedStateKey,
11592 loadedState->getCStringNoCopy(),
11593 collectionType->getCStringNoCopy());
11594 goto finish;
11595 }
11596 }
11597
11598 result = OSDictionary::withCapacity(sKextsByID->getCount());
11599 if (!result) {
11600 goto finish;
11601 }
11602
11603 IORecursiveLockLock(sKextLock);
11604 { // start block scope
11605 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11606 {
11607 OSKext *thisKext = NULL; // do not release
11608 OSSharedPtr<OSDictionary> kextInfo;
11609
11610 (void)thisKextID;
11611
11612 thisKext = OSDynamicCast(OSKext, obj);
11613 if (!thisKext) {
11614 return false;
11615 }
11616
11617 /*
11618 * skip the kext if it came from the wrong collection type
11619 * (and the caller requested a specific type)
11620 */
11621 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
11622 return false;
11623 }
11624
11625 /*
11626 * respect the caller's desire to find only loaded or
11627 * unloaded kexts
11628 */
11629 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11630 return false;
11631 }
11632 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11633 return false;
11634 }
11635
11636 kextInfo = thisKext->copyInfo(infoKeys);
11637 if (kextInfo) {
11638 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11639 }
11640 return false;
11641 });
11642 } // end block scope
11643 IORecursiveLockUnlock(sKextLock);
11644
11645 finish:
11646 return result;
11647 }
11648
11649 /* static */
11650 OSSharedPtr<OSArray>
11651 OSKext::copyDextsInfo(
11652 OSArray *kextIdentifiers,
11653 OSArray *infoKeys)
11654 {
11655 OSSharedPtr<OSArray> result = NULL;
11656 uint32_t idCount = 0;
11657 bool getActive = false;
11658 bool getLoaded = false;
11659 bool getUnloaded = false;
11660 bool getPendingUpgrade = false;
11661 unsigned int avgDextCount = 0;
11662
11663 #if CONFIG_MACF
11664 /* Is the calling process allowed to query dext info? */
11665 if (current_task() != kernel_task) {
11666 int macCheckResult = 0;
11667 kauth_cred_t cred = NULL;
11668
11669 cred = kauth_cred_get_with_ref();
11670 macCheckResult = mac_kext_check_query(cred);
11671 kauth_cred_unref(&cred);
11672
11673 if (macCheckResult != 0) {
11674 OSKextLog(/* kext */ NULL,
11675 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11676 "Failed to query kext info (MAC policy error 0x%x).",
11677 macCheckResult);
11678 goto finish;
11679 }
11680 }
11681 #endif
11682 /*
11683 * No infoKeys means return everything we
11684 * know about the dexts.
11685 */
11686 if (infoKeys && !infoKeys->getCount()) {
11687 infoKeys = NULL;
11688 }
11689
11690 /*
11691 * Empty list of bundle ids is equivalent to
11692 * no list (get all).
11693 */
11694 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11695 kextIdentifiers = NULL;
11696 } else if (kextIdentifiers) {
11697 idCount = kextIdentifiers->getCount();
11698 }
11699
11700 /*
11701 * Caller can specify which state of dexts to query.
11702 */
11703 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveKey)) {
11704 getActive = true;
11705 }
11706 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveLoadedKey)) {
11707 getLoaded = true;
11708 }
11709 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStateActiveUnloadedKey)) {
11710 getUnloaded = true;
11711 }
11712 if (infoKeys && _OSArrayContainsCString(infoKeys, kOSBundleDextStatePendingUpgradeKey)) {
11713 getPendingUpgrade = true;
11714 }
11715
11716 /*
11717 * By default we are going to return all active and pendingUpgrade dexts
11718 * only.
11719 */
11720 if (!(getActive || getLoaded || getUnloaded || getPendingUpgrade)) {
11721 getActive = true;
11722 getPendingUpgrade = true;
11723 }
11724
11725 /*
11726 * We return a dictionary of dexts
11727 * for every group requested.
11728 */
11729 avgDextCount = sLoadedDriverKitKexts->getCount() + sDriverKitToUpgradeByID->getCount();
11730 result = OSArray::withCapacity(avgDextCount);
11731 if (!result) {
11732 goto finish;
11733 }
11734
11735 IORecursiveLockLock(sKextLock);
11736 { // start block scope
11737 if (getActive || getLoaded || getUnloaded) {
11738 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11739 {
11740 OSKext *thisKext = NULL; // do not release
11741 OSSharedPtr<OSDictionary> kextInfo;
11742 Boolean includeThis = true;
11743 (void)thisKextID;
11744
11745 thisKext = OSDynamicCast(OSKext, obj);
11746 if (!thisKext || !thisKext->isDriverKit()) {
11747 return false;
11748 }
11749
11750 /*
11751 * Skip current dext if we have a list of bundle IDs and
11752 * it isn't in the list.
11753 */
11754 if (kextIdentifiers) {
11755 includeThis = false;
11756
11757 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11758 const OSString * thisRequestID = OSDynamicCast(OSString,
11759 kextIdentifiers->getObject(idIndex));
11760 if (thisKextID->isEqualTo(thisRequestID)) {
11761 includeThis = true;
11762 break;
11763 }
11764 }
11765 }
11766
11767 if (!includeThis) {
11768 return false;
11769 }
11770
11771 OSSharedPtr<OSString> state;
11772 if (sLoadedDriverKitKexts->getNextIndexOfObject(thisKext, 0) == -1U) {
11773 if (!(getActive || getUnloaded)) {
11774 return false;
11775 }
11776 state = OSString::withCString(kOSBundleDextStateActiveUnloadedKey);
11777 } else {
11778 if (!(getActive || getLoaded)) {
11779 return false;
11780 }
11781 state = OSString::withCString(kOSBundleDextStateActiveLoadedKey);
11782 }
11783
11784 kextInfo = thisKext->copyInfo(infoKeys);
11785 if (kextInfo) {
11786 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11787 result->setObject(kextInfo.get());
11788 }
11789
11790 return false;
11791 });
11792 }
11793
11794 if (getPendingUpgrade) {
11795 sDriverKitToUpgradeByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
11796 {
11797 OSKext *thisKext = NULL; // do not release
11798 OSSharedPtr<OSDictionary> kextInfo;
11799 Boolean includeThis = true;
11800 (void)thisKextID;
11801
11802 thisKext = OSDynamicCast(OSKext, obj);
11803 if (!thisKext) {
11804 return false;
11805 }
11806 __assert_only bool isDext = thisKext->isDriverKit();
11807 assert(isDext == true);
11808
11809 /*
11810 * Skip current dext if we have a list of bundle IDs and
11811 * it isn't in the list.
11812 */
11813 if (kextIdentifiers) {
11814 includeThis = false;
11815
11816 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11817 const OSString * thisRequestID = OSDynamicCast(OSString,
11818 kextIdentifiers->getObject(idIndex));
11819 if (thisKextID->isEqualTo(thisRequestID)) {
11820 includeThis = true;
11821 break;
11822 }
11823 }
11824 }
11825
11826 if (!includeThis) {
11827 return false;
11828 }
11829
11830 kextInfo = thisKext->copyInfo(infoKeys);
11831 if (kextInfo) {
11832 OSSharedPtr<OSString> state = OSString::withCString(kOSBundleDextStatePendingUpgradeKey);
11833 kextInfo->setObject(kOSBundleDextStateKey, state.get());
11834 result->setObject(kextInfo.get());
11835 }
11836 return false;
11837 });
11838 }
11839 } // end block scope
11840 IORecursiveLockUnlock(sKextLock);
11841 finish:
11842 return result;
11843 }
11844
11845 /*********************************************************************
11846 *********************************************************************/
11847 /* static */
11848 OSSharedPtr<OSDictionary>
11849 OSKext::copyLoadedKextInfo(
11850 OSArray * kextIdentifiers,
11851 OSArray * infoKeys)
11852 {
11853 OSSharedPtr<OSDictionary> result;
11854 uint32_t idCount = 0;
11855 bool onlyLoaded;
11856
11857 IORecursiveLockLock(sKextLock);
11858
11859 #if CONFIG_MACF
11860 /* Is the calling process allowed to query kext info? */
11861 if (current_task() != kernel_task) {
11862 int macCheckResult = 0;
11863 kauth_cred_t cred = NULL;
11864
11865 cred = kauth_cred_get_with_ref();
11866 macCheckResult = mac_kext_check_query(cred);
11867 kauth_cred_unref(&cred);
11868
11869 if (macCheckResult != 0) {
11870 OSKextLog(/* kext */ NULL,
11871 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
11872 "Failed to query kext info (MAC policy error 0x%x).",
11873 macCheckResult);
11874 goto finish;
11875 }
11876 }
11877 #endif
11878
11879 /* Empty list of bundle ids is equivalent to no list (get all).
11880 */
11881 if (kextIdentifiers && !kextIdentifiers->getCount()) {
11882 kextIdentifiers = NULL;
11883 } else if (kextIdentifiers) {
11884 idCount = kextIdentifiers->getCount();
11885 }
11886
11887 /* Same for keys.
11888 */
11889 if (infoKeys && !infoKeys->getCount()) {
11890 infoKeys = NULL;
11891 }
11892
11893 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
11894
11895 result = OSDictionary::withCapacity(128);
11896 if (!result) {
11897 goto finish;
11898 }
11899
11900 #if 0
11901 OSKextLog(/* kext */ NULL,
11902 kOSKextLogErrorLevel |
11903 kOSKextLogGeneralFlag,
11904 "kaslr: vm_kernel_slide 0x%lx \n",
11905 vm_kernel_slide);
11906 OSKextLog(/* kext */ NULL,
11907 kOSKextLogErrorLevel |
11908 kOSKextLogGeneralFlag,
11909 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
11910 vm_kernel_stext, vm_kernel_etext);
11911 OSKextLog(/* kext */ NULL,
11912 kOSKextLogErrorLevel |
11913 kOSKextLogGeneralFlag,
11914 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
11915 vm_kernel_base, vm_kernel_top);
11916 OSKextLog(/* kext */ NULL,
11917 kOSKextLogErrorLevel |
11918 kOSKextLogGeneralFlag,
11919 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
11920 vm_kext_base, vm_kext_top);
11921 OSKextLog(/* kext */ NULL,
11922 kOSKextLogErrorLevel |
11923 kOSKextLogGeneralFlag,
11924 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
11925 vm_prelink_stext, vm_prelink_etext);
11926 OSKextLog(/* kext */ NULL,
11927 kOSKextLogErrorLevel |
11928 kOSKextLogGeneralFlag,
11929 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
11930 vm_prelink_sinfo, vm_prelink_einfo);
11931 OSKextLog(/* kext */ NULL,
11932 kOSKextLogErrorLevel |
11933 kOSKextLogGeneralFlag,
11934 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
11935 vm_slinkedit, vm_elinkedit);
11936 #endif
11937 { // start block scope
11938 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
11939 {
11940 OSKext * thisKext = NULL; // do not release
11941 Boolean includeThis = true;
11942 OSSharedPtr<OSDictionary> kextInfo;
11943
11944 thisKext = OSDynamicCast(OSKext, obj);
11945 if (!thisKext) {
11946 return false;
11947 }
11948
11949 /* Skip current kext if not yet started and caller didn't request all.
11950 */
11951 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
11952 return false;
11953 }
11954
11955 /* Skip current kext if we have a list of bundle IDs and
11956 * it isn't in the list.
11957 */
11958 if (kextIdentifiers) {
11959 includeThis = false;
11960
11961 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
11962 const OSString * thisRequestID = OSDynamicCast(OSString,
11963 kextIdentifiers->getObject(idIndex));
11964 if (thisKextID->isEqualTo(thisRequestID)) {
11965 includeThis = true;
11966 break;
11967 }
11968 }
11969 }
11970
11971 if (!includeThis) {
11972 return false;
11973 }
11974
11975 kextInfo = thisKext->copyInfo(infoKeys);
11976 if (kextInfo) {
11977 result->setObject(thisKext->getIdentifier(), kextInfo.get());
11978 }
11979 return false;
11980 });
11981 } // end block scope
11982
11983 finish:
11984 IORecursiveLockUnlock(sKextLock);
11985
11986 return result;
11987 }
11988
11989 /*********************************************************************
11990 * Any info that needs to do allocations must goto finish on alloc
11991 * failure. Info that is just a lookup should just not set the object
11992 * if the info does not exist.
11993 *********************************************************************/
11994 #define _OSKextLoadInfoDictCapacity (12)
11995
11996 OSSharedPtr<OSDictionary>
11997 OSKext::copyInfo(OSArray * infoKeys)
11998 {
11999 OSSharedPtr<OSDictionary> result;
12000 bool success = false;
12001 OSSharedPtr<OSData> headerData;
12002 OSSharedPtr<OSData> logData;
12003 OSSharedPtr<OSNumber> cpuTypeNumber;
12004 OSSharedPtr<OSNumber> cpuSubtypeNumber;
12005 OSString * versionString = NULL; // do not release
12006 OSString * bundleType = NULL; // do not release
12007 uint32_t executablePathCStringSize = 0;
12008 char * executablePathCString = NULL; // must kfree
12009 OSSharedPtr<OSString> executablePathString;
12010 OSSharedPtr<OSData> uuid;
12011 OSSharedPtr<OSArray> dependencyLoadTags;
12012 OSSharedPtr<OSCollectionIterator> metaClassIterator;
12013 OSSharedPtr<OSArray> metaClassInfo;
12014 OSSharedPtr<OSDictionary> metaClassDict;
12015 OSMetaClass * thisMetaClass = NULL; // do not release
12016 OSSharedPtr<OSString> metaClassName;
12017 OSSharedPtr<OSString> superclassName;
12018 kc_format_t kcformat;
12019 uint32_t count, i;
12020
12021 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
12022 if (!result) {
12023 goto finish;
12024 }
12025
12026
12027 /* Empty keys means no keys, but NULL is quicker to check.
12028 */
12029 if (infoKeys && !infoKeys->getCount()) {
12030 infoKeys = NULL;
12031 }
12032
12033 if (!PE_get_primary_kc_format(&kcformat)) {
12034 goto finish;
12035 }
12036
12037 /* Headers, CPU type, and CPU subtype.
12038 */
12039 if (!infoKeys ||
12040 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
12041 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
12042 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
12043 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12044 if (linkedExecutable && !isInterface()) {
12045 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
12046 linkedExecutable->getBytesNoCopy();
12047
12048 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
12049 // do not return macho header info on shipping embedded - 19095897
12050 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
12051 kernel_mach_header_t * temp_kext_mach_hdr;
12052 struct load_command * lcp;
12053
12054 headerData = OSData::withBytes(kext_mach_hdr,
12055 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
12056 if (!headerData) {
12057 goto finish;
12058 }
12059
12060 // unslide any vmaddrs we return to userspace - 10726716
12061 temp_kext_mach_hdr = (kernel_mach_header_t *)
12062 headerData->getBytesNoCopy();
12063 if (temp_kext_mach_hdr == NULL) {
12064 goto finish;
12065 }
12066
12067 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
12068 for (i = 0; (i < temp_kext_mach_hdr->ncmds) && !flags.unslidMachO; i++) {
12069 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12070 kernel_segment_command_t * segp;
12071 kernel_section_t * secp;
12072
12073 segp = (kernel_segment_command_t *) lcp;
12074 // 10543468 - if we jettisoned __LINKEDIT clear size info
12075 if (flags.jettisonLinkeditSeg) {
12076 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
12077 segp->vmsize = 0;
12078 segp->fileoff = 0;
12079 segp->filesize = 0;
12080 }
12081 }
12082
12083 #if __arm__ || __arm64__
12084 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
12085 // and unslide them to avoid vm assertion failures / kernel logging breakage.
12086 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
12087 segp->vmaddr = gVirtBase;
12088 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
12089 secp->size = 0; // paranoia :)
12090 secp->addr = gVirtBase;
12091 }
12092 }
12093 #endif
12094
12095 #if 0
12096 OSKextLog(/* kext */ NULL,
12097 kOSKextLogErrorLevel |
12098 kOSKextLogGeneralFlag,
12099 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
12100 __FUNCTION__, segp->segname, segp->vmaddr,
12101 VM_KERNEL_UNSLIDE(segp->vmaddr),
12102 segp->vmsize, segp->nsects);
12103 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
12104 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
12105 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
12106 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
12107 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
12108 OSKextLog(/* kext */ NULL,
12109 kOSKextLogErrorLevel |
12110 kOSKextLogGeneralFlag,
12111 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
12112 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
12113 }
12114 #endif
12115 segp->vmaddr = ml_static_unslide(segp->vmaddr);
12116
12117 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
12118 secp->addr = ml_static_unslide(secp->addr);
12119 }
12120 }
12121 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
12122 }
12123 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
12124 }
12125 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
12126
12127 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12128 osLogDataHeaderRef *header;
12129 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12130
12131 void *os_log_data = NULL;
12132 void *cstring_data = NULL;
12133 void *asan_cstring_data = NULL;
12134 unsigned long os_log_size = 0;
12135 unsigned long cstring_size = 0;
12136 unsigned long asan_cstring_size = 0;
12137 uint32_t os_log_offset = 0;
12138 uint32_t cstring_offset = 0;
12139 uint32_t asan_cstring_offset = 0;
12140 bool res;
12141
12142 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
12143 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
12144 asan_cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__asan_cstring", &asan_cstring_size);
12145
12146 /*
12147 * If the addresses in the Mach-O header are unslid, manually
12148 * slide them to allow for dereferencing.
12149 */
12150 if (flags.unslidMachO) {
12151 os_log_data = (os_log_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)os_log_data) : nullptr;
12152 cstring_data = (cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)cstring_data) : nullptr;
12153 asan_cstring_data = (asan_cstring_data != nullptr) ? (void*)ml_static_slide((vm_offset_t)asan_cstring_data) : nullptr;
12154 }
12155
12156 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
12157 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
12158 asan_cstring_offset = (uintptr_t)asan_cstring_data - (uintptr_t)kext_mach_hdr;
12159
12160 header = (osLogDataHeaderRef *) headerBytes;
12161 header->version = OS_LOG_HDR_VERSION;
12162 header->sect_count = NUM_OS_LOG_SECTIONS;
12163 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
12164 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
12165 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
12166 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
12167 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = asan_cstring_offset;
12168 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) asan_cstring_size;
12169
12170
12171 logData = OSData::withValue(*header);
12172 if (!logData) {
12173 goto finish;
12174 }
12175 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12176 if (!res) {
12177 goto finish;
12178 }
12179 if (os_log_data) {
12180 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
12181 if (!res) {
12182 goto finish;
12183 }
12184 }
12185 if (cstring_data) {
12186 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
12187 if (!res) {
12188 goto finish;
12189 }
12190 }
12191 if (asan_cstring_data) {
12192 res = logData->appendBytes(asan_cstring_data, (u_int)header->sections[ASAN_CSTRING_SECT_IDX].sect_size);
12193 if (!res) {
12194 goto finish;
12195 }
12196 }
12197 result->setObject(kOSBundleLogStringsKey, logData.get());
12198 }
12199
12200 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
12201 cpuTypeNumber = OSNumber::withNumber(
12202 (uint64_t) kext_mach_hdr->cputype,
12203 8 * sizeof(kext_mach_hdr->cputype));
12204 if (!cpuTypeNumber) {
12205 goto finish;
12206 }
12207 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
12208 }
12209
12210 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
12211 cpuSubtypeNumber = OSNumber::withNumber(
12212 (uint64_t) kext_mach_hdr->cpusubtype,
12213 8 * sizeof(kext_mach_hdr->cpusubtype));
12214 if (!cpuSubtypeNumber) {
12215 goto finish;
12216 }
12217 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
12218 }
12219 } else {
12220 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
12221 osLogDataHeaderRef *header;
12222 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
12223 bool res;
12224
12225 header = (osLogDataHeaderRef *) headerBytes;
12226 header->version = OS_LOG_HDR_VERSION;
12227 header->sect_count = NUM_OS_LOG_SECTIONS;
12228 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
12229 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
12230 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
12231 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12232 header->sections[ASAN_CSTRING_SECT_IDX].sect_offset = 0;
12233 header->sections[ASAN_CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
12234
12235 logData = OSData::withValue(*header);
12236 if (!logData) {
12237 goto finish;
12238 }
12239 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
12240 if (!res) {
12241 goto finish;
12242 }
12243 result->setObject(kOSBundleLogStringsKey, logData.get());
12244 }
12245 }
12246 }
12247
12248 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
12249 */
12250 result->setObject(kCFBundleIdentifierKey, bundleID.get());
12251
12252 /* kOSBundleDextUniqueIdentifierKey if present.
12253 */
12254 if (isDriverKit() && dextUniqueID != NULL) {
12255 result->setObject(kOSBundleDextUniqueIdentifierKey, dextUniqueID.get());
12256 }
12257
12258 /* CFBundlePackageType
12259 */
12260 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
12261 if (bundleType) {
12262 result->setObject(kCFBundlePackageTypeKey, bundleType);
12263 }
12264
12265 /* CFBundleVersion.
12266 */
12267 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
12268 versionString = OSDynamicCast(OSString,
12269 getPropertyForHostArch(kCFBundleVersionKey));
12270 if (versionString) {
12271 result->setObject(kCFBundleVersionKey, versionString);
12272 }
12273 }
12274
12275 /* OSBundleCompatibleVersion.
12276 */
12277 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
12278 versionString = OSDynamicCast(OSString,
12279 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
12280 if (versionString) {
12281 result->setObject(kOSBundleCompatibleVersionKey, versionString);
12282 }
12283 }
12284
12285 /* Path.
12286 */
12287 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
12288 if (path) {
12289 result->setObject(kOSBundlePathKey, path.get());
12290 }
12291 }
12292
12293
12294 /* OSBundleExecutablePath.
12295 */
12296 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
12297 if (path && executableRelPath) {
12298 uint32_t pathLength = path->getLength(); // gets incremented below
12299
12300 // +1 for slash, +1 for \0
12301 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
12302
12303 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12304 Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
12305 if (!executablePathCString) {
12306 goto finish;
12307 }
12308 strlcpy(executablePathCString, path->getCStringNoCopy(),
12309 executablePathCStringSize);
12310 executablePathCString[pathLength++] = '/';
12311 executablePathCString[pathLength++] = '\0';
12312 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
12313 executablePathCStringSize);
12314
12315 executablePathString = OSString::withCString(executablePathCString);
12316
12317 if (!executablePathString) {
12318 goto finish;
12319 }
12320
12321 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12322 } else if (flags.builtin) {
12323 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
12324 } else if (isDriverKit()) {
12325 if (path) {
12326 // +1 for slash, +1 for \0
12327 uint32_t pathLength = path->getLength();
12328 executablePathCStringSize = pathLength + 2;
12329
12330 executablePathCString = (char *)kalloc_data_tag(executablePathCStringSize,
12331 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
12332 if (!executablePathCString) {
12333 goto finish;
12334 }
12335 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
12336 executablePathCString[pathLength++] = '/';
12337 executablePathCString[pathLength++] = '\0';
12338
12339 executablePathString = OSString::withCString(executablePathCString);
12340
12341 if (!executablePathString) {
12342 goto finish;
12343 }
12344
12345 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
12346 }
12347 }
12348 }
12349
12350 /* UUID, if the kext has one.
12351 */
12352 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
12353 uuid = copyUUID();
12354 if (uuid) {
12355 result->setObject(kOSBundleUUIDKey, uuid.get());
12356 }
12357 }
12358 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
12359 uuid = copyTextUUID();
12360 if (uuid) {
12361 result->setObject(kOSBundleTextUUIDKey, uuid.get());
12362 }
12363 }
12364
12365 /*
12366 * Info.plist digest
12367 */
12368 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
12369 OSData *digest;
12370 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
12371 if (digest) {
12372 result->setObject(kOSKextInfoPlistDigestKey, digest);
12373 }
12374 }
12375
12376 /*
12377 * Collection type
12378 */
12379 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
12380 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
12381 }
12382
12383 /*
12384 * Collection availability
12385 */
12386 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
12387 result->setObject(kOSKextAuxKCAvailabilityKey,
12388 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
12389 }
12390
12391 /*
12392 * Allows user load
12393 */
12394 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
12395 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
12396 if (allowUserLoad) {
12397 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
12398 }
12399 }
12400
12401 /*
12402 * Bundle Dependencies (OSBundleLibraries)
12403 */
12404 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
12405 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
12406 if (libraries) {
12407 result->setObject(kOSBundleLibrariesKey, libraries);
12408 }
12409 }
12410
12411 /*****
12412 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
12413 */
12414 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
12415 result->setObject(kOSKernelResourceKey,
12416 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
12417 }
12418
12419 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
12420 result->setObject(kOSBundleIsInterfaceKey,
12421 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
12422 }
12423
12424 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
12425 result->setObject(kOSBundlePrelinkedKey,
12426 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
12427 }
12428
12429 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
12430 result->setObject(kOSBundleStartedKey,
12431 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
12432 }
12433
12434 /* LoadTag (Index).
12435 */
12436 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
12437 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
12438 /* numBits */ 8 * sizeof(loadTag));
12439 if (!scratchNumber) {
12440 goto finish;
12441 }
12442 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
12443 }
12444
12445 /* LoadAddress, LoadSize.
12446 */
12447 if (!infoKeys ||
12448 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
12449 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
12450 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
12451 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
12452 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12453 bool is_dext = isDriverKit();
12454 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
12455 /* These go to userspace via serialization, so we don't want any doubts
12456 * about their size.
12457 */
12458 uint64_t loadAddress = 0;
12459 uint32_t loadSize = 0;
12460 uint32_t wiredSize = 0;
12461 uint64_t execLoadAddress = 0;
12462 uint32_t execLoadSize = 0;
12463
12464 /* Interfaces always report 0 load address & size.
12465 * Just the way they roll.
12466 *
12467 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
12468 * xxx - shouldn't have one!
12469 */
12470
12471 if (flags.builtin || linkedExecutable) {
12472 kernel_mach_header_t *mh = NULL;
12473 kernel_segment_command_t *seg = NULL;
12474
12475 if (flags.builtin) {
12476 loadAddress = kmod_info->address;
12477 loadSize = (uint32_t)kmod_info->size;
12478 } else {
12479 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
12480 loadSize = linkedExecutable->getLength();
12481 }
12482 mh = (kernel_mach_header_t *)loadAddress;
12483 loadAddress = ml_static_unslide(loadAddress);
12484
12485 /* Walk through the kext, looking for the first executable
12486 * segment in case we were asked for its size/address.
12487 */
12488 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
12489 if (seg->initprot & VM_PROT_EXECUTE) {
12490 execLoadAddress = (flags.unslidMachO) ? seg->vmaddr : ml_static_unslide(seg->vmaddr);
12491 execLoadSize = (uint32_t)seg->vmsize;
12492 break;
12493 }
12494 }
12495
12496 /* If we have a kmod_info struct, calculated the wired size
12497 * from that. Otherwise it's the full load size.
12498 */
12499 if (kmod_info) {
12500 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
12501 } else {
12502 wiredSize = loadSize;
12503 }
12504 } else if (is_dext) {
12505 /*
12506 * DriverKit userspace executables do not have a kernel linkedExecutable,
12507 * so we "fake" their address range with the LoadTag.
12508 */
12509 if (loadTag) {
12510 loadAddress = execLoadAddress = loadTag;
12511 loadSize = execLoadSize = 1;
12512 }
12513 }
12514
12515 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
12516 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12517 (unsigned long long)(loadAddress),
12518 /* numBits */ 8 * sizeof(loadAddress));
12519 if (!scratchNumber) {
12520 goto finish;
12521 }
12522 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
12523 }
12524 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
12525 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
12526 && loadAddress && loadSize) {
12527 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
12528 if (!baseAddress) {
12529 goto finish;
12530 }
12531
12532 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12533 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
12534 /* numBits */ 8 * sizeof(loadAddress));
12535 if (!scratchNumber) {
12536 goto finish;
12537 }
12538 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
12539 }
12540 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
12541 && (this == sKernelKext) && gBuiltinKmodsCount) {
12542 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
12543 }
12544 }
12545
12546 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
12547 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12548 (unsigned long long)(execLoadAddress),
12549 /* numBits */ 8 * sizeof(execLoadAddress));
12550 if (!scratchNumber) {
12551 goto finish;
12552 }
12553 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
12554 }
12555 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
12556 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12557 (unsigned long long)(loadSize),
12558 /* numBits */ 8 * sizeof(loadSize));
12559 if (!scratchNumber) {
12560 goto finish;
12561 }
12562 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
12563 }
12564 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
12565 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12566 (unsigned long long)(execLoadSize),
12567 /* numBits */ 8 * sizeof(execLoadSize));
12568 if (!scratchNumber) {
12569 goto finish;
12570 }
12571 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
12572 }
12573 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
12574 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12575 (unsigned long long)(wiredSize),
12576 /* numBits */ 8 * sizeof(wiredSize));
12577 if (!scratchNumber) {
12578 goto finish;
12579 }
12580 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
12581 }
12582 }
12583 }
12584
12585 /* OSBundleDependencies. In descending order for
12586 * easy compatibility with kextstat(8).
12587 */
12588 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
12589 if ((count = getNumDependencies())) {
12590 dependencyLoadTags = OSArray::withCapacity(count);
12591 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
12592
12593 i = count - 1;
12594 do {
12595 OSKext * dependency = OSDynamicCast(OSKext,
12596 dependencies->getObject(i));
12597
12598 if (!dependency) {
12599 continue;
12600 }
12601 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12602 (unsigned long long)dependency->getLoadTag(),
12603 /* numBits*/ 8 * sizeof(loadTag));
12604 if (!scratchNumber) {
12605 goto finish;
12606 }
12607 dependencyLoadTags->setObject(scratchNumber.get());
12608 } while (i--);
12609 }
12610 }
12611
12612 /* OSBundleMetaClasses.
12613 */
12614 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
12615 if (metaClasses && metaClasses->getCount()) {
12616 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
12617 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
12618 if (!metaClassIterator || !metaClassInfo) {
12619 goto finish;
12620 }
12621 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
12622
12623 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
12624 metaClassIterator->getNextObject()))) {
12625 metaClassDict = OSDictionary::withCapacity(3);
12626 if (!metaClassDict) {
12627 goto finish;
12628 }
12629
12630 metaClassName = OSString::withCString(thisMetaClass->getClassName());
12631 if (thisMetaClass->getSuperClass()) {
12632 superclassName = OSString::withCString(
12633 thisMetaClass->getSuperClass()->getClassName());
12634 }
12635 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
12636 8 * sizeof(unsigned int));
12637
12638 /* Bail if any of the essentials is missing. The root class lacks a superclass,
12639 * of course.
12640 */
12641 if (!metaClassDict || !metaClassName || !scratchNumber) {
12642 goto finish;
12643 }
12644
12645 metaClassInfo->setObject(metaClassDict.get());
12646 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
12647 if (superclassName) {
12648 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
12649 }
12650 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
12651 }
12652 }
12653 }
12654
12655 /* OSBundleRetainCount.
12656 */
12657 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
12658 {
12659 int kextRetainCount = getRetainCount() - 1;
12660 if (isLoaded()) {
12661 kextRetainCount--;
12662 }
12663 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
12664 (int)kextRetainCount,
12665 /* numBits*/ 8 * sizeof(int));
12666 if (scratchNumber) {
12667 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
12668 }
12669 }
12670 }
12671
12672 success = true;
12673
12674 finish:
12675 if (executablePathCString) {
12676 kfree_data(executablePathCString, executablePathCStringSize);
12677 }
12678 if (!success) {
12679 result.reset();
12680 }
12681 return result;
12682 }
12683
12684 /*********************************************************************
12685 *********************************************************************/
12686 /* static */
12687 bool
12688 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
12689 {
12690 bool ok;
12691 OSSharedPtr<OSKext> kext;
12692
12693 IORecursiveLockLock(sKextLock);
12694 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
12695 IORecursiveLockUnlock(sKextLock);
12696
12697 if (!kext || !kext->path || !kext->userExecutableRelPath) {
12698 return false;
12699 }
12700 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
12701 kext->path->getCStringNoCopy(),
12702 kext->userExecutableRelPath->getCStringNoCopy());
12703 ok = true;
12704
12705 return ok;
12706 }
12707
12708 /*********************************************************************
12709 *********************************************************************/
12710 /* static */
12711 OSReturn
12712 OSKext::requestResource(
12713 const char * kextIdentifierCString,
12714 const char * resourceNameCString,
12715 OSKextRequestResourceCallback callback,
12716 void * context,
12717 OSKextRequestTag * requestTagOut)
12718 {
12719 OSReturn result = kOSReturnError;
12720 OSSharedPtr<OSKext> callbackKext; // looked up
12721
12722 OSKextRequestTag requestTag = -1;
12723 OSSharedPtr<OSNumber> requestTagNum;
12724 OSSharedPtr<OSDictionary> requestDict;
12725 OSSharedPtr<OSString> kextIdentifier;
12726 OSSharedPtr<OSString> resourceName;
12727
12728 OSSharedPtr<OSDictionary> callbackRecord;
12729 OSSharedPtr<OSValueObject<OSKextRequestResourceCallback> > callbackWrapper;
12730
12731 OSSharedPtr<OSValueObject<void *> > contextWrapper;
12732
12733 IORecursiveLockLock(sKextLock);
12734
12735 if (requestTagOut) {
12736 *requestTagOut = kOSKextRequestTagInvalid;
12737 }
12738
12739 /* If requests to user space are disabled, don't go any further */
12740 if (!sKernelRequestsEnabled) {
12741 OSKextLog(/* kext */ NULL,
12742 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12743 "Can't request resource %s for %s - requests to user space are disabled.",
12744 resourceNameCString,
12745 kextIdentifierCString);
12746 result = kOSKextReturnDisabled;
12747 goto finish;
12748 }
12749
12750 if (!kextIdentifierCString || !resourceNameCString || !callback) {
12751 result = kOSKextReturnInvalidArgument;
12752 goto finish;
12753 }
12754
12755 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12756 if (!callbackKext) {
12757 OSKextLog(/* kext */ NULL,
12758 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12759 "Resource request has bad callback address.");
12760 result = kOSKextReturnInvalidArgument;
12761 goto finish;
12762 }
12763 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12764 OSKextLog(/* kext */ NULL,
12765 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12766 "Resource request callback is in a kext that is not started.");
12767 result = kOSKextReturnInvalidArgument;
12768 goto finish;
12769 }
12770
12771 /* Do not allow any new requests to be made on a kext that is unloading.
12772 */
12773 if (callbackKext->flags.stopping) {
12774 result = kOSKextReturnStopping;
12775 goto finish;
12776 }
12777
12778 /* If we're wrapped the next available request tag around to the negative
12779 * numbers, we can't service any more requests.
12780 */
12781 if (sNextRequestTag == kOSKextRequestTagInvalid) {
12782 OSKextLog(/* kext */ NULL,
12783 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12784 "No more request tags available; restart required.");
12785 result = kOSKextReturnNoResources;
12786 goto finish;
12787 }
12788 requestTag = sNextRequestTag++;
12789
12790 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
12791 requestDict);
12792 if (result != kOSReturnSuccess) {
12793 goto finish;
12794 }
12795
12796 kextIdentifier = OSString::withCString(kextIdentifierCString);
12797 resourceName = OSString::withCString(resourceNameCString);
12798 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
12799 8 * sizeof(requestTag));
12800 if (!kextIdentifier ||
12801 !resourceName ||
12802 !requestTagNum ||
12803 !_OSKextSetRequestArgument(requestDict.get(),
12804 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
12805 !_OSKextSetRequestArgument(requestDict.get(),
12806 kKextRequestArgumentNameKey, resourceName.get()) ||
12807 !_OSKextSetRequestArgument(requestDict.get(),
12808 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
12809 result = kOSKextReturnNoMemory;
12810 goto finish;
12811 }
12812
12813 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
12814 if (!callbackRecord) {
12815 result = kOSKextReturnNoMemory;
12816 goto finish;
12817 }
12818 // we validate callback address at call time
12819 callbackWrapper = OSValueObjectWithValue(callback);
12820 if (context) {
12821 contextWrapper = OSValueObjectWithValue(context);
12822 }
12823 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12824 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
12825 result = kOSKextReturnNoMemory;
12826 goto finish;
12827 }
12828
12829 if (context) {
12830 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
12831 kKextRequestArgumentContextKey, contextWrapper.get())) {
12832 result = kOSKextReturnNoMemory;
12833 goto finish;
12834 }
12835 }
12836
12837 /* Only post the requests after all the other potential failure points
12838 * have been passed.
12839 */
12840 if (!sKernelRequests->setObject(requestDict.get()) ||
12841 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
12842 result = kOSKextReturnNoMemory;
12843 goto finish;
12844 }
12845
12846 OSKext::pingIOKitDaemon();
12847
12848 result = kOSReturnSuccess;
12849 if (requestTagOut) {
12850 *requestTagOut = requestTag;
12851 }
12852
12853 finish:
12854
12855 /* If we didn't succeed, yank the request & callback
12856 * from their holding arrays.
12857 */
12858 if (result != kOSReturnSuccess) {
12859 unsigned int index;
12860
12861 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
12862 if (index != (unsigned int)-1) {
12863 sKernelRequests->removeObject(index);
12864 }
12865 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
12866 if (index != (unsigned int)-1) {
12867 sRequestCallbackRecords->removeObject(index);
12868 }
12869 }
12870
12871 OSKext::considerUnloads(/* rescheduleOnly? */ true);
12872
12873 IORecursiveLockUnlock(sKextLock);
12874
12875 return result;
12876 }
12877
12878 OSReturn
12879 OSKext::requestDaemonLaunch(
12880 OSString *kextIdentifier,
12881 OSString *serverName,
12882 OSNumber *serverTag,
12883 OSBoolean *reslide,
12884 IOUserServerCheckInToken * checkInToken,
12885 OSData *serverDUI)
12886 {
12887 OSReturn result = kOSReturnError;
12888 OSSharedPtr<OSDictionary> requestDict;
12889 unsigned int size = 0;
12890 const char *dextUniqueIDCString = NULL;
12891
12892 if (!kextIdentifier || !serverName || !serverTag || !checkInToken) {
12893 return kOSKextReturnInvalidArgument;
12894 }
12895 if (!iokitDaemonAvailable()) {
12896 panic("Received unexpected request in environment where " kIOKitDaemonName " is unavailable");
12897 }
12898
12899 if (serverDUI != NULL) {
12900 dextUniqueIDCString = getDextUniqueIDCString(serverDUI, &size);
12901 }
12902
12903 IORecursiveLockLock(sKextLock);
12904
12905 OSKextLog(/* kext */ NULL,
12906 kOSKextLogDebugLevel |
12907 kOSKextLogGeneralFlag,
12908 "Requesting daemon launch for %s %s with serverName %s and tag %llu%s",
12909 kextIdentifier->getCStringNoCopy(),
12910 (dextUniqueIDCString != NULL)?dextUniqueIDCString:"",
12911 serverName->getCStringNoCopy(),
12912 serverTag->unsigned64BitValue(),
12913 reslide == kOSBooleanTrue ? " with reslid shared cache" : ""
12914 );
12915
12916 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
12917 if (result != kOSReturnSuccess) {
12918 goto finish;
12919 }
12920
12921 if (!_OSKextSetRequestArgument(requestDict.get(),
12922 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12923 !_OSKextSetRequestArgument(requestDict.get(),
12924 kKextRequestArgumentDriverExtensionServerName, serverName) ||
12925 !_OSKextSetRequestArgument(requestDict.get(),
12926 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
12927 !_OSKextSetRequestArgument(requestDict.get(),
12928 kKextRequestArgumentDriverExtensionReslideSharedCache, reslide) ||
12929 !_OSKextSetRequestArgument(requestDict.get(),
12930 kKextRequestArgumentCheckInToken, checkInToken)) {
12931 result = kOSKextReturnNoMemory;
12932 goto finish;
12933 }
12934
12935 if (serverDUI) {
12936 if (!_OSKextSetRequestArgument(requestDict.get(),
12937 kOSBundleDextUniqueIdentifierKey, serverDUI)) {
12938 result = kOSKextReturnNoMemory;
12939 goto finish;
12940 }
12941 }
12942
12943 /* Only post the requests after all the other potential failure points
12944 * have been passed.
12945 */
12946 if (!sKernelRequests->setObject(requestDict.get())) {
12947 result = kOSKextReturnNoMemory;
12948 goto finish;
12949 }
12950 result = OSKext::pingIOKitDaemon();
12951 if (result != kOSReturnSuccess) {
12952 goto finish;
12953 }
12954
12955 result = kOSReturnSuccess;
12956 finish:
12957 IORecursiveLockUnlock(sKextLock);
12958 if (dextUniqueIDCString) {
12959 kfree_data(dextUniqueIDCString, size);
12960 }
12961 return result;
12962 }
12963
12964 OSReturn
12965 OSKext::notifyDextUpgrade(
12966 OSString *kextIdentifier,
12967 OSData *dextUniqueIdentifier)
12968 {
12969 OSReturn result = kOSReturnError;
12970 OSSharedPtr<OSDictionary> requestDict;
12971 unsigned int size = 0;
12972 const char *dextUniqueIDCString = getDextUniqueIDCString(dextUniqueIdentifier, &size);
12973 assert(dextUniqueIDCString != NULL);
12974
12975 IORecursiveLockLock(sKextLock);
12976
12977 OSKextLog(NULL,
12978 kOSKextLogDebugLevel |
12979 kOSKextLogGeneralFlag,
12980 "Notifying of dext upgrade for %s with UniqueID %s",
12981 kextIdentifier->getCStringNoCopy(), dextUniqueIDCString);
12982
12983 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonUpgradeNotification, requestDict);
12984 if (result != kOSReturnSuccess) {
12985 goto finish;
12986 }
12987
12988 if (!_OSKextSetRequestArgument(requestDict.get(),
12989 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
12990 !_OSKextSetRequestArgument(requestDict.get(),
12991 kKextRequestArgumentDriverUniqueIdentifier, dextUniqueIdentifier)) {
12992 result = kOSKextReturnNoMemory;
12993 goto finish;
12994 }
12995
12996 /* Only post the requests after all the other potential failure points
12997 * have been passed.
12998 */
12999 if (!sKernelRequests->setObject(requestDict.get())) {
13000 result = kOSKextReturnNoMemory;
13001 goto finish;
13002 }
13003 OSKext::pingIOKitDaemon();
13004
13005 result = kOSReturnSuccess;
13006 finish:
13007 IORecursiveLockUnlock(sKextLock);
13008
13009 if (dextUniqueIDCString != NULL) {
13010 kfree_data(dextUniqueIDCString, size);
13011 }
13012 return result;
13013 }
13014
13015 /*********************************************************************
13016 * Assumes sKextLock is held.
13017 *********************************************************************/
13018 /* static */
13019 OSReturn
13020 OSKext::dequeueCallbackForRequestTag(
13021 OSKextRequestTag requestTag,
13022 OSSharedPtr<OSDictionary> &callbackRecordOut)
13023 {
13024 OSDictionary * callbackRecordOutRaw = NULL;
13025 OSReturn result;
13026
13027 result = dequeueCallbackForRequestTag(requestTag,
13028 &callbackRecordOutRaw);
13029
13030 if (kOSReturnSuccess == result) {
13031 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
13032 }
13033
13034 return result;
13035 }
13036 OSReturn
13037 OSKext::dequeueCallbackForRequestTag(
13038 OSKextRequestTag requestTag,
13039 OSDictionary ** callbackRecordOut)
13040 {
13041 OSReturn result = kOSReturnError;
13042 OSSharedPtr<OSNumber> requestTagNum;
13043
13044 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
13045 8 * sizeof(requestTag));
13046 if (!requestTagNum) {
13047 goto finish;
13048 }
13049
13050 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
13051 callbackRecordOut);
13052
13053 finish:
13054 return result;
13055 }
13056
13057 /*********************************************************************
13058 * Assumes sKextLock is held.
13059 *********************************************************************/
13060 /* static */
13061 OSReturn
13062 OSKext::dequeueCallbackForRequestTag(
13063 OSNumber * requestTagNum,
13064 OSSharedPtr<OSDictionary> &callbackRecordOut)
13065 {
13066 OSDictionary * callbackRecordOutRaw = NULL;
13067 OSReturn result;
13068
13069 result = dequeueCallbackForRequestTag(requestTagNum,
13070 &callbackRecordOutRaw);
13071
13072 if (kOSReturnSuccess == result) {
13073 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
13074 }
13075
13076 return result;
13077 }
13078 OSReturn
13079 OSKext::dequeueCallbackForRequestTag(
13080 OSNumber * requestTagNum,
13081 OSDictionary ** callbackRecordOut)
13082 {
13083 OSReturn result = kOSKextReturnInvalidArgument;
13084 OSDictionary * callbackRecord = NULL; // retain if matched!
13085 OSNumber * callbackTagNum = NULL; // do not release
13086 unsigned int count, i;
13087
13088 result = kOSReturnError;
13089 count = sRequestCallbackRecords->getCount();
13090 for (i = 0; i < count; i++) {
13091 callbackRecord = OSDynamicCast(OSDictionary,
13092 sRequestCallbackRecords->getObject(i));
13093 if (!callbackRecord) {
13094 goto finish;
13095 }
13096
13097 /* If we don't find a tag, we basically have a leak here. Maybe
13098 * we should just remove it.
13099 */
13100 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
13101 callbackRecord, kKextRequestArgumentRequestTagKey));
13102 if (!callbackTagNum) {
13103 goto finish;
13104 }
13105
13106 /* We could be even more paranoid and check that all the incoming
13107 * args match what's in the callback record.
13108 */
13109 if (callbackTagNum->isEqualTo(requestTagNum)) {
13110 if (callbackRecordOut) {
13111 *callbackRecordOut = callbackRecord;
13112 callbackRecord->retain();
13113 }
13114 sRequestCallbackRecords->removeObject(i);
13115 result = kOSReturnSuccess;
13116 goto finish;
13117 }
13118 }
13119 result = kOSKextReturnNotFound;
13120
13121 finish:
13122 return result;
13123 }
13124
13125
13126 /*********************************************************************
13127 * Busy timeout triage
13128 *********************************************************************/
13129 /* static */
13130 bool
13131 OSKext::pendingIOKitDaemonRequests(void)
13132 {
13133 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
13134 }
13135
13136 /*********************************************************************
13137 * Acquires and releases sKextLock
13138 *
13139 * This function is designed to be called by kernelmanagerd and driverkitd
13140 * and it gathers all codeless kext and dext personalities, and then attempts
13141 * to map a System (pageable) KC and an Auxiliary (aux) KC.
13142 *
13143 * The pageable and aux KC can be loaded only once at boot time.
13144 * Even if the pageable or aux KC fail to load - this function will
13145 * not allow a new pageable or aux KC to be installed by subsequent calls.
13146 * This is done to avoid security issues where userspace has been compromised
13147 * or the pageable kc has been tampered with and the attacker
13148 * attempts to re-load a malicious variant.
13149 * However dexts can be dynamically loaded, so this function can be used
13150 * to request the installation of a new set of dexts even after boot time.
13151 *
13152 *
13153 *
13154 * Return: if a KC fails to load the return value will contain:
13155 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
13156 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
13157 * Similarly, if the aux kc load fails, the return value will
13158 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
13159 * compose with each other and with kOSKextReturnKCLoadFailure.
13160 *********************************************************************/
13161 /* static */
13162 OSReturn
13163 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
13164 {
13165 static bool daemon_ready = false;
13166
13167 OSReturn ret = kOSKextReturnInvalidArgument;
13168 OSReturn kcerr = 0;
13169 bool start_matching = false;
13170
13171 bool allow_fileset_load = !daemon_ready;
13172 #if !(defined(__x86_64__) || defined(__i386__))
13173 /* never allow KCs full of kexts on non-x86 machines */
13174 allow_fileset_load = false;
13175 #endif
13176
13177 /*
13178 * Change with 70582300
13179 */
13180 #if 0 || !defined(VM_MAPPED_KEXTS)
13181 /*
13182 * On platforms that don't support the SystemKC or a file-backed
13183 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
13184 * needs to be queried before we load any codeless kexts or release
13185 * any 3rd party kexts to run. On platforms that support a file-backed
13186 * AuxKC, this process is done via the kext audit mechanism.
13187 */
13188
13189 printf("KextLog: waiting for kext receipt to be queried.\n");
13190 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
13191 IOSleep(30);
13192 }
13193 #endif /* !VM_MAPPED_KEXTS */
13194
13195 /*
13196 * Get the args from the request. Right now we need the file
13197 * name for the pageable and the aux kext collection file sets.
13198 */
13199 OSDictionary * requestArgs = NULL; // do not release
13200 OSString * pageable_filepath = NULL; // do not release
13201 OSString * aux_filepath = NULL; // do not release
13202 OSArray * codeless_kexts = NULL; // do not release
13203
13204 kernel_mach_header_t *akc_mh = NULL;
13205
13206 requestArgs = OSDynamicCast(OSDictionary,
13207 requestDict->getObject(kKextRequestArgumentsKey));
13208
13209 if (requestArgs == NULL) {
13210 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13211 "KextLog: No arguments in plist for loading fileset kext\n");
13212 printf("KextLog: No arguments in plist for loading fileset kext\n");
13213 return ret;
13214 }
13215
13216 ret = kOSKextReturnDisabled;
13217
13218 IORecursiveLockLock(sKextLock);
13219
13220 if (!sLoadEnabled) {
13221 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13222 "KextLog: Kext loading is disabled (attempt to load KCs).");
13223 IORecursiveLockUnlock(sKextLock);
13224 return ret;
13225 }
13226
13227 pageable_filepath = OSDynamicCast(OSString,
13228 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
13229
13230 if (allow_fileset_load && pageable_filepath != NULL) {
13231 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
13232
13233 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
13234 if (ret) {
13235 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13236 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13237
13238 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
13239 ret = kOSKextReturnKCLoadFailure;
13240 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
13241 goto try_auxkc;
13242 }
13243 /*
13244 * Even if the AuxKC fails to load, we still want to send
13245 * the System KC personalities to the catalog for matching
13246 */
13247 start_matching = true;
13248 } else if (pageable_filepath != NULL) {
13249 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13250 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
13251 ret = kOSKextReturnUnsupported;
13252 }
13253
13254 try_auxkc:
13255 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
13256 if (akc_mh) {
13257 /*
13258 * If we try to load a deferred AuxKC, then don't ever attempt
13259 * a filesystem map of a file
13260 */
13261 allow_fileset_load = false;
13262
13263 /*
13264 * This function is only called once per boot, so we haven't
13265 * yet loaded an AuxKC. If we have registered the AuxKC mach
13266 * header, that means that the kext collection has been placed
13267 * in memory for us by the booter, and is waiting for us to
13268 * process it. Grab the deferred XML plist of info
13269 * dictionaries and add all the kexts.
13270 */
13271 OSSharedPtr<OSObject> parsedXML;
13272 OSSharedPtr<OSData> loaded_kcUUID;
13273 OSDictionary *infoDict;
13274 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
13275 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13276 #if !defined(VM_MAPPED_KEXTS)
13277 /*
13278 * On platforms where we don't dynamically wire-down / page-in
13279 * kext memory, we need to maintain the invariant that if the
13280 * AuxKC in memory does not contain a kext receipt, then we
13281 * should not load any of the kexts.
13282 */
13283 size_t receipt_sz = 0;
13284 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
13285 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13286 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
13287 ret = kOSKextReturnKCLoadFailure;
13288 goto try_codeless;
13289 }
13290 #endif
13291 if (infoDict) {
13292 bool added;
13293 printf("KextLog: Adding kexts from in-memory AuxKC\n");
13294 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
13295 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
13296 if (!loaded_kcUUID) {
13297 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13298 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
13299 } else if (!added) {
13300 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13301 "KextLog: WARNING: Failed to load AuxKC from memory.");
13302 }
13303 /* only return success if the pageable load (above) was successful */
13304 if (ret != kOSKextReturnKCLoadFailure) {
13305 ret = kOSReturnSuccess;
13306 }
13307 /* the registration of the AuxKC parsed out the KC's UUID already */
13308 } else {
13309 if (daemon_ready) {
13310 /*
13311 * Complain, but don't return an error if this isn't the first time the
13312 * IOKit daemon is checking in. If the daemon ever restarts, we will
13313 * hit this case because we've already consumed the deferred personalities.
13314 * We return success here so that a call to this function from a restarted
13315 * daemon with no codeless kexts will succeed.
13316 */
13317 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13318 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
13319 if (ret != kOSKextReturnKCLoadFailure) {
13320 ret = kOSReturnSuccess;
13321 }
13322 } else {
13323 /* this is a real error case */
13324 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13325 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
13326 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
13327 ret = kOSKextReturnKCLoadFailure;
13328 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13329 }
13330 }
13331 }
13332
13333 aux_filepath = OSDynamicCast(OSString,
13334 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
13335 if (allow_fileset_load && aux_filepath != NULL) {
13336 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
13337
13338 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
13339 if (ret) {
13340 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13341 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13342
13343 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
13344 ret = kOSKextReturnKCLoadFailure;
13345 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
13346 goto try_codeless;
13347 }
13348 start_matching = true;
13349 } else if (aux_filepath != NULL) {
13350 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13351 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
13352 if (ret != kOSKextReturnKCLoadFailure) {
13353 ret = kOSKextReturnUnsupported;
13354 }
13355 }
13356
13357 try_codeless:
13358 /*
13359 * Load codeless kexts last so that there is no possibilty of a
13360 * codeless kext bundle ID preventing a kext in the system KC from
13361 * loading
13362 */
13363 codeless_kexts = OSDynamicCast(OSArray,
13364 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
13365 if (codeless_kexts != NULL) {
13366 uint32_t count = codeless_kexts->getCount();
13367 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13368 "KextLog: loading %d codeless kexts/dexts", count);
13369 for (uint32_t i = 0; i < count; i++) {
13370 OSDictionary *infoDict;
13371 infoDict = OSDynamicCast(OSDictionary,
13372 codeless_kexts->getObject(i));
13373 if (!infoDict) {
13374 continue;
13375 }
13376 // instantiate a new kext, and don't hold a reference
13377 // (the kext subsystem will hold one implicitly)
13378 OSKext::withCodelessInfo(infoDict, NULL);
13379 }
13380 /* ignore errors that are not KC load failures */
13381 if (ret != kOSKextReturnKCLoadFailure) {
13382 ret = kOSReturnSuccess;
13383 }
13384 start_matching = true;
13385 }
13386
13387 /* send personalities to the IOCatalog once */
13388 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
13389 OSKext::sendAllKextPersonalitiesToCatalog(true);
13390 /*
13391 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
13392 * things as active and start all the delayed matching: the
13393 * dext and codeless kext personalities should have all been
13394 * delivered via this one call.
13395 */
13396 if (!daemon_ready) {
13397 OSKext::setIOKitDaemonActive();
13398 OSKext::setDeferredLoadSucceeded(TRUE);
13399 IOService::iokitDaemonLaunched();
13400 }
13401 if (sOSKextWasResetAfterUserspaceReboot) {
13402 sOSKextWasResetAfterUserspaceReboot = false;
13403 OSKext::setIOKitDaemonActive();
13404 IOService::startDeferredMatches();
13405 }
13406 }
13407
13408 if (ret == kOSKextReturnKCLoadFailure) {
13409 ret |= kcerr;
13410 }
13411
13412 /*
13413 * Only allow this function to attempt to load the pageable and
13414 * aux KCs once per boot.
13415 */
13416 daemon_ready = true;
13417
13418 IORecursiveLockUnlock(sKextLock);
13419
13420 return ret;
13421 }
13422
13423 OSReturn
13424 OSKext::resetMutableSegments(void)
13425 {
13426 kernel_segment_command_t *seg = NULL;
13427 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
13428 u_int index = 0;
13429 OSKextSavedMutableSegment *savedSegment = NULL;
13430 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
13431 OSReturn err;
13432
13433 if (!savedMutableSegments) {
13434 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
13435 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
13436 err = kOSKextReturnInternalError;
13437 goto finish;
13438 }
13439
13440 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
13441 if (!segmentIsMutable(seg)) {
13442 continue;
13443 }
13444 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
13445 uint64_t vmsize = seg->vmsize;
13446 err = kOSKextReturnInternalError;
13447 for (index = 0; index < savedMutableSegments->getCount(); index++) {
13448 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
13449 assert(savedSegment);
13450 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
13451 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
13452 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13453 err = savedSegment->restoreContents(seg);
13454 if (err != kOSReturnSuccess) {
13455 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13456 }
13457 }
13458 }
13459 if (err != kOSReturnSuccess) {
13460 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
13461 }
13462 }
13463 err = kOSReturnSuccess;
13464 finish:
13465 return err;
13466 }
13467
13468
13469 /*********************************************************************
13470 * Assumes sKextLock is held.
13471 *********************************************************************/
13472 /* static */
13473 OSReturn
13474 OSKext::loadKCFileSet(
13475 const char *filepath,
13476 kc_kind_t type)
13477 {
13478 #if VM_MAPPED_KEXTS
13479 /* we only need to load filesets on systems that support VM_MAPPED kexts */
13480 OSReturn err;
13481 struct vnode *vp = NULL;
13482 void *fileset_control;
13483 off_t fsize;
13484 bool pageable = (type == KCKindPageable);
13485
13486 if ((pageable && pageableKCloaded) ||
13487 (!pageable && auxKCloaded)) {
13488 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13489 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
13490
13491 return kOSKextReturnInvalidArgument;
13492 }
13493
13494 /* Do not allow AuxKC to load if Pageable KC is not loaded */
13495 if (!pageable && !pageableKCloaded) {
13496 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13497 "Trying to load the Aux KC without loading the Pageable KC");
13498 return kOSKextReturnInvalidArgument;
13499 }
13500
13501 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
13502
13503 if (fileset_control == NULL) {
13504 printf("Could not get memory control object for file %s", filepath);
13505
13506 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13507 "Could not get memory control object for file %s", filepath);
13508 return kOSKextReturnInvalidArgument;
13509 }
13510 if (vp == NULL) {
13511 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13512 "Could not find vnode for file %s", filepath);
13513 return kOSKextReturnInvalidArgument;
13514 }
13515
13516 kernel_mach_header_t *mh = NULL;
13517 uintptr_t slide = 0;
13518
13519 #if CONFIG_CSR
13520 /*
13521 * When SIP is enabled, the KC we map must be SIP-protected
13522 */
13523 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
13524 struct vnode_attr va;
13525 int error;
13526 VATTR_INIT(&va);
13527 VATTR_WANTED(&va, va_flags);
13528 error = vnode_getattr(vp, &va, vfs_context_current());
13529 if (error) {
13530 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13531 "vnode_getattr(%s) failed (error=%d)", filepath, error);
13532 err = kOSKextReturnInternalError;
13533 goto finish;
13534 }
13535 if (!(va.va_flags & SF_RESTRICTED)) {
13536 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13537 "Path to KC '%s' is not SIP-protected", filepath);
13538 err = kOSKextReturnInvalidArgument;
13539 goto finish;
13540 }
13541 }
13542 #endif
13543
13544 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
13545 if (err) {
13546 printf("KextLog: mapKCFileSet returned %d\n", err);
13547
13548 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13549 "mapKCFileSet returned %d\n", err);
13550
13551 err = kOSKextReturnInvalidArgument;
13552 }
13553
13554 #if CONFIG_CSR
13555 finish:
13556 #endif
13557 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
13558 assert(vp != NULL);
13559 if (err == kOSReturnSuccess) {
13560 PE_set_kc_vp(type, vp);
13561 if (pageable) {
13562 pageableKCloaded = true;
13563 } else {
13564 auxKCloaded = true;
13565 }
13566 } else {
13567 vnode_put(vp);
13568 }
13569
13570 return err;
13571 #else
13572 (void)filepath;
13573 (void)type;
13574 return kOSKextReturnUnsupported;
13575 #endif // VM_MAPPED_KEXTS
13576 }
13577
13578 #if defined(__x86_64__) || defined(__i386__)
13579 /*********************************************************************
13580 * Assumes sKextLock is held.
13581 *********************************************************************/
13582 /* static */
13583 OSReturn
13584 OSKext::mapKCFileSet(
13585 void *control,
13586 vm_size_t fsize,
13587 kernel_mach_header_t **mhp,
13588 off_t file_offset,
13589 uintptr_t *slidep,
13590 bool pageable,
13591 void *map_entry_list)
13592 {
13593 bool fileset_load = false;
13594 kern_return_t ret;
13595 OSReturn err;
13596 kernel_section_t *infoPlistSection = NULL;
13597 OSDictionary *infoDict = NULL;
13598
13599 OSSharedPtr<OSObject> parsedXML;
13600 OSSharedPtr<OSString> errorString;
13601 OSSharedPtr<OSData> loaded_kcUUID;
13602
13603 /* Check if initial load for file set */
13604 if (*mhp == NULL) {
13605 fileset_load = true;
13606
13607 /* Get a page aligned address from kext map to map the file */
13608 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
13609 if (pagealigned_addr == 0) {
13610 return kOSKextReturnNoMemory;
13611 }
13612
13613 *mhp = (kernel_mach_header_t *)pagealigned_addr;
13614
13615 /* Allocate memory for bailout mechanism */
13616 map_entry_list = allocate_kcfileset_map_entry_list();
13617 if (map_entry_list == NULL) {
13618 return kOSKextReturnNoMemory;
13619 }
13620 }
13621
13622 uintptr_t *slideptr = fileset_load ? slidep : NULL;
13623 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
13624 /* mhp and slideptr are updated by mapKCTextSegment */
13625 if (err) {
13626 if (fileset_load) {
13627 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13628 }
13629 return err;
13630 }
13631
13632 /* Initialize the kc header globals */
13633 if (fileset_load) {
13634 if (pageable) {
13635 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
13636 } else {
13637 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
13638 }
13639 }
13640
13641 /* Iterate through all the segments and map necessary segments */
13642 struct load_command *lcp = (struct load_command *) (*mhp + 1);
13643 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
13644 vm_map_offset_t start;
13645 kernel_mach_header_t *k_mh = NULL;
13646 kernel_segment_command_t * seg = NULL;
13647 struct fileset_entry_command *fse = NULL;
13648
13649 if (lcp->cmd == LC_SEGMENT_KERNEL) {
13650 seg = (kernel_segment_command_t *)lcp;
13651 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
13652 } else if (lcp->cmd == LC_FILESET_ENTRY) {
13653 fse = (struct fileset_entry_command *)lcp;
13654 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
13655
13656 /* Map the segments of the mach-o binary */
13657 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
13658 if (err) {
13659 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13660 return kOSKextReturnInvalidArgument;
13661 }
13662 continue;
13663 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
13664 /* Check if the Aux KC is built pageable style */
13665 if (!pageable && !fileset_load && !auxKCloaded) {
13666 resetAuxKCSegmentOnUnload = true;
13667 }
13668 continue;
13669 } else {
13670 continue;
13671 }
13672
13673 if (fileset_load) {
13674 if (seg->vmsize == 0) {
13675 continue;
13676 }
13677
13678 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
13679 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
13680 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
13681 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
13682 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
13683 continue;
13684 }
13685 } else {
13686 if (seg->vmsize == 0) {
13687 continue;
13688 }
13689
13690 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
13691 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
13692 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
13693 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
13694 continue;
13695 }
13696 }
13697
13698 ret = vm_map_kcfileset_segment(
13699 &start, seg->vmsize,
13700 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
13701
13702 if (ret != KERN_SUCCESS) {
13703 if (fileset_load) {
13704 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13705 }
13706 return kOSKextReturnInvalidArgument;
13707 }
13708 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
13709 }
13710
13711 /* Return if regular mach-o */
13712 if (!fileset_load) {
13713 return 0;
13714 }
13715
13716 /*
13717 * Fixup for the Pageable KC and the Aux KC is done by
13718 * i386_slide_kext_collection_mh_addrs, but it differs in
13719 * following ways:
13720 *
13721 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
13722 * The fixup of kext segments and kext load commands are done at kext
13723 * load time by calling i386_slide_individual_kext.
13724 *
13725 * AuxKC old style: Fixup all the segments and all the load commands.
13726 *
13727 * AuxKC pageable style: Same as the Pageable KC.
13728 */
13729 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
13730 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
13731 if (ret != KERN_SUCCESS) {
13732 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13733 return kOSKextReturnInvalidArgument;
13734 }
13735
13736 /* Get the prelink info dictionary */
13737 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
13738 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
13739 if (parsedXML) {
13740 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
13741 }
13742
13743 if (!infoDict) {
13744 const char *errorCString = "(unknown error)";
13745
13746 if (errorString && errorString->getCStringNoCopy()) {
13747 errorCString = errorString->getCStringNoCopy();
13748 } else if (parsedXML) {
13749 errorCString = "not a dictionary";
13750 }
13751 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13752 "Error unserializing kext info plist section: %s.", errorCString);
13753 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13754 return kOSKextReturnInvalidArgument;
13755 }
13756
13757 /* Validate that the Kext Collection is prelinked to the loaded KC */
13758 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
13759 if (err) {
13760 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
13761 return kOSKextReturnInvalidArgument;
13762 }
13763
13764 /* Set Protection of Segments */
13765 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
13766
13767 OSKext::addKextsFromKextCollection(*mhp,
13768 infoDict, kPrelinkTextSegment,
13769 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
13770
13771 /* Copy in the KC UUID */
13772 if (!loaded_kcUUID) {
13773 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
13774 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
13775 } else if (pageable) {
13776 pageablekc_uuid_valid = TRUE;
13777 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13778 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
13779 } else {
13780 auxkc_uuid_valid = TRUE;
13781 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
13782 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
13783 }
13784
13785 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
13786
13787 return 0;
13788 }
13789
13790 /*********************************************************************
13791 * Assumes sKextLock is held.
13792 *********************************************************************/
13793 /* static */
13794 OSReturn
13795 OSKext::mapKCTextSegment(
13796 void *control,
13797 kernel_mach_header_t **mhp,
13798 off_t file_offset,
13799 uintptr_t *slidep,
13800 void *map_entry_list)
13801 {
13802 kern_return_t ret;
13803 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
13804 PAGE_MASK);
13805 vm_map_offset_t load_command_map_size = 0;
13806 kernel_mach_header_t *base_mh = *mhp;
13807
13808 /* Map the mach header at start of fileset for now (vmaddr = 0) */
13809 ret = vm_map_kcfileset_segment(
13810 (vm_map_offset_t *)&base_mh, mach_header_map_size,
13811 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
13812
13813 if (ret != KERN_SUCCESS) {
13814 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
13815
13816 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13817 "Failed to map mach header of kc fileset with error %d", ret);
13818 return kOSKextReturnInvalidArgument;
13819 }
13820
13821 if (slidep) {
13822 /* Verify that it's an MH_FILESET */
13823 if (base_mh->filetype != MH_FILESET) {
13824 printf("Kext Log: mapKCTextSegment mach header filetype"
13825 " is not an MH_FILESET, it is %x", base_mh->filetype);
13826
13827 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13828 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
13829
13830 /* Unmap the mach header */
13831 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13832 return kOSKextReturnInvalidArgument;
13833 }
13834 }
13835
13836 /* Map the remaining pages of load commands */
13837 if (base_mh->sizeofcmds > mach_header_map_size) {
13838 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13839 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
13840
13841 /* Map the load commands */
13842 ret = vm_map_kcfileset_segment(
13843 &load_command_addr, load_command_map_size,
13844 (memory_object_control_t)control, file_offset + mach_header_map_size,
13845 (VM_PROT_READ | VM_PROT_WRITE));
13846
13847 if (ret != KERN_SUCCESS) {
13848 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
13849 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13850 "Failed to map load commands of kc fileset with error %d", ret);
13851
13852 /* Unmap the mach header */
13853 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13854 return kOSKextReturnInvalidArgument;
13855 }
13856 }
13857
13858 kernel_segment_command_t *text_seg;
13859 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
13860
13861 /* Calculate the slide and vm addr of mach header */
13862 if (slidep) {
13863 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
13864 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
13865 }
13866
13867 /* Cache the text segment size and file offset before unmapping */
13868 vm_map_offset_t text_segment_size = text_seg->vmsize;
13869 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
13870 vm_prot_t text_maxprot = text_seg->maxprot;
13871
13872 /* Unmap the first page and loadcommands and map the text segment */
13873 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
13874 assert(ret == KERN_SUCCESS);
13875
13876 if (load_command_map_size) {
13877 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
13878 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
13879 assert(ret == KERN_SUCCESS);
13880 }
13881
13882 /* Map the text segment at actual vm addr specified in fileset */
13883 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
13884 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
13885 if (ret != KERN_SUCCESS) {
13886 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
13887 "Failed to map Text segment of kc fileset with error %d", ret);
13888 return kOSKextReturnInvalidArgument;
13889 }
13890
13891 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
13892 return 0;
13893 }
13894
13895 /*********************************************************************
13896 * Assumes sKextLock is held.
13897 *********************************************************************/
13898 /* static */
13899 OSReturn
13900 OSKext::protectKCFileSet(
13901 kernel_mach_header_t *mh,
13902 kc_kind_t type)
13903 {
13904 vm_map_t kext_map = g_kext_map;
13905 kernel_segment_command_t * seg = NULL;
13906 vm_map_offset_t start = 0;
13907 vm_map_offset_t end = 0;
13908 vm_map_size_t size = 0;
13909 OSReturn ret = 0;
13910
13911 /* Set VM permissions */
13912 seg = firstsegfromheader((kernel_mach_header_t *)mh);
13913 while (seg) {
13914 start = round_page(seg->vmaddr);
13915 end = trunc_page(seg->vmaddr + seg->vmsize);
13916 size = end - start;
13917
13918 /*
13919 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
13920 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
13921 * for the Aux KC as well.
13922 */
13923 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
13924 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
13925 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
13926 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
13927 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
13928 ret = OSKext_protect((kernel_mach_header_t *)mh,
13929 kext_map, start, size, seg->maxprot, TRUE, type);
13930 if (ret != KERN_SUCCESS) {
13931 printf("OSKext protect failed with error %d", ret);
13932 return kOSKextReturnInvalidArgument;
13933 }
13934
13935 ret = OSKext_protect((kernel_mach_header_t *)mh,
13936 kext_map, start, size, seg->initprot, FALSE, type);
13937 if (ret != KERN_SUCCESS) {
13938 printf("OSKext protect failed with error %d", ret);
13939 return kOSKextReturnInvalidArgument;
13940 }
13941
13942 ret = OSKext_wire((kernel_mach_header_t *)mh,
13943 kext_map, start, end, seg->initprot, FALSE, type);
13944 if (ret != KERN_SUCCESS) {
13945 printf("OSKext wire failed with error %d", ret);
13946 return kOSKextReturnInvalidArgument;
13947 }
13948 }
13949
13950 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
13951 }
13952
13953 return 0;
13954 }
13955
13956 /*********************************************************************
13957 * Assumes sKextLock is held.
13958 *********************************************************************/
13959 /* static */
13960 void
13961 OSKext::freeKCFileSetcontrol(void)
13962 {
13963 PE_reset_all_kc_vp();
13964 }
13965
13966 /*********************************************************************
13967 * Assumes sKextLock is held.
13968 *
13969 * resetKCFileSetSegments: Kext start function expects data segment to
13970 * be pristine on every load, unmap the dirty segments on unload and
13971 * remap them from FileSet on disk. Remap all segments of kext since
13972 * fixups are done per kext and not per segment.
13973 *********************************************************************/
13974 OSReturn
13975 OSKext::resetKCFileSetSegments(void)
13976 {
13977 kernel_segment_command_t *seg = NULL;
13978 kernel_segment_command_t *text_seg;
13979 uint32_t text_fileoff;
13980 kernel_mach_header_t *k_mh = NULL;
13981 uintptr_t slide;
13982 struct vnode *vp = NULL;
13983 void *fileset_control = NULL;
13984 bool pageable = (kc_type == KCKindPageable);
13985 OSReturn err;
13986 kern_return_t kr;
13987
13988 /* Check the vnode reference is still available */
13989 vp = (struct vnode *)PE_get_kc_vp(kc_type);
13990 if (vp == NULL) {
13991 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
13992 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
13993 return kOSKextReturnInternalError;
13994 }
13995
13996 fileset_control = ubc_getobject(vp, 0);
13997 assert(fileset_control != NULL);
13998
13999 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
14000 "Kext %s resetting all segments", getIdentifierCString());
14001
14002 k_mh = (kernel_mach_header_t *)kmod_info->address;
14003 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
14004 text_fileoff = text_seg->fileoff;
14005 slide = PE_get_kc_slide(kc_type);
14006
14007 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
14008 while (seg) {
14009 if (seg->vmsize == 0) {
14010 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14011 continue;
14012 }
14013
14014 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
14015 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
14016 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
14017 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
14018 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14019 continue;
14020 }
14021
14022 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
14023 assert(kr == KERN_SUCCESS);
14024 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
14025 }
14026
14027 /* Unmap the text segment */
14028 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
14029 assert(kr == KERN_SUCCESS);
14030
14031 /* Map all the segments of the kext */
14032 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
14033 if (err) {
14034 panic("Could not reset segments of a mapped kext, error %x", err);
14035 }
14036
14037 /* Update address in kmod_info, since it has been reset */
14038 if (kmod_info->address) {
14039 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
14040 }
14041
14042 return 0;
14043 }
14044
14045 /*********************************************************************
14046 * Mechanism to track all segment mapping while mapping KC fileset.
14047 *********************************************************************/
14048
14049 struct kcfileset_map_entry {
14050 vm_map_offset_t me_start;
14051 vm_map_offset_t me_size;
14052 };
14053
14054 struct kcfileset_map_entry_list {
14055 int kme_list_count;
14056 int kme_list_index;
14057 struct kcfileset_map_entry kme_list[];
14058 };
14059
14060 #define KCFILESET_MAP_ENTRY_MAX (16380)
14061
14062 static void *
14063 allocate_kcfileset_map_entry_list(void)
14064 {
14065 struct kcfileset_map_entry_list *entry_list;
14066
14067 entry_list = kalloc_type(struct kcfileset_map_entry_list,
14068 struct kcfileset_map_entry, KCFILESET_MAP_ENTRY_MAX, Z_WAITOK_ZERO);
14069
14070 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
14071 entry_list->kme_list_index = 0;
14072 return entry_list;
14073 }
14074
14075 static void
14076 add_kcfileset_map_entry(
14077 void *map_entry_list,
14078 vm_map_offset_t start,
14079 vm_map_offset_t size)
14080 {
14081 if (map_entry_list == NULL) {
14082 return;
14083 }
14084
14085 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14086
14087 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
14088 panic("Ran out of map kc fileset list");
14089 }
14090
14091 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
14092 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
14093
14094 entry_list->kme_list_index++;
14095 }
14096
14097 static void
14098 deallocate_kcfileset_map_entry_list_and_unmap_entries(
14099 void *map_entry_list,
14100 boolean_t unmap_entries,
14101 bool pageable)
14102 {
14103 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
14104
14105 if (unmap_entries) {
14106 for (int i = 0; i < entry_list->kme_list_index; i++) {
14107 kern_return_t ret;
14108 ret = vm_unmap_kcfileset_segment(
14109 &(entry_list->kme_list[i].me_start),
14110 entry_list->kme_list[i].me_size);
14111 assert(ret == KERN_SUCCESS);
14112 }
14113
14114 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
14115 }
14116
14117 kfree_type(struct kcfileset_map_entry_list, struct kcfileset_map_entry,
14118 KCFILESET_MAP_ENTRY_MAX, entry_list);
14119 }
14120
14121 /*********************************************************************
14122 * Mechanism to map kext segment.
14123 *********************************************************************/
14124
14125 kern_return_t
14126 vm_map_kcfileset_segment(
14127 vm_map_offset_t *start,
14128 vm_map_offset_t size,
14129 void *control,
14130 vm_object_offset_t fileoffset,
14131 vm_prot_t max_prot)
14132 {
14133 vm_map_kernel_flags_t vmk_flags = {
14134 .vmf_fixed = true,
14135 .vmkf_no_copy_on_read = true,
14136 .vmkf_cs_enforcement_override = true,
14137 .vm_tag = VM_KERN_MEMORY_OSKEXT,
14138 };
14139 kern_return_t ret;
14140
14141 /* Add Write to max prot to allow fixups */
14142 max_prot = max_prot | VM_PROT_WRITE;
14143
14144 /*
14145 * Map the segments from file as COPY mappings to
14146 * make sure changes on disk to the file does not affect
14147 * mapped segments.
14148 */
14149 ret = vm_map_enter_mem_object_control(
14150 g_kext_map,
14151 start,
14152 size,
14153 (mach_vm_offset_t)0,
14154 vmk_flags,
14155 (memory_object_control_t)control,
14156 fileoffset,
14157 TRUE, /* copy */
14158 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
14159 VM_INHERIT_NONE);
14160
14161 return ret;
14162 }
14163
14164 kern_return_t
14165 vm_unmap_kcfileset_segment(
14166 vm_map_offset_t *start,
14167 vm_map_offset_t size)
14168 {
14169 return mach_vm_deallocate(g_kext_map, *start, size);
14170 }
14171
14172 #endif //(__x86_64__) || defined(__i386__)
14173
14174 /*********************************************************************
14175 * Assumes sKextLock is held.
14176 *********************************************************************/
14177 /* static */
14178 OSReturn
14179 OSKext::validateKCFileSetUUID(
14180 OSDictionary *infoDict,
14181 kc_kind_t type)
14182 {
14183 OSReturn ret = kOSReturnSuccess;
14184
14185 if (!kernelcache_uuid_valid) {
14186 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14187 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
14188 ret = kOSKextReturnInvalidArgument;
14189 goto finish;
14190 }
14191 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
14192 if (ret != 0) {
14193 goto finish;
14194 }
14195
14196 #if defined(__x86_64__) || defined(__i386__)
14197 /* Check if the Aux KC is prelinked to correct Pageable KC */
14198 if (type == KCKindAuxiliary) {
14199 if (!pageablekc_uuid_valid) {
14200 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14201 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
14202 ret = kOSKextReturnInvalidArgument;
14203 goto finish;
14204 }
14205 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
14206 if (ret != 0) {
14207 goto finish;
14208 }
14209 }
14210 #endif //(__x86_64__) || defined(__i386__)
14211
14212 printf("KextLog: Collection UUID matches with loaded KCs.\n");
14213 finish:
14214 return ret;
14215 }
14216
14217 /*********************************************************************
14218 * Assumes sKextLock is held.
14219 *********************************************************************/
14220 /* static */
14221 OSReturn
14222 OSKext::validateKCUUIDfromPrelinkInfo(
14223 uuid_t *loaded_kcuuid,
14224 kc_kind_t type,
14225 OSDictionary *infoDict,
14226 const char *uuid_key)
14227 {
14228 /* extract the UUID from the dictionary */
14229 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
14230 if (!prelinkinfoKCUUID) {
14231 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14232 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
14233 return kOSKextReturnInvalidArgument;
14234 }
14235
14236 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
14237 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14238 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
14239 return kOSKextReturnInvalidArgument;
14240 }
14241
14242 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
14243 prelinkinfoKCUUID->getLength())) {
14244 OSData *info_dict_uuid;
14245 uuid_string_t info_dict_uuid_str = {};
14246 uuid_string_t expected_uuid_str = {};
14247 uuid_string_t given_uuid_str = {};
14248 uuid_t given_uuid;
14249
14250 /* extract the KC UUID from the dictionary */
14251 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
14252 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
14253 uuid_t tmp_uuid;
14254 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
14255 uuid_unparse(tmp_uuid, info_dict_uuid_str);
14256 }
14257
14258 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
14259 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
14260 uuid_unparse(given_uuid, given_uuid_str);
14261
14262 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14263 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14264 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
14265 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
14266 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
14267 if (type == KCKindPageable && sPanicOnKCMismatch) {
14268 panic("System KC UUID %s linked against %s, but %s is loaded",
14269 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
14270 }
14271 return kOSKextReturnInvalidArgument;
14272 }
14273
14274 return 0;
14275 }
14276
14277 /*********************************************************************
14278 * Assumes sKextLock is held.
14279 *********************************************************************/
14280 /* static */
14281 OSReturn
14282 OSKext::dispatchResource(OSDictionary * requestDict)
14283 {
14284 OSReturn result = kOSReturnError;
14285 OSSharedPtr<OSDictionary> callbackRecord;
14286 OSNumber * requestTag = NULL; // do not release
14287 OSNumber * requestResult = NULL; // do not release
14288 OSData * dataObj = NULL; // do not release
14289 uint32_t dataLength = 0;
14290 const void * dataPtr = NULL; // do not free
14291 OSValueObject<OSKextRequestResourceCallback> * callbackWrapper = nullptr; // do not release
14292 OSKextRequestResourceCallback callback = NULL;
14293 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14294 void * context = NULL; // do not free
14295 OSSharedPtr<OSKext> callbackKext;
14296
14297 /* Get the args from the request. Right now we need the tag
14298 * to look up the callback record, and the result for invoking the callback.
14299 */
14300 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14301 kKextRequestArgumentRequestTagKey));
14302 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
14303 kKextRequestArgumentResultKey));
14304 if (!requestTag || !requestResult) {
14305 result = kOSKextReturnInvalidArgument;
14306 goto finish;
14307 }
14308
14309 /* Look for a callback record matching this request's tag.
14310 */
14311 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
14312 if (result != kOSReturnSuccess) {
14313 goto finish;
14314 }
14315
14316 /*****
14317 * Get the context pointer of the callback record (if there is one).
14318 */
14319 contextWrapper = OSDynamicCast(OSValueObject<void *>, _OSKextGetRequestArgument(
14320 callbackRecord.get(), kKextRequestArgumentContextKey));
14321 context = _OSKextExtractPointer(contextWrapper);
14322 if (contextWrapper && !context) {
14323 goto finish;
14324 }
14325
14326 callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14327 _OSKextGetRequestArgument(callbackRecord.get(),
14328 kKextRequestArgumentCallbackKey));
14329 callback = _OSKextExtractCallbackPointer(callbackWrapper);
14330 if (!callback) {
14331 goto finish;
14332 }
14333
14334 /* Check for a data obj. We might not have one and that's ok, that means
14335 * we didn't find the requested resource, and we still have to tell the
14336 * caller that via the callback.
14337 */
14338 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
14339 kKextRequestArgumentValueKey));
14340 if (dataObj) {
14341 dataPtr = dataObj->getBytesNoCopy();
14342 dataLength = dataObj->getLength();
14343 }
14344
14345 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
14346 if (!callbackKext) {
14347 OSKextLog(/* kext */ NULL,
14348 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14349 "Can't invoke callback for resource request; ");
14350 goto finish;
14351 }
14352 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
14353 OSKextLog(/* kext */ NULL,
14354 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
14355 "Can't invoke kext resource callback; ");
14356 goto finish;
14357 }
14358
14359 (void)callback(requestTag->unsigned32BitValue(),
14360 (OSReturn)requestResult->unsigned32BitValue(),
14361 dataPtr, dataLength, context);
14362
14363 result = kOSReturnSuccess;
14364
14365 finish:
14366 return result;
14367 }
14368
14369 /*********************************************************************
14370 * Assumes sKextLock is held.
14371 *********************************************************************/
14372 /* static */
14373 OSReturn
14374 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
14375 {
14376 OSSharedPtr<OSDictionary> missingIDs;
14377 OSArray *bundleIDList = NULL; // do not release
14378
14379 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
14380 requestDict, kKextRequestArgumentMissingBundleIDs));
14381 if (!bundleIDList) {
14382 return kOSKextReturnInvalidArgument;
14383 }
14384
14385 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
14386 if (!missingIDs) {
14387 return kOSKextReturnNoMemory;
14388 }
14389
14390 uint32_t count, i;
14391 count = bundleIDList->getCount();
14392 for (i = 0; i < count; i++) {
14393 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
14394 if (thisID) {
14395 missingIDs->setObject(thisID, kOSBooleanFalse);
14396 }
14397 }
14398
14399 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
14400
14401 return kOSReturnSuccess;
14402 }
14403
14404 /*********************************************************************
14405 * Assumes sKextLock is held.
14406 *********************************************************************/
14407 /* static */
14408 OSReturn
14409 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
14410 {
14411 bool loadable = true;
14412 if (!kextIdentifier) {
14413 return kOSKextReturnInvalidArgument;
14414 }
14415
14416 if (requestDict) {
14417 OSBoolean *loadableArg;
14418 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
14419 requestDict, kKextRequestArgumentBundleAvailability));
14420 /* If we find the "Bundle Available" arg, and it's false, then
14421 * mark the bundle ID as _not_ loadable
14422 */
14423 if (loadableArg && !loadableArg->getValue()) {
14424 loadable = false;
14425 }
14426 }
14427
14428 if (!sNonLoadableKextsByID) {
14429 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
14430 }
14431
14432 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
14433
14434 OSKextLog(/* kext */ NULL,
14435 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
14436 "KextLog: AuxKC bundle %s marked as %s",
14437 kextIdentifier->getCStringNoCopy(),
14438 (loadable ? "loadable" : "NOT loadable"));
14439
14440 return kOSReturnSuccess;
14441 }
14442
14443 /*********************************************************************
14444 *********************************************************************/
14445 /* static */
14446 void
14447 OSKext::invokeRequestCallback(
14448 OSDictionary * callbackRecord,
14449 OSReturn callbackResult)
14450 {
14451 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
14452 OSSharedPtr<OSNumber> resultNum;
14453
14454 if (!predicate) {
14455 goto finish;
14456 }
14457
14458 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
14459 8 * sizeof(callbackResult));
14460 if (!resultNum) {
14461 goto finish;
14462 }
14463
14464 /* Insert the result into the callback record and dispatch it as if it
14465 * were the reply coming down from user space.
14466 */
14467 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
14468 resultNum.get());
14469
14470 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
14471 /* This removes the pending callback record.
14472 */
14473 OSKext::dispatchResource(callbackRecord);
14474 }
14475
14476 finish:
14477 return;
14478 }
14479
14480 /*********************************************************************
14481 * Assumes sKextLock is held.
14482 *********************************************************************/
14483 /* static */
14484 OSReturn
14485 OSKext::cancelRequest(
14486 OSKextRequestTag requestTag,
14487 void ** contextOut)
14488 {
14489 OSReturn result = kOSKextReturnNoMemory;
14490 OSSharedPtr<OSDictionary> callbackRecord;
14491 OSValueObject<void *> * contextWrapper = nullptr; // do not release
14492
14493 IORecursiveLockLock(sKextLock);
14494 result = OSKext::dequeueCallbackForRequestTag(requestTag,
14495 callbackRecord);
14496 IORecursiveLockUnlock(sKextLock);
14497
14498 if (result == kOSReturnSuccess && contextOut) {
14499 contextWrapper = OSDynamicCast(OSValueObject<void *>,
14500 _OSKextGetRequestArgument(callbackRecord.get(),
14501 kKextRequestArgumentContextKey));
14502 *contextOut = _OSKextExtractPointer(contextWrapper);
14503 }
14504
14505 return result;
14506 }
14507
14508 /*********************************************************************
14509 * Assumes sKextLock is held.
14510 *********************************************************************/
14511 void
14512 OSKext::invokeOrCancelRequestCallbacks(
14513 OSReturn callbackResult,
14514 bool invokeFlag)
14515 {
14516 unsigned int count, i;
14517
14518 count = sRequestCallbackRecords->getCount();
14519 if (!count) {
14520 goto finish;
14521 }
14522
14523 i = count - 1;
14524 do {
14525 OSDictionary * request = OSDynamicCast(OSDictionary,
14526 sRequestCallbackRecords->getObject(i));
14527
14528 if (!request) {
14529 continue;
14530 }
14531 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14532 _OSKextGetRequestArgument(request,
14533 kKextRequestArgumentCallbackKey));
14534
14535 if (!callbackWrapper) {
14536 sRequestCallbackRecords->removeObject(i);
14537 continue;
14538 }
14539
14540 vm_address_t callbackAddress = (vm_address_t)
14541 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14542
14543 if ((kmod_info->address <= callbackAddress) &&
14544 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14545 if (invokeFlag) {
14546 /* This removes the callback record.
14547 */
14548 invokeRequestCallback(request, callbackResult);
14549 } else {
14550 sRequestCallbackRecords->removeObject(i);
14551 }
14552 }
14553 } while (i--);
14554
14555 finish:
14556 return;
14557 }
14558
14559 /*********************************************************************
14560 * Assumes sKextLock is held.
14561 *********************************************************************/
14562 uint32_t
14563 OSKext::countRequestCallbacks(void)
14564 {
14565 uint32_t result = 0;
14566 unsigned int count, i;
14567
14568 count = sRequestCallbackRecords->getCount();
14569 if (!count) {
14570 goto finish;
14571 }
14572
14573 i = count - 1;
14574 do {
14575 OSDictionary * request = OSDynamicCast(OSDictionary,
14576 sRequestCallbackRecords->getObject(i));
14577
14578 if (!request) {
14579 continue;
14580 }
14581 auto * callbackWrapper = OSDynamicCast(OSValueObject<OSKextRequestResourceCallback>,
14582 _OSKextGetRequestArgument(request,
14583 kKextRequestArgumentCallbackKey));
14584
14585 if (!callbackWrapper) {
14586 continue;
14587 }
14588
14589 vm_address_t callbackAddress = (vm_address_t)
14590 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
14591
14592 if ((kmod_info->address <= callbackAddress) &&
14593 (callbackAddress < (kmod_info->address + kmod_info->size))) {
14594 result++;
14595 }
14596 } while (i--);
14597
14598 finish:
14599 return result;
14600 }
14601
14602 /*********************************************************************
14603 *********************************************************************/
14604 static OSReturn
14605 _OSKextCreateRequest(
14606 const char * predicate,
14607 OSSharedPtr<OSDictionary> & requestR)
14608 {
14609 OSReturn result = kOSKextReturnNoMemory;
14610 OSSharedPtr<OSDictionary> request;
14611
14612 request = OSDictionary::withCapacity(2);
14613 if (!request) {
14614 goto finish;
14615 }
14616 result = _OSDictionarySetCStringValue(request.get(),
14617 kKextRequestPredicateKey, predicate);
14618 if (result != kOSReturnSuccess) {
14619 goto finish;
14620 }
14621 result = kOSReturnSuccess;
14622
14623 finish:
14624 if (result == kOSReturnSuccess) {
14625 requestR = os::move(request);
14626 }
14627
14628 return result;
14629 }
14630
14631 /*********************************************************************
14632 *********************************************************************/
14633 static OSString *
14634 _OSKextGetRequestPredicate(OSDictionary * requestDict)
14635 {
14636 return OSDynamicCast(OSString,
14637 requestDict->getObject(kKextRequestPredicateKey));
14638 }
14639
14640 /*********************************************************************
14641 *********************************************************************/
14642 static OSObject *
14643 _OSKextGetRequestArgument(
14644 OSDictionary * requestDict,
14645 const char * argName)
14646 {
14647 OSDictionary * args = OSDynamicCast(OSDictionary,
14648 requestDict->getObject(kKextRequestArgumentsKey));
14649 if (args) {
14650 return args->getObject(argName);
14651 }
14652 return NULL;
14653 }
14654
14655 /*********************************************************************
14656 *********************************************************************/
14657 static bool
14658 _OSKextSetRequestArgument(
14659 OSDictionary * requestDict,
14660 const char * argName,
14661 OSMetaClassBase * value)
14662 {
14663 OSDictionary * args = OSDynamicCast(OSDictionary,
14664 requestDict->getObject(kKextRequestArgumentsKey));
14665 OSSharedPtr<OSDictionary> newArgs;
14666 if (!args) {
14667 newArgs = OSDictionary::withCapacity(2);
14668 args = newArgs.get();
14669 if (!args) {
14670 goto finish;
14671 }
14672 requestDict->setObject(kKextRequestArgumentsKey, args);
14673 }
14674 if (args) {
14675 return args->setObject(argName, value);
14676 }
14677 finish:
14678 return false;
14679 }
14680
14681 /*********************************************************************
14682 *********************************************************************/
14683 template <typename T>
14684 static T *
14685 _OSKextExtractPointer(OSValueObject<T *> * wrapper)
14686 {
14687 if (!wrapper) {
14688 return nullptr;
14689 }
14690 return wrapper->getRef();
14691 }
14692
14693 /*********************************************************************
14694 *********************************************************************/
14695 static OSKextRequestResourceCallback
14696 _OSKextExtractCallbackPointer(OSValueObject<OSKextRequestResourceCallback> * wrapper)
14697 {
14698 if (!wrapper) {
14699 return nullptr;
14700 }
14701 return wrapper->getRef();
14702 }
14703
14704
14705 /*********************************************************************
14706 *********************************************************************/
14707 static OSReturn
14708 _OSDictionarySetCStringValue(
14709 OSDictionary * dict,
14710 const char * cKey,
14711 const char * cValue)
14712 {
14713 OSReturn result = kOSKextReturnNoMemory;
14714 OSSharedPtr<const OSSymbol> key;
14715 OSSharedPtr<OSString> value;
14716
14717 key = OSSymbol::withCString(cKey);
14718 value = OSString::withCString(cValue);
14719 if (!key || !value) {
14720 goto finish;
14721 }
14722 if (dict->setObject(key.get(), value.get())) {
14723 result = kOSReturnSuccess;
14724 }
14725
14726 finish:
14727 return result;
14728 }
14729
14730 /*********************************************************************
14731 *********************************************************************/
14732 static bool
14733 _OSArrayContainsCString(
14734 OSArray * array,
14735 const char * cString)
14736 {
14737 bool result = false;
14738 OSSharedPtr<const OSSymbol> symbol;
14739 uint32_t count, i;
14740
14741 if (!array || !cString) {
14742 goto finish;
14743 }
14744
14745 symbol = OSSymbol::withCStringNoCopy(cString);
14746 if (!symbol) {
14747 goto finish;
14748 }
14749
14750 count = array->getCount();
14751 for (i = 0; i < count; i++) {
14752 OSObject * thisObject = array->getObject(i);
14753 if (symbol->isEqualTo(thisObject)) {
14754 result = true;
14755 goto finish;
14756 }
14757 }
14758
14759 finish:
14760 return result;
14761 }
14762
14763 #if CONFIG_KXLD
14764 /*********************************************************************
14765 * We really only care about boot / system start up related kexts.
14766 * We return true if we're less than REBUILD_MAX_TIME since start up,
14767 * otherwise return false.
14768 *********************************************************************/
14769 bool
14770 _OSKextInPrelinkRebuildWindow(void)
14771 {
14772 static bool outside_the_window = false;
14773 AbsoluteTime my_abstime;
14774 UInt64 my_ns;
14775 SInt32 my_secs;
14776
14777 if (outside_the_window) {
14778 return false;
14779 }
14780 clock_get_uptime(&my_abstime);
14781 absolutetime_to_nanoseconds(my_abstime, &my_ns);
14782 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
14783 if (my_secs > REBUILD_MAX_TIME) {
14784 outside_the_window = true;
14785 return false;
14786 }
14787 return true;
14788 }
14789 #endif /* CONFIG_KXLD */
14790
14791 /*********************************************************************
14792 *********************************************************************/
14793 bool
14794 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
14795 {
14796 int unLoadedCount, i;
14797 bool result = false;
14798
14799 IORecursiveLockLock(sKextLock);
14800
14801 if (sUnloadedPrelinkedKexts == NULL) {
14802 goto finish;
14803 }
14804 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
14805 if (unLoadedCount == 0) {
14806 goto finish;
14807 }
14808
14809 for (i = 0; i < unLoadedCount; i++) {
14810 const OSSymbol * myBundleID; // do not release
14811
14812 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
14813 if (!myBundleID) {
14814 continue;
14815 }
14816 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
14817 result = true;
14818 break;
14819 }
14820 }
14821 finish:
14822 IORecursiveLockUnlock(sKextLock);
14823 return result;
14824 }
14825
14826 #if PRAGMA_MARK
14827 #pragma mark Personalities (IOKit Drivers)
14828 #endif
14829 /*********************************************************************
14830 *********************************************************************/
14831 /* static */
14832 OSSharedPtr<OSArray>
14833 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
14834 {
14835 OSSharedPtr<OSArray> result;
14836 OSSharedPtr<OSCollectionIterator> kextIterator;
14837 OSSharedPtr<OSArray> personalities;
14838
14839 OSString * kextID = NULL; // do not release
14840 OSKext * theKext = NULL; // do not release
14841
14842 IORecursiveLockLock(sKextLock);
14843
14844 /* Let's conservatively guess that any given kext has around 3
14845 * personalities for now.
14846 */
14847 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
14848 if (!result) {
14849 goto finish;
14850 }
14851
14852 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
14853 if (!kextIterator) {
14854 goto finish;
14855 }
14856
14857 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
14858 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
14859 if (theKext->flags.requireExplicitLoad) {
14860 OSKextLog(theKext,
14861 kOSKextLogDebugLevel |
14862 kOSKextLogLoadFlag,
14863 "Kext %s requires an explicit kextload; "
14864 "omitting its personalities.",
14865 theKext->getIdentifierCString());
14866 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
14867 personalities = theKext->copyPersonalitiesArray();
14868 if (!personalities) {
14869 continue;
14870 }
14871 result->merge(personalities.get());
14872 } else {
14873 // xxx - check for better place to put this log msg
14874 OSKextLog(theKext,
14875 kOSKextLogWarningLevel |
14876 kOSKextLogLoadFlag,
14877 "Kext %s is not loadable during safe boot; "
14878 "omitting its personalities.",
14879 theKext->getIdentifierCString());
14880 }
14881 }
14882
14883 finish:
14884 IORecursiveLockUnlock(sKextLock);
14885
14886 return result;
14887 }
14888
14889 /*********************************************************************
14890 *********************************************************************/
14891 /* static */
14892 void
14893 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
14894 {
14895 int numPersonalities = 0;
14896
14897 OSKextLog(/* kext */ NULL,
14898 kOSKextLogStepLevel |
14899 kOSKextLogLoadFlag,
14900 "Sending all eligible registered kexts' personalities "
14901 "to the IOCatalogue %s.",
14902 startMatching ? "and starting matching" : "but not starting matching");
14903
14904 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
14905 /* filterSafeBootFlag */ true);
14906
14907 if (personalities) {
14908 gIOCatalogue->addDrivers(personalities.get(), startMatching);
14909 numPersonalities = personalities->getCount();
14910 }
14911
14912 OSKextLog(/* kext */ NULL,
14913 kOSKextLogStepLevel |
14914 kOSKextLogLoadFlag,
14915 "%d kext personalit%s sent to the IOCatalogue; %s.",
14916 numPersonalities, numPersonalities > 0 ? "ies" : "y",
14917 startMatching ? "matching started" : "matching not started");
14918 return;
14919 }
14920
14921 /*********************************************************************
14922 * Do not make a deep copy, just convert the IOKitPersonalities dict
14923 * to an array for sending to the IOCatalogue.
14924 *********************************************************************/
14925 OSSharedPtr<OSArray>
14926 OSKext::copyPersonalitiesArray(void)
14927 {
14928 OSSharedPtr<OSArray> result;
14929 OSDictionary * personalities = NULL; // do not release
14930 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
14931
14932 OSString * personalityName = NULL; // do not release
14933 OSString * personalityBundleIdentifier = NULL; // do not release
14934
14935 personalities = OSDynamicCast(OSDictionary,
14936 getPropertyForHostArch(kIOKitPersonalitiesKey));
14937 if (!personalities) {
14938 goto finish;
14939 }
14940
14941 result = OSArray::withCapacity(personalities->getCount());
14942 if (!result) {
14943 goto finish;
14944 }
14945
14946 personalitiesIterator =
14947 OSCollectionIterator::withCollection(personalities);
14948 if (!personalitiesIterator) {
14949 goto finish;
14950 }
14951 while ((personalityName = OSDynamicCast(OSString,
14952 personalitiesIterator->getNextObject()))) {
14953 OSDictionary * personality = OSDynamicCast(OSDictionary,
14954 personalities->getObject(personalityName));
14955
14956 if (personality) {
14957 /******
14958 * If the personality doesn't have a CFBundleIdentifier, or if it
14959 * differs from the kext's, insert the kext's ID so we can find it.
14960 * The publisher ID is used to remove personalities from bundles
14961 * correctly.
14962 */
14963 personalityBundleIdentifier = OSDynamicCast(OSString,
14964 personality->getObject(kCFBundleIdentifierKey));
14965
14966 if (!personalityBundleIdentifier) {
14967 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
14968 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
14969 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
14970 }
14971 }
14972
14973 result->setObject(personality);
14974 }
14975
14976 finish:
14977 return result;
14978 }
14979
14980 /*********************************************************************
14981 * Might want to change this to a bool return?
14982 *********************************************************************/
14983 OSReturn
14984 OSKext::sendPersonalitiesToCatalog(
14985 bool startMatching,
14986 OSArray * personalityNames)
14987 {
14988 OSReturn result = kOSReturnSuccess;
14989 OSSharedPtr<OSArray> personalitiesToSend;
14990 OSDictionary * kextPersonalities = NULL; // do not release
14991 int count, i;
14992
14993 if (!sLoadEnabled) {
14994 OSKextLog(this,
14995 kOSKextLogErrorLevel |
14996 kOSKextLogLoadFlag,
14997 "Kext loading is disabled (attempt to start matching for kext %s).",
14998 getIdentifierCString());
14999 result = kOSKextReturnDisabled;
15000 goto finish;
15001 }
15002
15003 if (sSafeBoot && !isLoadableInSafeBoot()) {
15004 OSKextLog(this,
15005 kOSKextLogErrorLevel |
15006 kOSKextLogLoadFlag,
15007 "Kext %s is not loadable during safe boot; "
15008 "not sending personalities to the IOCatalogue.",
15009 getIdentifierCString());
15010 result = kOSKextReturnNotLoadable;
15011 goto finish;
15012 }
15013
15014 if (!personalityNames || !personalityNames->getCount()) {
15015 personalitiesToSend = copyPersonalitiesArray();
15016 } else {
15017 kextPersonalities = OSDynamicCast(OSDictionary,
15018 getPropertyForHostArch(kIOKitPersonalitiesKey));
15019 if (!kextPersonalities || !kextPersonalities->getCount()) {
15020 // not an error
15021 goto finish;
15022 }
15023 personalitiesToSend = OSArray::withCapacity(0);
15024 if (!personalitiesToSend) {
15025 result = kOSKextReturnNoMemory;
15026 goto finish;
15027 }
15028 count = personalityNames->getCount();
15029 for (i = 0; i < count; i++) {
15030 OSString * name = OSDynamicCast(OSString,
15031 personalityNames->getObject(i));
15032 if (!name) {
15033 continue;
15034 }
15035 OSDictionary * personality = OSDynamicCast(OSDictionary,
15036 kextPersonalities->getObject(name));
15037 if (personality) {
15038 personalitiesToSend->setObject(personality);
15039 }
15040 }
15041 }
15042 if (personalitiesToSend) {
15043 unsigned numPersonalities = personalitiesToSend->getCount();
15044 OSKextLog(this,
15045 kOSKextLogStepLevel |
15046 kOSKextLogLoadFlag,
15047 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
15048 getIdentifierCString(),
15049 numPersonalities,
15050 numPersonalities > 1 ? "ies" : "y",
15051 startMatching ? " and starting matching" : " but not starting matching");
15052 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
15053 }
15054 finish:
15055 return result;
15056 }
15057
15058 /*********************************************************************
15059 * xxx - We should allow removing the kext's declared personalities,
15060 * xxx - even with other bundle identifiers.
15061 *********************************************************************/
15062 void
15063 OSKext::removePersonalitiesFromCatalog(void)
15064 {
15065 OSSharedPtr<OSDictionary> personality;
15066
15067 personality = OSDictionary::withCapacity(1);
15068 if (!personality) {
15069 goto finish;
15070 }
15071 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
15072
15073 OSKextLog(this,
15074 kOSKextLogStepLevel |
15075 kOSKextLogLoadFlag,
15076 "Kext %s removing all personalities naming it from the IOCatalogue.",
15077 getIdentifierCString());
15078
15079 /* Have the IOCatalog remove all personalities matching this kext's
15080 * bundle ID and trigger matching anew.
15081 */
15082 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
15083
15084 finish:
15085 return;
15086 }
15087
15088 void
15089 OSKext::updatePersonalitiesInCatalog(OSArray *upgradedPersonalities)
15090 {
15091 if (!upgradedPersonalities || upgradedPersonalities->getCount() == 0) {
15092 return;
15093 }
15094
15095 OSSharedPtr<OSDictionary> personalityToRemove = OSDictionary::withCapacity(1);
15096 if (!personalityToRemove) {
15097 return;
15098 }
15099
15100 /*
15101 * Create a personality dictionary with just the bundleID.
15102 * We will remove any personality that has a matching bundleID,
15103 * irrespective of which other keys are present on the dictionary.
15104 */
15105 personalityToRemove->setObject(kCFBundleIdentifierKey, getIdentifier());
15106 gIOCatalogue->exchangeDrivers(personalityToRemove.get(), upgradedPersonalities, true);
15107 }
15108
15109 #if PRAGMA_MARK
15110 #pragma mark Logging
15111 #endif
15112 /*********************************************************************
15113 * Do not call any function that takes sKextLock here!
15114 *********************************************************************/
15115 /* static */
15116 OSKextLogSpec
15117 OSKext::setUserSpaceLogFilter(
15118 OSKextLogSpec newUserLogFilter,
15119 bool captureFlag)
15120 {
15121 OSKextLogSpec result;
15122 bool allocError = false;
15123
15124 /* Do not call any function that takes sKextLoggingLock during
15125 * this critical block. That means do logging after.
15126 */
15127 IOLockLock(sKextLoggingLock);
15128
15129 result = sUserSpaceKextLogFilter;
15130 sUserSpaceKextLogFilter = newUserLogFilter;
15131
15132 if (newUserLogFilter && captureFlag &&
15133 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
15134 // xxx - do some measurements for a good initial capacity?
15135 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
15136 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
15137
15138 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
15139 allocError = true;
15140 }
15141 }
15142
15143 IOLockUnlock(sKextLoggingLock);
15144
15145 /* If the config flag itself is changing, log the state change
15146 * going both ways, before setting up the user-space log arrays,
15147 * so that this is only logged in the kernel.
15148 */
15149 if (result != newUserLogFilter) {
15150 OSKextLog(/* kext */ NULL,
15151 kOSKextLogDebugLevel |
15152 kOSKextLogGeneralFlag,
15153 "User-space log flags changed from 0x%x to 0x%x.",
15154 result, newUserLogFilter);
15155 }
15156 if (allocError) {
15157 OSKextLog(/* kext */ NULL,
15158 kOSKextLogErrorLevel |
15159 kOSKextLogGeneralFlag,
15160 "Failed to allocate user-space log message arrays.");
15161 }
15162
15163 return result;
15164 }
15165
15166 /*********************************************************************
15167 * Do not call any function that takes sKextLock here!
15168 *********************************************************************/
15169 /* static */
15170 OSSharedPtr<OSArray>
15171 OSKext::clearUserSpaceLogFilter(void)
15172 {
15173 OSSharedPtr<OSArray> result;
15174 OSKextLogSpec oldLogFilter;
15175 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
15176
15177 /* Do not call any function that takes sKextLoggingLock during
15178 * this critical block. That means do logging after.
15179 */
15180 IOLockLock(sKextLoggingLock);
15181
15182 result = OSArray::withCapacity(2);
15183 if (result) {
15184 result->setObject(sUserSpaceLogSpecArray.get());
15185 result->setObject(sUserSpaceLogMessageArray.get());
15186 }
15187 sUserSpaceLogSpecArray.reset();
15188 sUserSpaceLogMessageArray.reset();
15189
15190 oldLogFilter = sUserSpaceKextLogFilter;
15191 sUserSpaceKextLogFilter = newLogFilter;
15192
15193 IOLockUnlock(sKextLoggingLock);
15194
15195 /* If the config flag itself is changing, log the state change
15196 * going both ways, after tearing down the user-space log
15197 * arrays, so this is only logged within the kernel.
15198 */
15199 if (oldLogFilter != newLogFilter) {
15200 OSKextLog(/* kext */ NULL,
15201 kOSKextLogDebugLevel |
15202 kOSKextLogGeneralFlag,
15203 "User-space log flags changed from 0x%x to 0x%x.",
15204 oldLogFilter, newLogFilter);
15205 }
15206
15207 return result;
15208 }
15209
15210
15211 /*********************************************************************
15212 * Do not call any function that takes sKextLock here!
15213 *********************************************************************/
15214 /* static */
15215 OSKextLogSpec
15216 OSKext::getUserSpaceLogFilter(void)
15217 {
15218 OSKextLogSpec result;
15219
15220 IOLockLock(sKextLoggingLock);
15221 result = sUserSpaceKextLogFilter;
15222 IOLockUnlock(sKextLoggingLock);
15223
15224 return result;
15225 }
15226
15227 /*********************************************************************
15228 * This function is called by OSMetaClass during kernel C++ setup.
15229 * Be careful what you access here; assume only OSKext::initialize()
15230 * has been called.
15231 *
15232 * Do not call any function that takes sKextLock here!
15233 *********************************************************************/
15234 #define VTRESET "\033[0m"
15235
15236 #define VTBOLD "\033[1m"
15237 #define VTUNDER "\033[4m"
15238
15239 #define VTRED "\033[31m"
15240 #define VTGREEN "\033[32m"
15241 #define VTYELLOW "\033[33m"
15242 #define VTBLUE "\033[34m"
15243 #define VTMAGENTA "\033[35m"
15244 #define VTCYAN "\033[36m"
15245
15246 inline const char *
15247 colorForFlags(OSKextLogSpec flags)
15248 {
15249 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
15250
15251 switch (logLevel) {
15252 case kOSKextLogErrorLevel:
15253 return VTRED VTBOLD;
15254 case kOSKextLogWarningLevel:
15255 return VTRED;
15256 case kOSKextLogBasicLevel:
15257 return VTYELLOW VTUNDER;
15258 case kOSKextLogProgressLevel:
15259 return VTYELLOW;
15260 case kOSKextLogStepLevel:
15261 return VTGREEN;
15262 case kOSKextLogDetailLevel:
15263 return VTCYAN;
15264 case kOSKextLogDebugLevel:
15265 return VTMAGENTA;
15266 default:
15267 return ""; // white
15268 }
15269 }
15270
15271 inline bool
15272 logSpecMatch(
15273 OSKextLogSpec msgLogSpec,
15274 OSKextLogSpec logFilter)
15275 {
15276 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
15277 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
15278 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
15279
15280 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
15281 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
15282 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
15283
15284 /* Explicit messages always get logged.
15285 */
15286 if (msgLevel == kOSKextLogExplicitLevel) {
15287 return true;
15288 }
15289
15290 /* Warnings and errors are logged regardless of the flags.
15291 */
15292 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
15293 return true;
15294 }
15295
15296 /* A verbose message that isn't for a logging-enabled kext and isn't global
15297 * does *not* get logged.
15298 */
15299 if (!msgKextGlobal && !filterKextGlobal) {
15300 return false;
15301 }
15302
15303 /* Warnings and errors are logged regardless of the flags.
15304 * All other messages must fit the flags and
15305 * have a level at or below the filter.
15306 *
15307 */
15308 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
15309 return true;
15310 }
15311 return false;
15312 }
15313
15314 extern "C" {
15315 void
15316 OSKextLog(
15317 OSKext * aKext,
15318 OSKextLogSpec msgLogSpec,
15319 const char * format, ...)
15320 {
15321 va_list argList;
15322
15323 va_start(argList, format);
15324 OSKextVLog(aKext, msgLogSpec, format, argList);
15325 va_end(argList);
15326 }
15327
15328 void
15329 OSKextVLog(
15330 OSKext * aKext,
15331 OSKextLogSpec msgLogSpec,
15332 const char * format,
15333 va_list srcArgList)
15334 {
15335 bool logForKernel = false;
15336 bool logForUser = false;
15337 va_list argList;
15338 char stackBuffer[120];
15339 uint32_t length = 0;
15340 char * allocBuffer = NULL; // must kfree
15341 OSSharedPtr<OSNumber> logSpecNum;
15342 OSSharedPtr<OSString> logString;
15343 char * buffer = stackBuffer; // do not free
15344
15345 IOLockLock(sKextLoggingLock);
15346
15347 /* Set the kext/global bit in the message spec if we have no
15348 * kext or if the kext requests logging.
15349 */
15350 if (!aKext || aKext->flags.loggingEnabled) {
15351 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
15352 }
15353
15354 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
15355 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15356 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
15357 }
15358
15359 if (!(logForKernel || logForUser)) {
15360 goto finish;
15361 }
15362
15363 /* No goto from here until past va_end()!
15364 */
15365 va_copy(argList, srcArgList);
15366 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
15367 va_end(argList);
15368
15369 if (length + 1 >= sizeof(stackBuffer)) {
15370 allocBuffer = (char *)kalloc_data_tag(length + 1,
15371 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
15372 if (!allocBuffer) {
15373 goto finish;
15374 }
15375
15376 /* No goto from here until past va_end()!
15377 */
15378 va_copy(argList, srcArgList);
15379 vsnprintf(allocBuffer, length + 1, format, argList);
15380 va_end(argList);
15381
15382 buffer = allocBuffer;
15383 }
15384
15385 /* If user space wants the log message, queue it up.
15386 */
15387 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
15388 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
15389 logString = OSString::withCString(buffer);
15390 if (logSpecNum && logString) {
15391 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
15392 sUserSpaceLogMessageArray->setObject(logString.get());
15393 }
15394 }
15395
15396 /* Always log messages from the kernel according to the kernel's
15397 * log flags.
15398 */
15399 if (logForKernel) {
15400 /* If we are in console mode and have a custom log filter,
15401 * colorize the log message.
15402 */
15403 if (sBootArgLogFilterFound) {
15404 const char * color = ""; // do not free
15405 color = colorForFlags(msgLogSpec);
15406 printf("%s%s%s\n", colorForFlags(msgLogSpec),
15407 buffer, color[0] ? VTRESET : "");
15408 } else {
15409 printf("%s\n", buffer);
15410 }
15411 }
15412
15413 finish:
15414 IOLockUnlock(sKextLoggingLock);
15415
15416 if (allocBuffer) {
15417 kfree_data(allocBuffer, length + 1);
15418 }
15419 return;
15420 }
15421
15422 #if KASLR_IOREG_DEBUG
15423
15424 #define IOLOG_INDENT( the_indention ) \
15425 { \
15426 int i; \
15427 for ( i = 0; i < (the_indention); i++ ) { \
15428 IOLog(" "); \
15429 } \
15430 }
15431
15432 extern vm_offset_t vm_kernel_stext;
15433 extern vm_offset_t vm_kernel_etext;
15434 extern mach_vm_offset_t kext_alloc_base;
15435 extern mach_vm_offset_t kext_alloc_max;
15436
15437 bool ScanForAddrInObject(OSObject * theObject,
15438 int indent );
15439
15440 bool
15441 ScanForAddrInObject(OSObject * theObject,
15442 int indent)
15443 {
15444 const OSMetaClass * myTypeID;
15445 OSSharedPtr<OSCollectionIterator> myIter;
15446 OSSymbol * myKey;
15447 OSObject * myValue;
15448 bool myResult = false;
15449
15450 if (theObject == NULL) {
15451 IOLog("%s: theObject is NULL \n",
15452 __FUNCTION__);
15453 return myResult;
15454 }
15455
15456 myTypeID = OSTypeIDInst(theObject);
15457
15458 if (myTypeID == OSTypeID(OSDictionary)) {
15459 OSDictionary * myDictionary;
15460
15461 myDictionary = OSDynamicCast(OSDictionary, theObject);
15462 myIter = OSCollectionIterator::withCollection( myDictionary );
15463 if (myIter == NULL) {
15464 return myResult;
15465 }
15466
15467 // !! reset the iterator
15468 myIter->reset();
15469
15470 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
15471 bool myTempResult;
15472
15473 myValue = myDictionary->getObject(myKey);
15474 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15475 if (myTempResult) {
15476 // if we ever get a true result return true
15477 myResult = true;
15478 IOLOG_INDENT(indent);
15479 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
15480 }
15481 }
15482
15483 // !! release the iterator
15484 myIter.reset();
15485 } else if (myTypeID == OSTypeID(OSArray)) {
15486 OSArray * myArray;
15487
15488 myArray = OSDynamicCast(OSArray, theObject);
15489 myIter = OSCollectionIterator::withCollection(myArray);
15490 if (myIter == NULL) {
15491 return myResult;
15492 }
15493 // !! reset the iterator
15494 myIter->reset();
15495
15496 while ((myValue = myIter->getNextObject())) {
15497 bool myTempResult;
15498 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
15499 if (myTempResult) {
15500 // if we ever get a true result return true
15501 myResult = true;
15502 IOLOG_INDENT(indent);
15503 IOLog("OSArray: \n");
15504 }
15505 }
15506 // !! release the iterator
15507 myIter.reset();
15508 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
15509 // should we look for addresses in strings?
15510 } else if (myTypeID == OSTypeID(OSData)) {
15511 void * * myPtrPtr;
15512 unsigned int myLen;
15513 OSData * myDataObj;
15514
15515 myDataObj = OSDynamicCast(OSData, theObject);
15516 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
15517 myLen = myDataObj->getLength();
15518
15519 if (myPtrPtr && myLen && myLen > 7) {
15520 int i;
15521 int myPtrCount = (myLen / sizeof(void *));
15522
15523 for (i = 0; i < myPtrCount; i++) {
15524 UInt64 numberValue = (UInt64) * (myPtrPtr);
15525
15526 if (kext_alloc_max != 0 &&
15527 numberValue >= kext_alloc_base &&
15528 numberValue < kext_alloc_max) {
15529 OSSharedPtr<OSKext> myKext;
15530 // IOLog("found OSData %p in kext map %p to %p \n",
15531 // *(myPtrPtr),
15532 // (void *) kext_alloc_base,
15533 // (void *) kext_alloc_max);
15534
15535 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
15536 if (myKext) {
15537 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
15538 *(myPtrPtr),
15539 myKext->getIdentifierCString());
15540 }
15541 myResult = true;
15542 }
15543 if (vm_kernel_etext != 0 &&
15544 numberValue >= vm_kernel_stext &&
15545 numberValue < vm_kernel_etext) {
15546 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
15547 *(myPtrPtr),
15548 (void *) vm_kernel_stext,
15549 (void *) vm_kernel_etext);
15550 myResult = true;
15551 }
15552 myPtrPtr++;
15553 }
15554 }
15555 } else if (myTypeID == OSTypeID(OSBoolean)) {
15556 // do nothing here...
15557 } else if (myTypeID == OSTypeID(OSNumber)) {
15558 OSNumber * number = OSDynamicCast(OSNumber, theObject);
15559
15560 UInt64 numberValue = number->unsigned64BitValue();
15561
15562 if (kext_alloc_max != 0 &&
15563 numberValue >= kext_alloc_base &&
15564 numberValue < kext_alloc_max) {
15565 OSSharedPtr<OSKext> myKext;
15566 IOLog("found OSNumber in kext map %p to %p \n",
15567 (void *) kext_alloc_base,
15568 (void *) kext_alloc_max);
15569 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15570
15571 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
15572 if (myKext) {
15573 IOLog("found in kext \"%s\" \n",
15574 myKext->getIdentifierCString());
15575 }
15576
15577 myResult = true;
15578 }
15579 if (vm_kernel_etext != 0 &&
15580 numberValue >= vm_kernel_stext &&
15581 numberValue < vm_kernel_etext) {
15582 IOLog("found OSNumber in kernel text segment %p to %p \n",
15583 (void *) vm_kernel_stext,
15584 (void *) vm_kernel_etext);
15585 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
15586 myResult = true;
15587 }
15588 }
15589 #if 0
15590 else {
15591 const OSMetaClass* myMetaClass = NULL;
15592
15593 myMetaClass = theObject->getMetaClass();
15594 if (myMetaClass) {
15595 IOLog("class %s \n", myMetaClass->getClassName());
15596 } else {
15597 IOLog("Unknown object \n" );
15598 }
15599 }
15600 #endif
15601
15602 return myResult;
15603 }
15604 #endif // KASLR_KEXT_DEBUG
15605 }; /* extern "C" */
15606
15607 #if PRAGMA_MARK
15608 #pragma mark Backtrace Dump & kmod_get_info() support
15609 #endif
15610 /*********************************************************************
15611 * This function must be safe to call in panic context.
15612 *********************************************************************/
15613 /* static */
15614 void
15615 OSKext::printKextsInBacktrace(
15616 vm_offset_t * addr __unused,
15617 unsigned int cnt __unused,
15618 int (* printf_func)(const char *fmt, ...) __unused,
15619 uint32_t flags __unused)
15620 {
15621 addr64_t summary_page = 0;
15622 addr64_t last_summary_page = 0;
15623
15624 if (kPrintKextsLock & flags) {
15625 if (!sKextSummariesLock) {
15626 return;
15627 }
15628 IOLockLock(sKextSummariesLock);
15629 }
15630
15631 if (!gLoadedKextSummaries) {
15632 (*printf_func)(" can't perform kext scan: no kext summary");
15633 goto finish;
15634 }
15635
15636 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
15637 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
15638 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
15639 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
15640 (*printf_func)(" can't perform kext scan: "
15641 "missing kext summary page %p", summary_page);
15642 goto finish;
15643 }
15644 }
15645
15646 foreachKextInBacktrace(addr, cnt, 0, ^(OSKextLoadedKextSummary *summary, uint32_t index) {
15647 if (index == 0 && !(kPrintKextsTerse & flags)) {
15648 (*printf_func)(" Kernel Extensions in backtrace:\n");
15649 }
15650
15651 printSummary(summary, printf_func, flags);
15652 });
15653
15654 finish:
15655 if (kPrintKextsLock & flags) {
15656 IOLockUnlock(sKextSummariesLock);
15657 }
15658
15659 return;
15660 }
15661
15662 void
15663 OSKext::foreachKextInBacktrace(
15664 vm_offset_t * addr,
15665 uint32_t cnt,
15666 uint32_t flags,
15667 void (^ handler)(OSKextLoadedKextSummary *summary, uint32_t index))
15668 {
15669 uint32_t n = 0;
15670
15671 if (kPrintKextsLock & flags) {
15672 if (!sKextSummariesLock) {
15673 return;
15674 }
15675 IOLockLock(sKextSummariesLock);
15676 }
15677
15678 for (uint32_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15679 OSKextLoadedKextSummary * summary;
15680
15681 summary = gLoadedKextSummaries->summaries + i;
15682 if (!summary->address) {
15683 continue;
15684 }
15685
15686 if (!summaryIsInBacktrace(summary, addr, cnt)) {
15687 continue;
15688 }
15689
15690 handler(summary, n++);
15691 }
15692
15693 if (kPrintKextsLock & flags) {
15694 IOLockUnlock(sKextSummariesLock);
15695 }
15696 }
15697
15698 /*********************************************************************
15699 * This function must be safe to call in panic context.
15700 *********************************************************************/
15701 /* static */
15702 boolean_t
15703 OSKext::summaryIsInBacktrace(
15704 OSKextLoadedKextSummary * summary,
15705 vm_offset_t * addr,
15706 unsigned int cnt)
15707 {
15708 u_int i = 0;
15709
15710 for (i = 0; i < cnt; i++) {
15711 vm_offset_t kscan_addr = addr[i];
15712 #if __has_feature(ptrauth_calls)
15713 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
15714 #endif /* __has_feature(ptrauth_calls) */
15715 if ((kscan_addr >= summary->text_exec_address) &&
15716 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
15717 return TRUE;
15718 }
15719 }
15720
15721 return FALSE;
15722 }
15723
15724 /*
15725 * Get the kext summary object for the kext where 'addr' lies. Must be called with
15726 * sKextSummariesLock held.
15727 */
15728 OSKextLoadedKextSummary *
15729 OSKext::summaryForAddress(uintptr_t addr)
15730 {
15731 #if __has_feature(ptrauth_calls)
15732 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15733 #endif /* __has_feature(ptrauth_calls) */
15734 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15735 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
15736 if (!summary->address) {
15737 continue;
15738 }
15739
15740 #if VM_MAPPED_KEXTS
15741 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
15742 * support split kexts, but we also may unmap the kexts, which can
15743 * race with the above codepath (see OSKext::unload). As such,
15744 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
15745 */
15746 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
15747 return summary;
15748 }
15749 #else
15750 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
15751 kernel_segment_command_t *seg;
15752
15753 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
15754 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
15755 return summary;
15756 }
15757 }
15758 #endif
15759 }
15760
15761 /* addr did not map to any kext */
15762 return NULL;
15763 }
15764
15765 /* static */
15766 void *
15767 OSKext::kextForAddress(const void *address)
15768 {
15769 OSKextActiveAccount * active;
15770 OSKext * kext = NULL;
15771 uint32_t baseIdx;
15772 uint32_t lim;
15773 uintptr_t addr = (uintptr_t) address;
15774 size_t i;
15775
15776 if (!addr) {
15777 return NULL;
15778 }
15779 #if __has_feature(ptrauth_calls)
15780 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
15781 #endif /* __has_feature(ptrauth_calls) */
15782
15783 if (sKextAccountsCount) {
15784 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
15785 // bsearch sKextAccounts list
15786 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15787 active = &sKextAccounts[baseIdx + (lim >> 1)];
15788 if ((addr >= active->address) && (addr < active->address_end)) {
15789 kext = active->account->kext;
15790 if (kext && kext->kmod_info) {
15791 lck_ticket_unlock(sKextAccountsLock);
15792 return (void *)kext->kmod_info->address;
15793 }
15794 break;
15795 } else if (addr > active->address) {
15796 // move right
15797 baseIdx += (lim >> 1) + 1;
15798 lim--;
15799 }
15800 // else move left
15801 }
15802 lck_ticket_unlock(sKextAccountsLock);
15803 }
15804 if (kernel_text_contains(addr)) {
15805 return (void *)&_mh_execute_header;
15806 }
15807 if (gLoadedKextSummaries) {
15808 IOLockLock(sKextSummariesLock);
15809 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
15810 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
15811 if (addr >= summary->address && addr < summary->address + summary->size) {
15812 void *kextAddress = (void *)summary->address;
15813 IOLockUnlock(sKextSummariesLock);
15814 return kextAddress;
15815 }
15816 }
15817 IOLockUnlock(sKextSummariesLock);
15818 }
15819
15820 return NULL;
15821 }
15822
15823 /* static */
15824 kern_return_t
15825 OSKext::summaryForAddressExt(
15826 const void * address,
15827 OSKextLoadedKextSummary * summary)
15828 {
15829 kern_return_t result = KERN_FAILURE;
15830 const OSKextLoadedKextSummary * foundSummary = NULL;
15831
15832 /*
15833 * This needs to be safe to call even before the lock has been initialized
15834 * in OSKext::initialize(), as we might get here from the ksancov runtime
15835 * when instrumenting XNU itself with sanitizer coverage.
15836 */
15837 if (!sKextSummariesLock) {
15838 return result;
15839 }
15840
15841 IOLockLock(sKextSummariesLock);
15842 if (gLoadedKextSummaries) {
15843 foundSummary = summaryForAddress((uintptr_t)address);
15844 if (foundSummary) {
15845 memcpy(summary, foundSummary, sizeof(*summary));
15846 result = KERN_SUCCESS;
15847 } else {
15848 result = KERN_NOT_FOUND;
15849 }
15850 }
15851 IOLockUnlock(sKextSummariesLock);
15852
15853 return result;
15854 }
15855
15856 /*
15857 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
15858 * Safe to call in panic context.
15859 */
15860 static OSKextLoadedKextSummary *
15861 findSummary(uint32_t tagID)
15862 {
15863 OSKextLoadedKextSummary * summary;
15864 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
15865 summary = gLoadedKextSummaries->summaries + i;
15866 if (summary->loadTag == tagID) {
15867 return summary;
15868 }
15869 }
15870 return NULL;
15871 }
15872
15873 /*********************************************************************
15874 * This function must be safe to call in panic context.
15875 *********************************************************************/
15876 void
15877 OSKext::printSummary(
15878 OSKextLoadedKextSummary * summary,
15879 int (* printf_func)(const char *fmt, ...),
15880 uint32_t flags)
15881 {
15882 kmod_reference_t * kmod_ref = NULL;
15883 uuid_string_t uuid;
15884 char version[kOSKextVersionMaxLength];
15885 uint64_t tmpAddr;
15886 uint64_t tmpSize;
15887 OSKextLoadedKextSummary *dependencySummary;
15888
15889 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
15890 strlcpy(version, "unknown version", sizeof(version));
15891 }
15892 (void) uuid_unparse(summary->uuid, uuid);
15893
15894 #if defined(__arm__) || defined(__arm64__)
15895 tmpAddr = summary->text_exec_address;
15896 tmpSize = summary->text_exec_size;
15897 #else
15898 tmpAddr = summary->address;
15899 tmpSize = summary->size;
15900 #endif
15901 if (kPrintKextsUnslide & flags) {
15902 tmpAddr = ml_static_unslide(tmpAddr);
15903 }
15904 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
15905 (kPrintKextsTerse & flags) ? "" : " ",
15906 summary->name, version, uuid,
15907 tmpAddr, tmpAddr + tmpSize - 1);
15908
15909 if (kPrintKextsTerse & flags) {
15910 return;
15911 }
15912
15913 /* print dependency info */
15914 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
15915 kmod_ref;
15916 kmod_ref = kmod_ref->next) {
15917 kmod_info_t * rinfo;
15918
15919 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
15920 (*printf_func)(" kmod dependency scan stopped "
15921 "due to missing dependency page: %p\n",
15922 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
15923 break;
15924 }
15925 rinfo = kmod_ref->info;
15926
15927 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
15928 (*printf_func)(" kmod dependency scan stopped "
15929 "due to missing kmod page: %p\n",
15930 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
15931 break;
15932 }
15933
15934 if (!rinfo->address) {
15935 continue; // skip fake entries for built-ins
15936 }
15937
15938 dependencySummary = findSummary(rinfo->id);
15939 uuid[0] = 0x00;
15940 tmpAddr = rinfo->address;
15941 tmpSize = rinfo->size;
15942 if (dependencySummary) {
15943 (void) uuid_unparse(dependencySummary->uuid, uuid);
15944 #if defined(__arm__) || defined(__arm64__)
15945 tmpAddr = dependencySummary->text_exec_address;
15946 tmpSize = dependencySummary->text_exec_size;
15947 #endif
15948 }
15949
15950 if (kPrintKextsUnslide & flags) {
15951 tmpAddr = ml_static_unslide(tmpAddr);
15952 }
15953 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
15954 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
15955 }
15956 return;
15957 }
15958
15959
15960 #if !defined(__arm__) && !defined(__arm64__)
15961 /*******************************************************************************
15962 * substitute() looks at an input string (a pointer within a larger buffer)
15963 * for a match to a substring, and on match it writes the marker & substitution
15964 * character to an output string, updating the scan (from) and
15965 * output (to) indexes as appropriate.
15966 *******************************************************************************/
15967 static int substitute(
15968 const char * scan_string,
15969 char * string_out,
15970 uint32_t * to_index,
15971 uint32_t * from_index,
15972 const char * substring,
15973 char marker,
15974 char substitution);
15975
15976 /* string_out must be at least KMOD_MAX_NAME bytes.
15977 */
15978 static int
15979 substitute(
15980 const char * scan_string,
15981 char * string_out,
15982 uint32_t * to_index,
15983 uint32_t * from_index,
15984 const char * substring,
15985 char marker,
15986 char substitution)
15987 {
15988 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
15989
15990 /* On a substring match, append the marker (if there is one) and then
15991 * the substitution character, updating the output (to) index accordingly.
15992 * Then update the input (from) length by the length of the substring
15993 * that got replaced.
15994 */
15995 if (!strncmp(scan_string, substring, substring_length)) {
15996 if (marker) {
15997 string_out[(*to_index)++] = marker;
15998 }
15999 string_out[(*to_index)++] = substitution;
16000 (*from_index) += substring_length;
16001 return 1;
16002 }
16003 return 0;
16004 }
16005
16006 /*******************************************************************************
16007 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
16008 * KMOD_MAX_NAME characters and performs various substitutions of common
16009 * prefixes & substrings as defined by tables in kext_panic_report.h.
16010 *******************************************************************************/
16011 static void compactIdentifier(
16012 const char * identifier,
16013 char * identifier_out,
16014 char ** identifier_out_end);
16015
16016 static void
16017 compactIdentifier(
16018 const char * identifier,
16019 char * identifier_out,
16020 char ** identifier_out_end)
16021 {
16022 uint32_t from_index, to_index;
16023 uint32_t scan_from_index = 0;
16024 uint32_t scan_to_index = 0;
16025 subs_entry_t * subs_entry = NULL;
16026 int did_sub = 0;
16027
16028 from_index = to_index = 0;
16029 identifier_out[0] = '\0';
16030
16031 /* Replace certain identifier prefixes with shorter @+character sequences.
16032 * Check the return value of substitute() so we only replace the prefix.
16033 */
16034 for (subs_entry = &kext_identifier_prefix_subs[0];
16035 subs_entry->substring && !did_sub;
16036 subs_entry++) {
16037 did_sub = substitute(identifier, identifier_out,
16038 &scan_to_index, &scan_from_index,
16039 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
16040 }
16041 did_sub = 0;
16042
16043 /* Now scan through the identifier looking for the common substrings
16044 * and replacing them with shorter !+character sequences via substitute().
16045 */
16046 for (/* see above */;
16047 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
16048 /* see loop */) {
16049 const char * scan_string = &identifier[scan_from_index];
16050
16051 did_sub = 0;
16052
16053 if (scan_from_index) {
16054 for (subs_entry = &kext_identifier_substring_subs[0];
16055 subs_entry->substring && !did_sub;
16056 subs_entry++) {
16057 did_sub = substitute(scan_string, identifier_out,
16058 &scan_to_index, &scan_from_index,
16059 subs_entry->substring, '!', subs_entry->substitute);
16060 }
16061 }
16062
16063 /* If we didn't substitute, copy the input character to the output.
16064 */
16065 if (!did_sub) {
16066 identifier_out[scan_to_index++] = identifier[scan_from_index++];
16067 }
16068 }
16069
16070 identifier_out[scan_to_index] = '\0';
16071 if (identifier_out_end) {
16072 *identifier_out_end = &identifier_out[scan_to_index];
16073 }
16074
16075 return;
16076 }
16077 #endif /* !defined(__arm__) && !defined(__arm64__) */
16078
16079 /*******************************************************************************
16080 * assemble_identifier_and_version() adds to a string buffer a compacted
16081 * bundle identifier followed by a version string.
16082 *******************************************************************************/
16083
16084 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
16085 */
16086 static size_t assemble_identifier_and_version(
16087 kmod_info_t * kmod_info,
16088 char * identPlusVers,
16089 size_t bufSize);
16090
16091 static size_t
16092 assemble_identifier_and_version(
16093 kmod_info_t * kmod_info,
16094 char * identPlusVers,
16095 size_t bufSize)
16096 {
16097 size_t result = 0;
16098
16099 #if defined(__arm__) || defined(__arm64__)
16100 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
16101 #else
16102 compactIdentifier(kmod_info->name, identPlusVers, NULL);
16103 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
16104 #endif
16105 identPlusVers[result++] = '\t'; // increment for real char
16106 identPlusVers[result] = '\0'; // don't increment for nul char
16107 result = strlcat(identPlusVers, kmod_info->version, bufSize);
16108 if (result >= bufSize) {
16109 identPlusVers[bufSize - 1] = '\0';
16110 result = bufSize - 1;
16111 }
16112
16113 return result;
16114 }
16115
16116 /*******************************************************************************
16117 * Assumes sKextLock is held.
16118 *******************************************************************************/
16119 /* static */
16120 int
16121 OSKext::saveLoadedKextPanicListTyped(
16122 const char * prefix,
16123 int invertFlag,
16124 int libsFlag,
16125 char * paniclist,
16126 uint32_t list_size)
16127 {
16128 int result = -1;
16129 unsigned int count, i;
16130
16131 count = sLoadedKexts->getCount();
16132 if (!count) {
16133 goto finish;
16134 }
16135
16136 i = count - 1;
16137 do {
16138 OSObject * rawKext = sLoadedKexts->getObject(i);
16139 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
16140 int match;
16141 size_t identPlusVersLength;
16142 size_t tempLen;
16143 char identPlusVers[2 * KMOD_MAX_NAME];
16144
16145 if (!rawKext) {
16146 printf("OSKext::saveLoadedKextPanicListTyped - "
16147 "NULL kext in loaded kext list; continuing\n");
16148 continue;
16149 }
16150
16151 if (!theKext) {
16152 printf("OSKext::saveLoadedKextPanicListTyped - "
16153 "Kext type cast failed in loaded kext list; continuing\n");
16154 continue;
16155 }
16156
16157 /* Skip all built-in kexts.
16158 */
16159 if (theKext->isKernelComponent()) {
16160 continue;
16161 }
16162
16163 kmod_info_t * kmod_info = theKext->kmod_info;
16164
16165 /* Filter for kmod name (bundle identifier).
16166 */
16167 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
16168 if ((match && invertFlag) || (!match && !invertFlag)) {
16169 continue;
16170 }
16171
16172 /* Filter for libraries (kexts that have a compatible version).
16173 */
16174 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
16175 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
16176 continue;
16177 }
16178
16179 if (!kmod_info ||
16180 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
16181 printf("kext scan stopped due to missing kmod_info page: %p\n",
16182 kmod_info);
16183 goto finish;
16184 }
16185
16186 identPlusVersLength = assemble_identifier_and_version(kmod_info,
16187 identPlusVers,
16188 sizeof(identPlusVers));
16189 if (!identPlusVersLength) {
16190 printf("error saving loaded kext info\n");
16191 goto finish;
16192 }
16193
16194 /* make sure everything fits and we null terminate.
16195 */
16196 tempLen = strlcat(paniclist, identPlusVers, list_size);
16197 if (tempLen >= list_size) {
16198 // panic list is full, keep it and null terminate
16199 paniclist[list_size - 1] = 0x00;
16200 result = 0;
16201 goto finish;
16202 }
16203 tempLen = strlcat(paniclist, "\n", list_size);
16204 if (tempLen >= list_size) {
16205 // panic list is full, keep it and null terminate
16206 paniclist[list_size - 1] = 0x00;
16207 result = 0;
16208 goto finish;
16209 }
16210 } while (i--);
16211
16212 result = 0;
16213 finish:
16214
16215 return result;
16216 }
16217
16218 /*********************************************************************
16219 *********************************************************************/
16220 /* static */
16221 void
16222 OSKext::saveLoadedKextPanicList(void)
16223 {
16224 char * newlist = NULL;
16225 uint32_t newlist_size = 0;
16226
16227 newlist_size = KEXT_PANICLIST_SIZE;
16228 newlist = (char *)kalloc_data_tag(newlist_size,
16229 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
16230
16231 if (!newlist) {
16232 OSKextLog(/* kext */ NULL,
16233 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
16234 "Couldn't allocate kext panic log buffer.");
16235 goto finish;
16236 }
16237
16238 newlist[0] = '\0';
16239
16240 // non-"com.apple." kexts
16241 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
16242 /* libs? */ -1, newlist, newlist_size) != 0) {
16243 goto finish;
16244 }
16245 // "com.apple." nonlibrary kexts
16246 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16247 /* libs? */ 0, newlist, newlist_size) != 0) {
16248 goto finish;
16249 }
16250 // "com.apple." library kexts
16251 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
16252 /* libs? */ 1, newlist, newlist_size) != 0) {
16253 goto finish;
16254 }
16255
16256 if (loaded_kext_paniclist) {
16257 kfree_data(loaded_kext_paniclist, loaded_kext_paniclist_size);
16258 }
16259 loaded_kext_paniclist = newlist;
16260 newlist = NULL;
16261 loaded_kext_paniclist_size = newlist_size;
16262
16263 finish:
16264 if (newlist) {
16265 kfree_data(newlist, newlist_size);
16266 }
16267 return;
16268 }
16269
16270 /*********************************************************************
16271 * Assumes sKextLock is held.
16272 *********************************************************************/
16273 void
16274 OSKext::savePanicString(bool isLoading)
16275 {
16276 u_long len;
16277
16278 if (!kmod_info) {
16279 return; // do not goto finish here b/c of lock
16280 }
16281
16282 len = assemble_identifier_and_version( kmod_info,
16283 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
16284 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
16285 if (!len) {
16286 printf("error saving unloaded kext info\n");
16287 goto finish;
16288 }
16289
16290 if (isLoading) {
16291 last_loaded_strlen = len;
16292 last_loaded_address = (void *)kmod_info->address;
16293 last_loaded_size = kmod_info->size;
16294 clock_get_uptime(&last_loaded_timestamp);
16295 } else {
16296 last_unloaded_strlen = len;
16297 last_unloaded_address = (void *)kmod_info->address;
16298 last_unloaded_size = kmod_info->size;
16299 clock_get_uptime(&last_unloaded_timestamp);
16300 }
16301
16302 finish:
16303 return;
16304 }
16305
16306 /*********************************************************************
16307 *********************************************************************/
16308 /* static */
16309 void
16310 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
16311 {
16312 if (last_loaded_strlen) {
16313 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
16314 AbsoluteTime_to_scalar(&last_loaded_timestamp),
16315 last_loaded_strlen, last_loaded_str_buf,
16316 last_loaded_address, last_loaded_size);
16317 }
16318
16319 if (last_unloaded_strlen) {
16320 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
16321 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
16322 last_unloaded_strlen, last_unloaded_str_buf,
16323 last_unloaded_address, last_unloaded_size);
16324 }
16325
16326 printf_func("loaded kexts:\n");
16327 if (loaded_kext_paniclist &&
16328 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
16329 loaded_kext_paniclist[0]) {
16330 printf_func("%.*s",
16331 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
16332 loaded_kext_paniclist);
16333 } else {
16334 printf_func("(none)\n");
16335 }
16336 return;
16337 }
16338
16339 /*********************************************************************
16340 * Assumes sKextLock is held.
16341 *********************************************************************/
16342 /* static */
16343 void
16344 OSKext::updateLoadedKextSummaries(void)
16345 {
16346 kern_return_t result = KERN_FAILURE;
16347 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
16348 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
16349 OSKext *aKext;
16350 vm_map_offset_t start;
16351 size_t summarySize = 0;
16352 size_t size;
16353 u_int count;
16354 u_int maxKexts;
16355 u_int i, j;
16356 OSKextActiveAccount * accountingList;
16357 OSKextActiveAccount * prevAccountingList;
16358 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
16359
16360 prevAccountingList = NULL;
16361 prevAccountingListCount = 0;
16362
16363 #if DEVELOPMENT || DEBUG
16364 if (IORecursiveLockHaveLock(sKextLock) == false) {
16365 panic("sKextLock must be held");
16366 }
16367 #endif
16368
16369 IOLockLock(sKextSummariesLock);
16370
16371 count = sLoadedKexts->getCount();
16372 for (i = 0, maxKexts = 0; i < count; ++i) {
16373 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16374 maxKexts += (aKext && (aKext->isExecutable() || aKext->isSpecialKernelBinary()));
16375 }
16376
16377 if (!maxKexts) {
16378 goto finish;
16379 }
16380 if (maxKexts < kOSKextTypicalLoadCount) {
16381 maxKexts = kOSKextTypicalLoadCount;
16382 }
16383
16384 /* Calculate the size needed for the new summary headers.
16385 */
16386
16387 size = sizeof(*gLoadedKextSummaries);
16388 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
16389 size = round_page(size);
16390
16391 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
16392 if (gLoadedKextSummaries) {
16393 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
16394 gLoadedKextSummaries = NULL;
16395 gLoadedKextSummariesTimestamp = mach_absolute_time();
16396 sLoadedKextSummariesAllocSize = 0;
16397 }
16398 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size,
16399 KMA_DATA, VM_KERN_MEMORY_OSKEXT);
16400 if (result != KERN_SUCCESS) {
16401 goto finish;
16402 }
16403 summaryHeader = summaryHeaderAlloc;
16404 summarySize = size;
16405 } else {
16406 summaryHeader = gLoadedKextSummaries;
16407 summarySize = sLoadedKextSummariesAllocSize;
16408
16409 start = (vm_map_offset_t) summaryHeader;
16410 result = mach_vm_protect(kernel_map,
16411 start,
16412 summarySize,
16413 false,
16414 VM_PROT_DEFAULT);
16415 if (result != KERN_SUCCESS) {
16416 goto finish;
16417 }
16418 }
16419
16420 /* Populate the summary header.
16421 */
16422
16423 bzero(summaryHeader, summarySize);
16424 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
16425 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
16426
16427 /* Populate each kext summary.
16428 */
16429
16430 count = sLoadedKexts->getCount();
16431 accountingListAlloc = 0;
16432 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16433 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16434 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16435 continue;
16436 }
16437
16438 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
16439 summaryHeader->numSummaries++;
16440 accountingListAlloc++;
16441 }
16442
16443 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
16444 accountingListCount = 0;
16445 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
16446 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
16447 if (!aKext || (!aKext->isExecutable() && !aKext->isSpecialKernelBinary())) {
16448 continue;
16449 }
16450
16451 OSKextActiveAccount activeAccount;
16452 aKext->updateActiveAccount(&activeAccount);
16453 // order by address
16454 for (idx = 0; idx < accountingListCount; idx++) {
16455 if (activeAccount.address < accountingList[idx].address) {
16456 break;
16457 }
16458 }
16459 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
16460 accountingList[idx] = activeAccount;
16461 accountingListCount++;
16462 }
16463 assert(accountingListCount == accountingListAlloc);
16464 /* Write protect the buffer and move it into place.
16465 */
16466
16467 start = (vm_map_offset_t) summaryHeader;
16468
16469 result = mach_vm_protect(kernel_map, start, summarySize, false, VM_PROT_READ);
16470 if (result != KERN_SUCCESS) {
16471 goto finish;
16472 }
16473
16474 gLoadedKextSummaries = summaryHeader;
16475 gLoadedKextSummariesTimestamp = mach_absolute_time();
16476 sLoadedKextSummariesAllocSize = summarySize;
16477 summaryHeaderAlloc = NULL;
16478
16479 /* Call the magic breakpoint function through a static function pointer so
16480 * the compiler can't optimize the function away.
16481 */
16482 if (sLoadedKextSummariesUpdated) {
16483 (*sLoadedKextSummariesUpdated)();
16484 }
16485
16486 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16487 prevAccountingList = sKextAccounts;
16488 prevAccountingListCount = sKextAccountsCount;
16489 sKextAccounts = accountingList;
16490 sKextAccountsCount = accountingListCount;
16491 lck_ticket_unlock(sKextAccountsLock);
16492
16493 finish:
16494 IOLockUnlock(sKextSummariesLock);
16495
16496 /* If we had to allocate a new buffer but failed to generate the summaries,
16497 * free that now.
16498 */
16499 if (summaryHeaderAlloc) {
16500 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
16501 }
16502 if (prevAccountingList) {
16503 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
16504 }
16505
16506 return;
16507 }
16508
16509 /*********************************************************************
16510 *********************************************************************/
16511 void
16512 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
16513 {
16514 OSSharedPtr<OSData> uuid;
16515
16516 strlcpy(summary->name, getIdentifierCString(),
16517 sizeof(summary->name));
16518
16519 uuid = copyUUID();
16520 if (uuid) {
16521 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
16522 }
16523
16524 if (flags.builtin) {
16525 // this value will stop lldb from parsing the mach-o header
16526 // summary->address = UINT64_MAX;
16527 // summary->size = 0;
16528 summary->address = kmod_info->address;
16529 summary->size = kmod_info->size;
16530 } else {
16531 summary->address = kmod_info->address;
16532 summary->size = kmod_info->size;
16533 }
16534 summary->version = getVersion();
16535 summary->loadTag = kmod_info->id;
16536 summary->flags = 0;
16537 summary->reference_list = (uint64_t) kmod_info->reference_list;
16538
16539 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
16540 if (summary->text_exec_address == 0) {
16541 // Fallback to __TEXT
16542 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
16543 }
16544
16545 /**
16546 * If the addresses within the Mach-O are unslid, then manually slide any
16547 * addresses coming from the Mach-O as higher layer software using these
16548 * summaries expects a slid address here.
16549 */
16550 if (flags.unslidMachO) {
16551 summary->text_exec_address = (uint64_t) ml_static_slide((vm_offset_t) summary->text_exec_address);
16552 }
16553
16554 return;
16555 }
16556
16557 /*********************************************************************
16558 *********************************************************************/
16559
16560 void
16561 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
16562 {
16563 kernel_mach_header_t *hdr = NULL;
16564 kernel_segment_command_t *seg = NULL;
16565
16566 bzero(accountp, sizeof(*accountp));
16567
16568 hdr = (kernel_mach_header_t *)kmod_info->address;
16569 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
16570 /*
16571 * If this kext supports split segments (or is in a new
16572 * MH_FILESET kext collection), use the first
16573 * executable segment as the range for instructions
16574 * (and thus for backtracing.
16575 */
16576 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
16577 if (seg->initprot & VM_PROT_EXECUTE) {
16578 break;
16579 }
16580 }
16581 }
16582 if (seg) {
16583 accountp->address = seg->vmaddr;
16584 if (accountp->address) {
16585 accountp->address_end = seg->vmaddr + seg->vmsize;
16586 }
16587 } else {
16588 /* For non-split kexts and for kexts without executable
16589 * segments, just use the kmod_info range (as the kext
16590 * is either all in one range or should not show up in
16591 * instruction backtraces).
16592 */
16593 accountp->address = kmod_info->address;
16594 if (accountp->address) {
16595 accountp->address_end = kmod_info->address + kmod_info->size;
16596 }
16597 }
16598
16599 accountp->account = this->account;
16600 }
16601
16602 bool
16603 OSKext::isDriverKit(void)
16604 {
16605 OSString *bundleType;
16606
16607 if (infoDict) {
16608 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
16609 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
16610 return TRUE;
16611 }
16612 }
16613 return FALSE;
16614 }
16615
16616 bool
16617 OSKext::isInFileset(void)
16618 {
16619 if (!kmod_info) {
16620 goto check_prelinked;
16621 }
16622
16623 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
16624 return true;
16625 }
16626
16627 check_prelinked:
16628 if (isPrelinked()) {
16629 /*
16630 * If we haven't setup kmod_info yet, but we know
16631 * we're loading a prelinked kext in an MH_FILESET KC,
16632 * then return true
16633 */
16634 kc_format_t kc_format;
16635 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
16636 return true;
16637 }
16638 }
16639 return false;
16640 }
16641
16642 OSSharedPtr<OSDextStatistics>
16643 OSKext::copyDextStatistics(void)
16644 {
16645 return dextStatistics;
16646 }
16647
16648 bool
16649 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
16650 {
16651 kern_return_t result;
16652 if (!super::init()) {
16653 return false;
16654 }
16655 if (seg == nullptr) {
16656 return false;
16657 }
16658 result = kmem_alloc(kernel_map, (vm_offset_t *)&data, seg->vmsize,
16659 KMA_PAGEABLE, VM_KERN_MEMORY_KEXT);
16660 if (result != KERN_SUCCESS) {
16661 return false;
16662 }
16663 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
16664 savedSegment = seg;
16665 vmsize = seg->vmsize;
16666 vmaddr = seg->vmaddr;
16667 return true;
16668 }
16669
16670 OSSharedPtr<OSKextSavedMutableSegment>
16671 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
16672 {
16673 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
16674 if (me && !me->initWithSegment(seg)) {
16675 return nullptr;
16676 }
16677 return me;
16678 }
16679
16680 void
16681 OSKextSavedMutableSegment::free(void)
16682 {
16683 if (data) {
16684 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
16685 }
16686 }
16687
16688 vm_offset_t
16689 OSKextSavedMutableSegment::getVMAddr() const
16690 {
16691 return vmaddr;
16692 }
16693
16694 vm_offset_t
16695 OSKextSavedMutableSegment::getVMSize() const
16696 {
16697 return vmsize;
16698 }
16699
16700 OSReturn
16701 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
16702 {
16703 if (seg != savedSegment) {
16704 return kOSKextReturnInvalidArgument;
16705 }
16706 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
16707 return kOSKextReturnInvalidArgument;
16708 }
16709 memcpy((void *)seg->vmaddr, data, vmsize);
16710 return kOSReturnSuccess;
16711 }
16712
16713 extern "C" kern_return_t
16714 OSKextSetReceiptQueried(void)
16715 {
16716 OSKextLog(/* kext */ NULL,
16717 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
16718 "Setting kext receipt as queried");
16719
16720 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
16721 return KERN_SUCCESS;
16722 }
16723
16724 extern "C" const vm_allocation_site_t *
16725 OSKextGetAllocationSiteForCaller(uintptr_t address)
16726 {
16727 OSKextActiveAccount * active;
16728 vm_allocation_site_t * site;
16729 vm_allocation_site_t * releasesite;
16730
16731 uint32_t baseIdx;
16732 uint32_t lim;
16733 #if __has_feature(ptrauth_calls)
16734 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
16735 #endif /* __has_feature(ptrauth_calls) */
16736
16737 lck_ticket_lock(sKextAccountsLock, sKextAccountsLockGrp);
16738 site = releasesite = NULL;
16739
16740 // bsearch sKextAccounts list
16741 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16742 active = &sKextAccounts[baseIdx + (lim >> 1)];
16743 if ((address >= active->address) && (address < active->address_end)) {
16744 site = &active->account->site;
16745 if (!site->tag) {
16746 vm_tag_alloc_locked(site, &releasesite);
16747 }
16748 break;
16749 } else if (address > active->address) {
16750 // move right
16751 baseIdx += (lim >> 1) + 1;
16752 lim--;
16753 }
16754 // else move left
16755 }
16756 lck_ticket_unlock(sKextAccountsLock);
16757 if (releasesite) {
16758 kern_allocation_name_release(releasesite);
16759 }
16760
16761 return site;
16762 }
16763
16764 #if DEVELOPMENT || DEBUG
16765 extern "C" void
16766 OSKextGetRefGrpForCaller(uintptr_t address, void (^cb)(struct os_refgrp *))
16767 {
16768 OSKextActiveAccount * active;
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
16778 // bsearch sKextAccounts list
16779 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
16780 active = &sKextAccounts[baseIdx + (lim >> 1)];
16781 if ((address >= active->address) && (address < active->address_end)) {
16782 cb(&active->account->task_refgrp);
16783 break;
16784 } else if (address > active->address) {
16785 // move right
16786 baseIdx += (lim >> 1) + 1;
16787 lim--;
16788 }
16789 // else move left
16790 }
16791 lck_ticket_unlock(sKextAccountsLock);
16792 }
16793 #endif /* DEVELOPMENT || DEBUG */
16794
16795 extern "C" uint32_t
16796 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
16797 {
16798 OSKextAccount * account = (typeof(account))site;
16799 const char * kname;
16800
16801 if (name) {
16802 if (account->kext) {
16803 kname = account->kext->getIdentifierCString();
16804 } else {
16805 kname = "<>";
16806 }
16807 strlcpy(name, kname, namelen);
16808 }
16809
16810 return account->loadTag;
16811 }
16812
16813 extern "C" void
16814 OSKextFreeSite(vm_allocation_site_t * site)
16815 {
16816 OSKextAccount * freeAccount = (typeof(freeAccount))site;
16817 IOFreeType(freeAccount, OSKextAccount);
16818 }
16819
16820 /*********************************************************************
16821 *********************************************************************/
16822
16823 #if CONFIG_IMAGEBOOT
16824 int
16825 OSKextGetUUIDForName(const char *name, uuid_t uuid)
16826 {
16827 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
16828 if (!kext) {
16829 return 1;
16830 }
16831
16832 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
16833 if (uuid_data) {
16834 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
16835 return 0;
16836 }
16837
16838 return 1;
16839 }
16840 #endif
16841
16842
16843
16844 class OSDextCrash : public OSObject {
16845 OSDeclareDefaultStructors(OSDextCrash);
16846 public:
16847 static OSPtr<OSDextCrash> withTimestamp(uint64_t timestamp);
16848 uint64_t getTimestamp();
16849
16850 private:
16851 virtual bool initWithTimestamp(uint64_t timestamp);
16852 uint64_t fTimestamp;
16853 };
16854
16855 OSDefineMetaClassAndStructors(OSDextCrash, OSObject);
16856
16857 OSSharedPtr<OSDextCrash>
16858 OSDextCrash::withTimestamp(uint64_t timestamp)
16859 {
16860 OSSharedPtr<OSDextCrash> result = OSMakeShared<OSDextCrash>();
16861 if (!result->initWithTimestamp(timestamp)) {
16862 return NULL;
16863 }
16864 return result;
16865 }
16866
16867 bool
16868 OSDextCrash::initWithTimestamp(uint64_t timestamp)
16869 {
16870 if (!OSObject::init()) {
16871 return false;
16872 }
16873 fTimestamp = timestamp;
16874 return true;
16875 }
16876
16877 uint64_t
16878 OSDextCrash::getTimestamp()
16879 {
16880 return fTimestamp;
16881 }
16882
16883 OSSharedPtr<OSDextStatistics>
16884 OSDextStatistics::create()
16885 {
16886 OSSharedPtr<OSDextStatistics> result = OSMakeShared<OSDextStatistics>();
16887 if (!result->init()) {
16888 return NULL;
16889 }
16890 return result;
16891 }
16892
16893 bool
16894 OSDextStatistics::init()
16895 {
16896 if (!OSObject::init()) {
16897 return false;
16898 }
16899
16900 lock = IOLockAlloc();
16901 crashes = OSArray::withCapacity(kMaxDextCrashesInOneDay);
16902 return true;
16903 }
16904
16905 void
16906 OSDextStatistics::free()
16907 {
16908 if (lock) {
16909 IOLockFree(lock);
16910 }
16911 crashes.reset();
16912 OSObject::free();
16913 }
16914
16915 OSDextCrashPolicy
16916 OSDextStatistics::recordCrash()
16917 {
16918 size_t i = 0;
16919 uint64_t timestamp = mach_continuous_time();
16920 uint64_t interval;
16921 nanoseconds_to_absolutetime(86400 * NSEC_PER_SEC /* 1 day */, &interval);
16922 uint64_t lastTimestamp = timestamp > interval ? timestamp - interval : 0;
16923 OSDextCrashPolicy policy;
16924
16925 IOLockLock(lock);
16926 OSSharedPtr<OSDextCrash> crash = OSDextCrash::withTimestamp(timestamp);
16927 for (i = 0; i < crashes->getCount();) {
16928 OSDextCrash * current = OSDynamicCast(OSDextCrash, crashes->getObject(i));
16929 assert(current != NULL);
16930 if (current->getTimestamp() < lastTimestamp) {
16931 crashes->removeObject(i);
16932 } else {
16933 i++;
16934 }
16935 }
16936
16937 crashes->setObject(crash);
16938
16939 if (crashes->getCount() > kMaxDextCrashesInOneDay) {
16940 policy = kOSDextCrashPolicyReboot;
16941 } else {
16942 policy = kOSDextCrashPolicyNone;
16943 }
16944
16945 IOLockUnlock(lock);
16946
16947 return policy;
16948 }
16949
16950 size_t
16951 OSDextStatistics::getCrashCount()
16952 {
16953 size_t result = 0;
16954 IOLockLock(lock);
16955 result = crashes->getCount();
16956 IOLockUnlock(lock);
16957 return result;
16958 }
16959
16960 static int
16961 sysctl_willuserspacereboot
16962 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
16963 {
16964 int new_value = 0, old_value = 0, changed = 0;
16965 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
16966 if (error) {
16967 return error;
16968 }
16969 if (changed) {
16970 OSKext::willUserspaceReboot();
16971 }
16972 return 0;
16973 }
16974
16975 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
16976 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
16977 NULL, 0, sysctl_willuserspacereboot, "I", "");
16978