]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSKext.cpp
aa1c83d5bc50c53756fad56d70151c27c2d7c550
[apple/xnu.git] / libkern / c++ / OSKext.cpp
1 /*
2 * Copyright (c) 2008-2016 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_kern.h>
40 #include <vm/vm_map.h>
41 #include <kextd/kextd_mach.h>
42 #include <libkern/kernel_mach_header.h>
43 #include <libkern/kext_panic_report.h>
44 #include <libkern/kext_request_keys.h>
45 #include <libkern/mkext.h>
46 #include <libkern/prelink.h>
47 #include <libkern/version.h>
48 #include <libkern/zlib.h>
49 #include <mach/host_special_ports.h>
50 #include <mach/mach_vm.h>
51 #include <mach/mach_time.h>
52 #include <sys/sysctl.h>
53 #include <uuid/uuid.h>
54 #include <sys/random.h>
55 #include <pexpert/pexpert.h>
56
57 #include <sys/pgo.h>
58
59 #if CONFIG_MACF
60 #include <sys/kauth.h>
61 #include <security/mac_framework.h>
62 #endif
63
64 #if CONFIG_CSR
65 #include <sys/csr.h>
66 #include <sys/stat.h>
67 #include <sys/vnode.h>
68 #endif /* CONFIG_CSR */
69 };
70
71 #include <os/cpp_util.h>
72
73 #include <libkern/OSKextLibPrivate.h>
74 #include <libkern/c++/OSKext.h>
75 #include <libkern/c++/OSLib.h>
76
77 #include <IOKit/IOLib.h>
78 #include <IOKit/IOCatalogue.h>
79 #include <IOKit/IORegistryEntry.h>
80 #include <IOKit/IOService.h>
81 #include <IOKit/IOUserServer.h>
82
83 #include <IOKit/IOStatisticsPrivate.h>
84 #include <IOKit/IOBSD.h>
85 #include <IOKit/IOPlatformExpert.h>
86
87 #include <san/kasan.h>
88
89 #if PRAGMA_MARK
90 #pragma mark External & Internal Function Protos
91 #endif
92 /*********************************************************************
93 *********************************************************************/
94 extern "C" {
95 extern int IODTGetLoaderInfo(const char * key, void ** infoAddr, int * infoSize);
96 extern void IODTFreeLoaderInfo(const char * key, void * infoAddr, int infoSize);
97
98 extern ppnum_t pmap_find_phys(pmap_t pmap, addr64_t va); /* osfmk/machine/pmap.h */
99 extern int dtrace_keep_kernel_symbols(void);
100
101 #if defined(__x86_64__) || defined(__i386__)
102 extern kern_return_t i386_slide_individual_kext(kernel_mach_header_t *mh, uintptr_t slide);
103 extern kern_return_t i386_slide_kext_collection_mh_addrs(kernel_mach_header_t *mh, uintptr_t slide, bool adjust_mach_headers);
104 extern void *ubc_getobject_from_filename(const char *filename, struct vnode **, off_t *file_size);
105 static void *allocate_kcfileset_map_entry_list(void);
106 static void add_kcfileset_map_entry(void *map_entry_list, vm_map_offset_t start, vm_map_offset_t size);
107 static void deallocate_kcfileset_map_entry_list_and_unmap_entries(void *map_entry_list, boolean_t unmap_entries, bool pageable);
108 int vnode_put(struct vnode *vp);
109 kern_return_t vm_map_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size,
110 void *control, vm_object_offset_t fileoffset, vm_prot_t max_prot);
111 kern_return_t vm_unmap_kcfileset_segment(vm_map_offset_t *start, vm_map_offset_t size);
112 void * ubc_getobject(struct vnode *vp, __unused int flags);
113 #endif //(__x86_64__) || defined(__i386__)
114 }
115
116 extern unsigned long gVirtBase;
117 extern unsigned long gPhysBase;
118 extern vm_map_t g_kext_map;
119
120 bool pageableKCloaded = false;
121 bool auxKCloaded = false;
122 bool resetAuxKCSegmentOnUnload = false;
123
124 extern boolean_t pageablekc_uuid_valid;
125 extern uuid_t pageablekc_uuid;
126 extern uuid_string_t pageablekc_uuid_string;
127
128 extern boolean_t auxkc_uuid_valid;
129 extern uuid_t auxkc_uuid;
130 extern uuid_string_t auxkc_uuid_string;
131
132 static OSReturn _OSKextCreateRequest(
133 const char * predicate,
134 OSSharedPtr<OSDictionary> & requestP);
135 static OSString * _OSKextGetRequestPredicate(OSDictionary * requestDict);
136 static OSObject * _OSKextGetRequestArgument(
137 OSDictionary * requestDict,
138 const char * argName);
139 static bool _OSKextSetRequestArgument(
140 OSDictionary * requestDict,
141 const char * argName,
142 OSObject * value);
143 static void * _OSKextExtractPointer(OSData * wrapper);
144 static OSKextRequestResourceCallback _OSKextExtractCallbackPointer(OSData * wrapper);
145 static OSReturn _OSDictionarySetCStringValue(
146 OSDictionary * dict,
147 const char * key,
148 const char * value);
149 static bool _OSKextInUnloadedPrelinkedKexts(const OSSymbol * theBundleID);
150 #if CONFIG_KXLD
151 static bool _OSKextInPrelinkRebuildWindow(void);
152 #endif
153
154 // We really should add containsObject() & containsCString to OSCollection & subclasses.
155 // So few pad slots, though....
156 static bool _OSArrayContainsCString(OSArray * array, const char * cString);
157 static void OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code);
158
159 /* Prelinked arm kexts do not have VM entries because the method we use to
160 * fake an entry (see libsa/bootstrap.cpp:readPrelinkedExtensions()) does
161 * not work on ARM. To get around that, we must free prelinked kext
162 * executables with ml_static_mfree() instead of kext_free().
163 */
164 #if __i386__ || __x86_64__
165 #define VM_MAPPED_KEXTS 1
166 #define KASLR_KEXT_DEBUG 0
167 #define KASLR_IOREG_DEBUG 0
168 #elif __arm__ || __arm64__
169 #define VM_MAPPED_KEXTS 0
170 #define KASLR_KEXT_DEBUG 0
171 #else
172 #error Unsupported architecture
173 #endif
174
175 #if PRAGMA_MARK
176 #pragma mark Constants & Macros
177 #endif
178 /*********************************************************************
179 * Constants & Macros
180 *********************************************************************/
181
182 /* Use this number to create containers.
183 */
184 #define kOSKextTypicalLoadCount (150)
185
186 /* Any kext will have at least 1 retain for the internal lookup-by-ID dict.
187 * A loaded kext will no dependents or external retains will have 2 retains.
188 */
189 #define kOSKextMinRetainCount (1)
190 #define kOSKextMinLoadedRetainCount (2)
191
192 /**********
193 * Strings and substrings used in dependency resolution.
194 */
195 #define APPLE_KEXT_PREFIX "com.apple."
196 #define KERNEL_LIB "com.apple.kernel"
197
198 #define PRIVATE_KPI "com.apple.kpi.private"
199
200 /* Version for compatbility pseudokexts (com.apple.kernel.*),
201 * compatible back to v6.0.
202 */
203 #define KERNEL6_LIB "com.apple.kernel.6.0"
204 #define KERNEL6_VERSION "7.9.9"
205
206 #define KERNEL_LIB_PREFIX "com.apple.kernel."
207 #define KPI_LIB_PREFIX "com.apple.kpi."
208
209 #define STRING_HAS_PREFIX(s, p) (strncmp((s), (p), strlen(p)) == 0)
210
211 #define REBUILD_MAX_TIME (60 * 5) // 5 minutes
212 #define MINIMUM_WAKEUP_SECONDS (30)
213
214 /*********************************************************************
215 * infoDict keys for internally-stored data. Saves on ivar slots for
216 * objects we don't keep around past boot time or during active load.
217 *********************************************************************/
218
219 /* A usable, uncompressed file is stored under this key.
220 */
221 #define _kOSKextExecutableKey "_OSKextExecutable"
222
223 /* An indirect reference to the executable file from an mkext
224 * is stored under this key.
225 */
226 #define _kOSKextMkextExecutableReferenceKey "_OSKextMkextExecutableReference"
227
228 /* If the file is contained in a larger buffer laid down by the booter or
229 * sent from user space, the OSKext stores that OSData under this key so that
230 * references are properly tracked. This is always an mkext, right now.
231 */
232 #define _kOSKextExecutableExternalDataKey "_OSKextExecutableExternalData"
233
234 #define OS_LOG_HDR_VERSION 1
235 #define NUM_OS_LOG_SECTIONS 2
236
237 #define OS_LOG_SECT_IDX 0
238 #define CSTRING_SECT_IDX 1
239
240 #if PRAGMA_MARK
241 #pragma mark Typedefs
242 #endif
243 /*********************************************************************
244 * Typedefs
245 *********************************************************************/
246
247 /*********************************************************************
248 * osLogDataHeaderRef describes the header information of an OSData
249 * object that is returned when querying for kOSBundleLogStringsKey.
250 * We currently return information regarding 2 sections - os_log and
251 * cstring. In the case that the os_log section doesn't exist, we just
252 * return an offset and length of 0 for that section.
253 *********************************************************************/
254 typedef struct osLogDataHeader {
255 uint32_t version;
256 uint32_t sect_count;
257 struct {
258 uint32_t sect_offset;
259 uint32_t sect_size;
260 } sections[0];
261 } osLogDataHeaderRef;
262
263 /*********************************************************************
264 * MkextEntryRef describes the contents of an OSData object
265 * referencing a file entry from an mkext so that we can uncompress
266 * (if necessary) and extract it on demand.
267 *
268 * It contains the mkextVersion in case we ever wind up supporting
269 * multiple mkext formats. Mkext format 1 is officially retired as of
270 * Snow Leopard.
271 *********************************************************************/
272 typedef struct MkextEntryRef {
273 mkext_basic_header * mkext; // beginning of whole mkext file
274 void * fileinfo;// mkext2_file_entry or equiv; see mkext.h
275 } MkextEntryRef;
276
277 #if PRAGMA_MARK
278 #pragma mark Global and static Module Variables
279 #endif
280 /*********************************************************************
281 * Global & static variables, used to keep track of kexts.
282 *********************************************************************/
283
284 static bool sPrelinkBoot = false;
285 static bool sSafeBoot = false;
286 static bool sKeepSymbols = false;
287 static bool sPanicOnKCMismatch = false;
288 static bool sOSKextWasResetAfterUserspaceReboot = false;
289
290 /*********************************************************************
291 * sKextLock is the principal lock for OSKext, and guards all static
292 * and global variables not owned by other locks (declared further
293 * below). It must be taken by any entry-point method or function,
294 * including internal functions called on scheduled threads.
295 *
296 * sKextLock and sKextInnerLock are recursive due to multiple functions
297 * that are called both externally and internally. The other locks are
298 * nonrecursive.
299 *
300 * Which locks are taken depends on what they protect, but if more than
301 * one must be taken, they must always be locked in this order
302 * (and unlocked in reverse order) to prevent deadlocks:
303 *
304 * 1. sKextLock
305 * 2. sKextInnerLock
306 * 3. sKextSummariesLock
307 * 4. sKextLoggingLock
308 */
309 static IORecursiveLock * sKextLock = NULL;
310
311 static OSSharedPtr<OSDictionary> sKextsByID;
312 static OSSharedPtr<OSDictionary> sExcludeListByID;
313 static OSKextVersion sExcludeListVersion = 0;
314 static OSSharedPtr<OSArray> sLoadedKexts;
315 static OSSharedPtr<OSDictionary> sNonLoadableKextsByID;
316 static OSSharedPtr<OSArray> sUnloadedPrelinkedKexts;
317 static OSSharedPtr<OSArray> sLoadedDriverKitKexts;
318
319 // Requests to the IOKit daemon waiting to be picked up.
320 static OSSharedPtr<OSArray> sKernelRequests;
321 // Identifier of kext load requests in sKernelRequests
322 static OSSharedPtr<OSSet> sPostedKextLoadIdentifiers;
323 static OSSharedPtr<OSArray> sRequestCallbackRecords;
324
325 // Identifiers of all kexts ever requested in kernel; used for prelinked kernel
326 static OSSharedPtr<OSSet> sAllKextLoadIdentifiers;
327 #if CONFIG_KXLD
328 static KXLDContext * sKxldContext = NULL;
329 #endif
330 static uint32_t sNextLoadTag = 0;
331 static uint32_t sNextRequestTag = 0;
332
333 static bool sUserLoadsActive = false;
334 static bool sIOKitDaemonActive = false;
335 static bool sDeferredLoadSucceeded = false;
336 static bool sConsiderUnloadsExecuted = false;
337
338 #if NO_KEXTD
339 static bool sKernelRequestsEnabled = false;
340 #else
341 static bool sKernelRequestsEnabled = true;
342 #endif
343 static bool sLoadEnabled = true;
344 static bool sUnloadEnabled = true;
345
346 /*********************************************************************
347 * Stuff for the OSKext representing the kernel itself.
348 **********/
349 static OSKext * sKernelKext = NULL;
350
351 /* Set up a fake kmod_info struct for the kernel.
352 * It's used in OSRuntime.cpp to call OSRuntimeInitializeCPP()
353 * before OSKext is initialized; that call only needs the name
354 * and address to be set correctly.
355 *
356 * We don't do much else with the kerne's kmod_info; we never
357 * put it into the kmod list, never adjust the reference count,
358 * and never have kernel components reference it.
359 * For that matter, we don't do much with kmod_info structs
360 * at all anymore! We just keep them filled in for gdb and
361 * binary compability.
362 */
363 kmod_info_t g_kernel_kmod_info = {
364 .next = NULL,
365 .info_version = KMOD_INFO_VERSION,
366 .id = 0, // loadTag: kernel is always 0
367 .name = kOSKextKernelIdentifier,// bundle identifier
368 .version = "0", // filled in in OSKext::initialize()
369 .reference_count = -1, // never adjusted; kernel never unloads
370 .reference_list = NULL,
371 .address = 0,
372 .size = 0, // filled in in OSKext::initialize()
373 .hdr_size = 0,
374 .start = NULL,
375 .stop = NULL
376 };
377
378 /* Set up a fake kmod_info struct for statically linked kexts that don't have one. */
379
380 kmod_info_t invalid_kmod_info = {
381 .next = NULL,
382 .info_version = KMOD_INFO_VERSION,
383 .id = UINT32_MAX,
384 .name = "invalid",
385 .version = "0",
386 .reference_count = -1,
387 .reference_list = NULL,
388 .address = 0,
389 .size = 0,
390 .hdr_size = 0,
391 .start = NULL,
392 .stop = NULL
393 };
394
395 extern "C" {
396 // symbol 'kmod' referenced in: model_dep.c, db_trace.c, symbols.c, db_low_trace.c,
397 // dtrace.c, dtrace_glue.h, OSKext.cpp, locore.s, lowmem_vectors.s,
398 // misc_protos.h, db_low_trace.c, kgmacros
399 // 'kmod' is a holdover from the old kmod system, we can't rename it.
400 kmod_info_t * kmod = NULL;
401
402 #define KEXT_PANICLIST_SIZE (2 * PAGE_SIZE)
403
404
405 static char * loaded_kext_paniclist = NULL;
406 static uint32_t loaded_kext_paniclist_size = 0;
407
408 AbsoluteTime last_loaded_timestamp;
409 static char last_loaded_str_buf[2 * KMOD_MAX_NAME];
410 static u_long last_loaded_strlen = 0;
411 static void * last_loaded_address = NULL;
412 static u_long last_loaded_size = 0;
413
414 AbsoluteTime last_unloaded_timestamp;
415 static char last_unloaded_str_buf[2 * KMOD_MAX_NAME];
416 static u_long last_unloaded_strlen = 0;
417 static void * last_unloaded_address = NULL;
418 static u_long last_unloaded_size = 0;
419
420 // Statically linked kmods described by several mach-o sections:
421 //
422 // kPrelinkInfoSegment:kBuiltinInfoSection
423 // Array of pointers to kmod_info_t structs.
424 //
425 // kPrelinkInfoSegment:kBuiltinInfoSection
426 // Array of pointers to an embedded mach-o header.
427 //
428 // __DATA:kBuiltinInitSection, kBuiltinTermSection
429 // Structors for all kmods. Has to be filtered by proc address.
430 //
431
432 static uint32_t gBuiltinKmodsCount;
433 static kernel_section_t * gBuiltinKmodsSectionInfo;
434 static kernel_section_t * gBuiltinKmodsSectionStart;
435
436 const OSSymbol * gIOSurfaceIdentifier;
437 vm_tag_t gIOSurfaceTag;
438
439 /*********************************************************************
440 * sKextInnerLock protects against cross-calls with IOService and
441 * IOCatalogue, and owns the variables declared immediately below.
442 *
443 * Note that sConsiderUnloadsExecuted above belongs to sKextLock!
444 *
445 * When both sKextLock and sKextInnerLock need to be taken,
446 * always lock sKextLock first and unlock it second. Never take both
447 * locks in an entry point to OSKext; if you need to do so, you must
448 * spawn an independent thread to avoid potential deadlocks for threads
449 * calling into OSKext.
450 **********/
451 static IORecursiveLock * sKextInnerLock = NULL;
452
453 static bool sAutounloadEnabled = true;
454 static bool sConsiderUnloadsCalled = false;
455 static bool sConsiderUnloadsPending = false;
456
457 static unsigned int sConsiderUnloadDelay = 60; // seconds
458 static thread_call_t sUnloadCallout = NULL;
459 #if CONFIG_KXLD
460 static thread_call_t sDestroyLinkContextThread = NULL; // one-shot, one-at-a-time thread
461 #endif // CONFIG_KXLD
462 static bool sSystemSleep = false; // true when system going to sleep
463 static AbsoluteTime sLastWakeTime; // last time we woke up
464
465 /*********************************************************************
466 * Backtraces can be printed at various times so we need a tight lock
467 * on data used for that. sKextSummariesLock protects the variables
468 * declared immediately below.
469 *
470 * gLoadedKextSummaries is accessed by other modules, but only during
471 * a panic so the lock isn't needed then.
472 *
473 * gLoadedKextSummaries has the "used" attribute in order to ensure
474 * that it remains visible even when we are performing extremely
475 * aggressive optimizations, as it is needed to allow the debugger
476 * to automatically parse the list of loaded kexts.
477 **********/
478 static IOLock * sKextSummariesLock = NULL;
479 extern "C" lck_spin_t vm_allocation_sites_lock;
480 static IOSimpleLock * sKextAccountsLock = &vm_allocation_sites_lock;
481
482 void(*const sLoadedKextSummariesUpdated)(void) = OSKextLoadedKextSummariesUpdated;
483 OSKextLoadedKextSummaryHeader * gLoadedKextSummaries __attribute__((used)) = NULL;
484 uint64_t gLoadedKextSummariesTimestamp __attribute__((used)) = 0;
485 static size_t sLoadedKextSummariesAllocSize = 0;
486
487 static OSKextActiveAccount * sKextAccounts;
488 static uint32_t sKextAccountsCount;
489 };
490
491 /*********************************************************************
492 * sKextLoggingLock protects the logging variables declared immediately below.
493 **********/
494 static IOLock * sKextLoggingLock = NULL;
495
496 static const OSKextLogSpec kDefaultKernelLogFilter = kOSKextLogBasicLevel |
497 kOSKextLogVerboseFlagsMask;
498 static OSKextLogSpec sKernelLogFilter = kDefaultKernelLogFilter;
499 static bool sBootArgLogFilterFound = false;
500 SYSCTL_UINT(_debug, OID_AUTO, kextlog, CTLFLAG_RW | CTLFLAG_LOCKED, &sKernelLogFilter,
501 0, "kernel kext logging");
502
503 static OSKextLogSpec sUserSpaceKextLogFilter = kOSKextLogSilentFilter;
504 static OSSharedPtr<OSArray> sUserSpaceLogSpecArray;
505 static OSSharedPtr<OSArray> sUserSpaceLogMessageArray;
506
507 /*********
508 * End scope for sKextInnerLock-protected variables.
509 *********************************************************************/
510
511
512 /*********************************************************************
513 * helper function used for collecting PGO data upon unload of a kext
514 */
515
516 static int OSKextGrabPgoDataLocked(OSKext *kext,
517 bool metadata,
518 uuid_t instance_uuid,
519 uint64_t *pSize,
520 char *pBuffer,
521 uint64_t bufferSize);
522
523 /**********************************************************************/
524
525
526
527 #if PRAGMA_MARK
528 #pragma mark OSData callbacks (need to move to OSData)
529 #endif
530 /*********************************************************************
531 * C functions used for callbacks.
532 *********************************************************************/
533 extern "C" {
534 void
535 osdata_kmem_free(void * ptr, unsigned int length)
536 {
537 kmem_free(kernel_map, (vm_address_t)ptr, length);
538 return;
539 }
540
541 void
542 osdata_phys_free(void * ptr, unsigned int length)
543 {
544 ml_static_mfree((vm_offset_t)ptr, length);
545 return;
546 }
547
548 void
549 osdata_vm_deallocate(void * ptr, unsigned int length)
550 {
551 (void)vm_deallocate(kernel_map, (vm_offset_t)ptr, length);
552 return;
553 }
554
555 void
556 osdata_kext_free(void * ptr, unsigned int length)
557 {
558 (void)kext_free((vm_offset_t)ptr, length);
559 }
560 };
561
562 #if PRAGMA_MARK
563 #pragma mark KXLD Allocation Callback
564 #endif
565 #if CONFIG_KXLD
566 /*********************************************************************
567 * KXLD Allocation Callback
568 *********************************************************************/
569 kxld_addr_t
570 kern_allocate(
571 u_long size,
572 KXLDAllocateFlags * flags,
573 void * user_data)
574 {
575 vm_address_t result = 0; // returned
576 kern_return_t mach_result = KERN_FAILURE;
577 bool success = false;
578 OSKext * theKext = (OSKext *)user_data;
579 unsigned int roundSize = 0;
580 OSSharedPtr<OSData> linkBuffer;
581
582 if (round_page(size) > UINT_MAX) {
583 OSKextLog(theKext,
584 kOSKextLogErrorLevel |
585 kOSKextLogGeneralFlag,
586 "%s: Requested memory size is greater than UINT_MAX.",
587 theKext->getIdentifierCString());
588 goto finish;
589 }
590
591 roundSize = (unsigned int)round_page(size);
592
593 mach_result = kext_alloc(&result, roundSize, /* fixed */ FALSE);
594 if (mach_result != KERN_SUCCESS) {
595 OSKextLog(theKext,
596 kOSKextLogErrorLevel |
597 kOSKextLogGeneralFlag,
598 "Can't allocate kernel memory to link %s.",
599 theKext->getIdentifierCString());
600 goto finish;
601 }
602
603 /* Create an OSData wrapper for the allocated buffer.
604 */
605 linkBuffer = OSData::withBytesNoCopy((void *)result, roundSize);
606 if (!linkBuffer) {
607 OSKextLog(theKext,
608 kOSKextLogErrorLevel |
609 kOSKextLogGeneralFlag,
610 "Can't allocate linked executable wrapper for %s.",
611 theKext->getIdentifierCString());
612 goto finish;
613 }
614 linkBuffer->setDeallocFunction(osdata_kext_free);
615 OSKextLog(theKext,
616 kOSKextLogProgressLevel |
617 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
618 "Allocated link buffer for kext %s at %p (%lu bytes).",
619 theKext->getIdentifierCString(),
620 (void *)result, (unsigned long)roundSize);
621
622 theKext->setLinkedExecutable(linkBuffer.get());
623
624 *flags = kKxldAllocateWritable;
625 success = true;
626
627 finish:
628 if (!success && result) {
629 kext_free(result, roundSize);
630 result = 0;
631 }
632
633 return (kxld_addr_t)result;
634 }
635
636 /*********************************************************************
637 *********************************************************************/
638 void
639 kxld_log_callback(
640 KXLDLogSubsystem subsystem,
641 KXLDLogLevel level,
642 const char * format,
643 va_list argList,
644 void * user_data)
645 {
646 OSKext *theKext = (OSKext *) user_data;
647 OSKextLogSpec logSpec = 0;
648
649 switch (subsystem) {
650 case kKxldLogLinking:
651 logSpec |= kOSKextLogLinkFlag;
652 break;
653 case kKxldLogPatching:
654 logSpec |= kOSKextLogPatchFlag;
655 break;
656 }
657
658 switch (level) {
659 case kKxldLogExplicit:
660 logSpec |= kOSKextLogExplicitLevel;
661 break;
662 case kKxldLogErr:
663 logSpec |= kOSKextLogErrorLevel;
664 break;
665 case kKxldLogWarn:
666 logSpec |= kOSKextLogWarningLevel;
667 break;
668 case kKxldLogBasic:
669 logSpec |= kOSKextLogProgressLevel;
670 break;
671 case kKxldLogDetail:
672 logSpec |= kOSKextLogDetailLevel;
673 break;
674 case kKxldLogDebug:
675 logSpec |= kOSKextLogDebugLevel;
676 break;
677 }
678
679 OSKextVLog(theKext, logSpec, format, argList);
680 }
681 #endif // CONFIG_KXLD
682
683 #if PRAGMA_MARK
684 #pragma mark IOStatistics defines
685 #endif
686
687 #if IOKITSTATS
688
689 #define notifyKextLoadObservers(kext, kmod_info) \
690 do { \
691 IOStatistics::onKextLoad(kext, kmod_info); \
692 } while (0)
693
694 #define notifyKextUnloadObservers(kext) \
695 do { \
696 IOStatistics::onKextUnload(kext); \
697 } while (0)
698
699 #define notifyAddClassObservers(kext, addedClass, flags) \
700 do { \
701 IOStatistics::onClassAdded(kext, addedClass); \
702 } while (0)
703
704 #define notifyRemoveClassObservers(kext, removedClass, flags) \
705 do { \
706 IOStatistics::onClassRemoved(kext, removedClass); \
707 } while (0)
708
709 #else
710
711 #define notifyKextLoadObservers(kext, kmod_info)
712 #define notifyKextUnloadObservers(kext)
713 #define notifyAddClassObservers(kext, addedClass, flags)
714 #define notifyRemoveClassObservers(kext, removedClass, flags)
715
716 #endif /* IOKITSTATS */
717
718 #if PRAGMA_MARK
719 #pragma mark Module Config (Startup & Shutdown)
720 #endif
721 /*********************************************************************
722 * Module Config (Class Definition & Class Methods)
723 *********************************************************************/
724 #define super OSObject
725 OSDefineMetaClassAndStructors(OSKext, OSObject)
726
727 OSDefineMetaClassAndStructors(OSKextSavedMutableSegment, OSObject);
728
729 /*********************************************************************
730 *********************************************************************/
731 /* static */
732 void
733 OSKext::initialize(void)
734 {
735 OSSharedPtr<OSData> kernelExecutable = NULL;// do not release
736 u_char * kernelStart = NULL;// do not free
737 size_t kernelLength = 0;
738 IORegistryEntry * registryRoot = NULL;// do not release
739 OSSharedPtr<OSNumber> kernelCPUType;
740 OSSharedPtr<OSNumber> kernelCPUSubtype;
741 OSKextLogSpec bootLogFilter = kOSKextLogSilentFilter;
742 bool setResult = false;
743 uint64_t * timestamp = NULL;
744 __unused char bootArgBuffer[16];// for PE_parse_boot_argn w/strings
745
746 /* This must be the first thing allocated. Everything else grabs this lock.
747 */
748 sKextLock = IORecursiveLockAlloc();
749 sKextInnerLock = IORecursiveLockAlloc();
750 sKextSummariesLock = IOLockAlloc();
751 sKextLoggingLock = IOLockAlloc();
752 assert(sKextLock);
753 assert(sKextInnerLock);
754 assert(sKextSummariesLock);
755 assert(sKextLoggingLock);
756
757 sKextsByID = OSDictionary::withCapacity(kOSKextTypicalLoadCount);
758 sLoadedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
759 sLoadedDriverKitKexts = OSArray::withCapacity(kOSKextTypicalLoadCount);
760 sUnloadedPrelinkedKexts = OSArray::withCapacity(kOSKextTypicalLoadCount / 10);
761 sKernelRequests = OSArray::withCapacity(0);
762 sPostedKextLoadIdentifiers = OSSet::withCapacity(0);
763 sAllKextLoadIdentifiers = OSSet::withCapacity(kOSKextTypicalLoadCount);
764 sRequestCallbackRecords = OSArray::withCapacity(0);
765 assert(sKextsByID && sLoadedKexts && sLoadedDriverKitKexts && sKernelRequests &&
766 sPostedKextLoadIdentifiers && sAllKextLoadIdentifiers &&
767 sRequestCallbackRecords && sUnloadedPrelinkedKexts);
768
769 /* Read the log flag boot-args and set the log flags.
770 */
771 if (PE_parse_boot_argn("kextlog", &bootLogFilter, sizeof(bootLogFilter))) {
772 sBootArgLogFilterFound = true;
773 sKernelLogFilter = bootLogFilter;
774 // log this if any flags are set
775 OSKextLog(/* kext */ NULL,
776 kOSKextLogBasicLevel |
777 kOSKextLogFlagsMask,
778 "Kernel kext log filter 0x%x per kextlog boot arg.",
779 (unsigned)sKernelLogFilter);
780 }
781
782 #if !defined(__arm__) && !defined(__arm64__)
783 /*
784 * On our ARM targets, the kernelcache/boot kernel collection contains
785 * the set of kexts required to boot, as specified by KCB. Safeboot is
786 * either unsupported, or is supported by the bootloader only loading
787 * the boot kernel collection; as a result OSKext has no role to play
788 * in safeboot policy on ARM.
789 */
790 sSafeBoot = PE_parse_boot_argn("-x", bootArgBuffer,
791 sizeof(bootArgBuffer)) ? true : false;
792 #endif /* defined(__arm__) && defined(__arm64__) */
793
794 if (sSafeBoot) {
795 OSKextLog(/* kext */ NULL,
796 kOSKextLogWarningLevel |
797 kOSKextLogGeneralFlag,
798 "SAFE BOOT DETECTED - "
799 "only valid OSBundleRequired kexts will be loaded.");
800 }
801
802 PE_parse_boot_argn("keepsyms", &sKeepSymbols, sizeof(sKeepSymbols));
803 #if CONFIG_DTRACE
804 if (dtrace_keep_kernel_symbols()) {
805 sKeepSymbols = true;
806 }
807 #endif /* CONFIG_DTRACE */
808 #if KASAN_DYNAMIC_BLACKLIST
809 /* needed for function lookup */
810 sKeepSymbols = true;
811 #endif
812
813 /*
814 * Should we panic when the SystemKC is not linked against the
815 * BootKC that was loaded by the booter? By default: yes, if the
816 * "-nokcmismatchpanic" boot-arg is passed, then we _don't_ panic
817 * on mis-match and instead just print an error and continue.
818 */
819 sPanicOnKCMismatch = PE_parse_boot_argn("-nokcmismatchpanic", bootArgBuffer,
820 sizeof(bootArgBuffer)) ? false : true;
821
822 /* Set up an OSKext instance to represent the kernel itself.
823 */
824 sKernelKext = new OSKext;
825 assert(sKernelKext);
826
827 kernelStart = (u_char *)&_mh_execute_header;
828 kernelLength = getlastaddr() - (vm_offset_t)kernelStart;
829 assert(kernelLength <= UINT_MAX);
830 kernelExecutable = OSData::withBytesNoCopy(
831 kernelStart, (unsigned int)kernelLength);
832 assert(kernelExecutable);
833
834 #if KASLR_KEXT_DEBUG
835 IOLog("kaslr: kernel start 0x%lx end 0x%lx length %lu vm_kernel_slide %lu (0x%016lx) \n",
836 (unsigned long)kernelStart,
837 (unsigned long)getlastaddr(),
838 kernelLength,
839 (unsigned long)vm_kernel_slide,
840 (unsigned long)vm_kernel_slide);
841 #endif
842
843 sKernelKext->loadTag = sNextLoadTag++; // the kernel is load tag 0
844 sKernelKext->bundleID = OSSymbol::withCString(kOSKextKernelIdentifier);
845
846 sKernelKext->version = OSKextParseVersionString(osrelease);
847 sKernelKext->compatibleVersion = sKernelKext->version;
848 sKernelKext->linkedExecutable = os::move(kernelExecutable);
849 sKernelKext->interfaceUUID = sKernelKext->copyUUID();
850
851 sKernelKext->flags.hasAllDependencies = 1;
852 sKernelKext->flags.kernelComponent = 1;
853 sKernelKext->flags.prelinked = 0;
854 sKernelKext->flags.loaded = 1;
855 sKernelKext->flags.started = 1;
856 sKernelKext->flags.CPPInitialized = 0;
857 sKernelKext->flags.jettisonLinkeditSeg = 0;
858
859 sKernelKext->kmod_info = &g_kernel_kmod_info;
860 strlcpy(g_kernel_kmod_info.version, osrelease,
861 sizeof(g_kernel_kmod_info.version));
862 g_kernel_kmod_info.size = kernelLength;
863 g_kernel_kmod_info.id = sKernelKext->loadTag;
864
865 /* Cons up an info dict, so we don't have to have special-case
866 * checking all over.
867 */
868 sKernelKext->infoDict = OSDictionary::withCapacity(5);
869 assert(sKernelKext->infoDict);
870 setResult = sKernelKext->infoDict->setObject(kCFBundleIdentifierKey,
871 sKernelKext->bundleID.get());
872 assert(setResult);
873 setResult = sKernelKext->infoDict->setObject(kOSKernelResourceKey,
874 kOSBooleanTrue);
875 assert(setResult);
876
877 {
878 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy(osrelease));
879 assert(scratchString);
880 setResult = sKernelKext->infoDict->setObject(kCFBundleVersionKey,
881 scratchString.get());
882 assert(setResult);
883 }
884
885 {
886 OSSharedPtr<OSString> scratchString(OSString::withCStringNoCopy("mach_kernel"));
887 assert(scratchString);
888 setResult = sKernelKext->infoDict->setObject(kCFBundleNameKey,
889 scratchString.get());
890 assert(setResult);
891 }
892
893 /* Add the kernel kext to the bookkeeping dictionaries. Note that
894 * the kernel kext doesn't have a kmod_info struct. copyInfo()
895 * gathers info from other places anyhow.
896 */
897 setResult = sKextsByID->setObject(sKernelKext->bundleID.get(), sKernelKext);
898 assert(setResult);
899 setResult = sLoadedKexts->setObject(sKernelKext);
900 assert(setResult);
901
902 // XXX: better way with OSSharedPtr?
903 // sKernelKext remains a valid pointer even after the decref
904 sKernelKext->release();
905
906 registryRoot = IORegistryEntry::getRegistryRoot();
907 kernelCPUType = OSNumber::withNumber(
908 (long long unsigned int)_mh_execute_header.cputype,
909 8 * sizeof(_mh_execute_header.cputype));
910 kernelCPUSubtype = OSNumber::withNumber(
911 (long long unsigned int)_mh_execute_header.cpusubtype,
912 8 * sizeof(_mh_execute_header.cpusubtype));
913 assert(registryRoot && kernelCPUSubtype && kernelCPUType);
914
915 registryRoot->setProperty(kOSKernelCPUTypeKey, kernelCPUType.get());
916 registryRoot->setProperty(kOSKernelCPUSubtypeKey, kernelCPUSubtype.get());
917
918 gBuiltinKmodsSectionInfo = getsectbyname(kPrelinkInfoSegment, kBuiltinInfoSection);
919 if (gBuiltinKmodsSectionInfo) {
920 uint32_t count;
921
922 assert(gBuiltinKmodsSectionInfo->addr);
923 assert(gBuiltinKmodsSectionInfo->size);
924 assert(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *) <= UINT_MAX);
925 gBuiltinKmodsCount = (unsigned int)(gBuiltinKmodsSectionInfo->size / sizeof(kmod_info_t *));
926
927 gBuiltinKmodsSectionStart = getsectbyname(kPrelinkInfoSegment, kBuiltinStartSection);
928 assert(gBuiltinKmodsSectionStart);
929 assert(gBuiltinKmodsSectionStart->addr);
930 assert(gBuiltinKmodsSectionStart->size);
931 assert(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t) <= UINT_MAX);
932 count = (unsigned int)(gBuiltinKmodsSectionStart->size / sizeof(uintptr_t));
933 // one extra pointer for the end of last kmod
934 assert(count == (gBuiltinKmodsCount + 1));
935
936 vm_kernel_builtinkmod_text = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[0];
937 vm_kernel_builtinkmod_text_end = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[count - 1];
938 }
939
940 // Don't track this object -- it's never released
941 gIOSurfaceIdentifier = OSSymbol::withCStringNoCopy("com.apple.iokit.IOSurface").detach();
942
943 timestamp = __OSAbsoluteTimePtr(&last_loaded_timestamp);
944 *timestamp = 0;
945 timestamp = __OSAbsoluteTimePtr(&last_unloaded_timestamp);
946 *timestamp = 0;
947 timestamp = __OSAbsoluteTimePtr(&sLastWakeTime);
948 *timestamp = 0;
949
950 OSKextLog(/* kext */ NULL,
951 kOSKextLogProgressLevel |
952 kOSKextLogGeneralFlag,
953 "Kext system initialized.");
954
955 notifyKextLoadObservers(sKernelKext, sKernelKext->kmod_info);
956
957 return;
958 }
959
960 /*********************************************************************
961 * This is expected to be called exactly once, from exactly one thread
962 * context, during kernel bootstrap.
963 *********************************************************************/
964 /* static */
965 OSReturn
966 OSKext::removeKextBootstrap(void)
967 {
968 OSReturn result = kOSReturnError;
969
970 const char * dt_kernel_header_name = "Kernel-__HEADER";
971 const char * dt_kernel_symtab_name = "Kernel-__SYMTAB";
972 kernel_mach_header_t * dt_mach_header = NULL;
973 int dt_mach_header_size = 0;
974 struct symtab_command * dt_symtab = NULL;
975 int dt_symtab_size = 0;
976 int dt_result = 0;
977
978 kernel_segment_command_t * seg_to_remove = NULL;
979
980 const char __unused * dt_segment_name = NULL;
981 void __unused * segment_paddress = NULL;
982 int __unused segment_size = 0;
983
984 OSKextLog(/* kext */ NULL,
985 kOSKextLogProgressLevel |
986 kOSKextLogGeneralFlag,
987 "Jettisoning kext bootstrap segments.");
988
989 /*
990 * keep the linkedit segment around when booted from a new MH_FILESET
991 * KC because all the kexts shared a linkedit segment.
992 */
993 kc_format_t kc_format;
994 if (!PE_get_primary_kc_format(&kc_format)) {
995 OSKextLog(/* kext */ NULL,
996 kOSKextLogErrorLevel |
997 kOSKextLogGeneralFlag,
998 "Unable to determine primary KC format");
999 }
1000
1001 /*****
1002 * Dispose of unnecessary stuff that the booter didn't need to load.
1003 */
1004 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1005 (void **)&dt_mach_header, &dt_mach_header_size);
1006 if (dt_result == 0 && dt_mach_header) {
1007 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1008 round_page_32(dt_mach_header_size));
1009 }
1010 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1011 (void **)&dt_symtab, &dt_symtab_size);
1012 if (dt_result == 0 && dt_symtab) {
1013 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1014 round_page_32(dt_symtab_size));
1015 }
1016
1017 /*****
1018 * KLD bootstrap segment.
1019 */
1020 // xxx - should rename KLD segment
1021 seg_to_remove = getsegbyname("__KLD");
1022 if (seg_to_remove) {
1023 OSRuntimeUnloadCPPForSegment(seg_to_remove);
1024 }
1025
1026 #if __arm__ || __arm64__
1027 /* Free the memory that was set up by bootx.
1028 */
1029 dt_segment_name = "Kernel-__KLD";
1030 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1031 /* We cannot free this with KTRR enabled, as we cannot
1032 * update the permissions on the KLD range this late
1033 * in the boot process.
1034 */
1035 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1036 (int)segment_size);
1037 }
1038 #elif __i386__ || __x86_64__
1039 /* On x86, use the mapping data from the segment load command to
1040 * unload KLD directly.
1041 * This may invalidate any assumptions about "avail_start"
1042 * defining the lower bound for valid physical addresses.
1043 */
1044 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
1045 bzero((void *)seg_to_remove->vmaddr, seg_to_remove->vmsize);
1046 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
1047 }
1048 #else
1049 #error arch
1050 #endif
1051
1052 seg_to_remove = NULL;
1053
1054 /*****
1055 * Prelinked kernel's symtab (if there is one).
1056 */
1057 if (kc_format != KCFormatFileset) {
1058 kernel_section_t * sect;
1059 sect = getsectbyname("__PRELINK", "__symtab");
1060 if (sect && sect->addr && sect->size) {
1061 ml_static_mfree(sect->addr, sect->size);
1062 }
1063 }
1064
1065 seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1066
1067 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1068 * pageable, unless keepsyms is set. To do that, we have to copy it from
1069 * its booter-allocated memory, free the booter memory, reallocate proper
1070 * managed memory, then copy the segment back in.
1071 *
1072 * NOTE: This optimization is not valid for fileset KCs because each
1073 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1074 * that points to one fileset-global LINKEDIT segment. This
1075 * optimization is also only valid for platforms that support vm
1076 * mapped kexts or mapped kext collections (pageable KCs)
1077 */
1078 #if VM_MAPPED_KEXTS
1079 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1080 kern_return_t mem_result;
1081 void *seg_copy = NULL;
1082 void *seg_data = NULL;
1083 vm_map_offset_t seg_offset = 0;
1084 vm_map_offset_t seg_copy_offset = 0;
1085 vm_map_size_t seg_length = 0;
1086
1087 seg_data = (void *) seg_to_remove->vmaddr;
1088 seg_offset = (vm_map_offset_t) seg_to_remove->vmaddr;
1089 seg_length = (vm_map_size_t) seg_to_remove->vmsize;
1090
1091 /* Allocate space for the LINKEDIT copy.
1092 */
1093 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1094 seg_length, VM_KERN_MEMORY_KEXT);
1095 if (mem_result != KERN_SUCCESS) {
1096 OSKextLog(/* kext */ NULL,
1097 kOSKextLogErrorLevel |
1098 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1099 "Can't copy __LINKEDIT segment for VM reassign.");
1100 return result;
1101 }
1102 seg_copy_offset = (vm_map_offset_t) seg_copy;
1103
1104 /* Copy it out.
1105 */
1106 memcpy(seg_copy, seg_data, seg_length);
1107
1108 /* Dump the booter memory.
1109 */
1110 ml_static_mfree(seg_offset, seg_length);
1111
1112 /* Set up the VM region.
1113 */
1114 mem_result = vm_map_enter_mem_object(
1115 kernel_map,
1116 &seg_offset,
1117 seg_length, /* mask */ 0,
1118 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1119 VM_MAP_KERNEL_FLAGS_NONE,
1120 VM_KERN_MEMORY_NONE,
1121 (ipc_port_t)NULL,
1122 (vm_object_offset_t) 0,
1123 /* copy */ FALSE,
1124 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1125 /* max_protection */ VM_PROT_ALL,
1126 /* inheritance */ VM_INHERIT_DEFAULT);
1127 if ((mem_result != KERN_SUCCESS) ||
1128 (seg_offset != (vm_map_offset_t) seg_data)) {
1129 OSKextLog(/* kext */ NULL,
1130 kOSKextLogErrorLevel |
1131 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1132 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1133 seg_data, seg_length, mem_result);
1134 return result;
1135 }
1136
1137 /* And copy it back.
1138 */
1139 memcpy(seg_data, seg_copy, seg_length);
1140
1141 /* Free the copy.
1142 */
1143 kmem_free(kernel_map, seg_copy_offset, seg_length);
1144 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1145 /* Remove the linkedit segment of the Boot KC */
1146 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1147 OSKext::jettisonFileSetLinkeditSegment(mh);
1148 }
1149 #else // !VM_MAPPED_KEXTS
1150 /*****
1151 * Dump the LINKEDIT segment, unless keepsyms is set.
1152 */
1153 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1154 dt_segment_name = "Kernel-__LINKEDIT";
1155 if (0 == IODTGetLoaderInfo(dt_segment_name,
1156 &segment_paddress, &segment_size)) {
1157 #ifdef SECURE_KERNEL
1158 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1159 bzero((void*)vmaddr, segment_size);
1160 #endif
1161 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1162 (int)segment_size);
1163 }
1164 } else {
1165 OSKextLog(/* kext */ NULL,
1166 kOSKextLogBasicLevel |
1167 kOSKextLogGeneralFlag,
1168 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1169 }
1170 #endif // VM_MAPPED_KEXTS
1171
1172 seg_to_remove = NULL;
1173
1174 result = kOSReturnSuccess;
1175
1176 return result;
1177 }
1178
1179 #if CONFIG_KXLD
1180 /*********************************************************************
1181 *********************************************************************/
1182 void
1183 OSKext::flushNonloadedKexts(
1184 Boolean flushPrelinkedKexts)
1185 {
1186 OSSharedPtr<OSSet> keepKexts;
1187
1188 /* TODO: make this more efficient with MH_FILESET kexts */
1189
1190 // Do not unload prelinked kexts on arm because the kernelcache is not
1191 // structured in a way that allows them to be unmapped
1192 #if !defined(__x86_64__)
1193 flushPrelinkedKexts = false;
1194 #endif /* defined(__x86_64__) */
1195
1196 IORecursiveLockLock(sKextLock);
1197
1198 OSKextLog(/* kext */ NULL,
1199 kOSKextLogProgressLevel |
1200 kOSKextLogKextBookkeepingFlag,
1201 "Flushing nonloaded kexts and other unused data.");
1202
1203 OSKext::considerDestroyingLinkContext();
1204
1205 /* If we aren't flushing unused prelinked kexts, we have to put them
1206 * aside while we flush everything else so make a container for them.
1207 */
1208 keepKexts = OSSet::withCapacity(16);
1209 if (!keepKexts) {
1210 goto finish;
1211 }
1212
1213 /* Set aside prelinked kexts (in-use or not) and break
1214 * any lingering inter-kext references for nonloaded kexts
1215 * so they have min. retain counts.
1216 */
1217 {
1218 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1219 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1220 if (!thisKext) {
1221 return false;
1222 }
1223 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1224 keepKexts->setObject(thisKext);
1225 } else if (!thisKext->declaresExecutable()) {
1226 /*
1227 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1228 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1229 * flushNonloadedKexts().
1230 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1231 */
1232 keepKexts->setObject(thisKext);
1233 } else if (thisKext->isInFileset()) {
1234 /* keep all kexts in the new MH_FILESET KC */
1235 keepKexts->setObject(thisKext);
1236 }
1237
1238 thisKext->flushDependencies(/* forceIfLoaded */ false);
1239 return false;
1240 });
1241 }
1242 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1243 */
1244 sKextsByID->flushCollection();
1245
1246 /* Now put the loaded kexts back into the ID dictionary.
1247 */
1248 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1249 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1250 if (!thisKext) {
1251 return false;
1252 }
1253 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1254 return false;
1255 });
1256
1257 /* Finally, put back the kept kexts if we saved any.
1258 */
1259 keepKexts->iterateObjects(^bool (OSObject * obj) {
1260 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1261 if (!thisKext) {
1262 return false;
1263 }
1264 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1265 return false;
1266 });
1267
1268 finish:
1269 IORecursiveLockUnlock(sKextLock);
1270 return;
1271 }
1272 #else /* !CONFIG_KXLD */
1273
1274 void
1275 OSKext::flushNonloadedKexts(
1276 Boolean flushPrelinkedKexts __unused)
1277 {
1278 IORecursiveLockLock(sKextLock);
1279
1280 OSKextLog(/* kext */ NULL,
1281 kOSKextLogProgressLevel |
1282 kOSKextLogKextBookkeepingFlag,
1283 "Flushing dependency info for non-loaded kexts.");
1284
1285 /*
1286 * In a world where we don't dynamically link kexts, they all come
1287 * from a kext collection that's either in wired memory, or
1288 * wire-on-demand. We don't need to mess around with moving kexts in
1289 * and out of the sKextsByID array - they can all just stay there.
1290 * Here we just flush the dependency list for kexts that are not
1291 * loaded.
1292 */
1293 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1294 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1295 if (!thisKext) {
1296 return false;
1297 }
1298 thisKext->flushDependencies(/* forceIfLoaded */ false);
1299 return false;
1300 });
1301
1302 IORecursiveLockUnlock(sKextLock);
1303 return;
1304 }
1305
1306 #endif /* CONFIG_KXLD */
1307
1308 /*********************************************************************
1309 *********************************************************************/
1310 /* static */
1311 void
1312 OSKext::setIOKitDaemonActive(bool active)
1313 {
1314 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1315 IORecursiveLockLock(sKextLock);
1316 sIOKitDaemonActive = active;
1317 if (sKernelRequests->getCount()) {
1318 OSKext::pingIOKitDaemon();
1319 }
1320 IORecursiveLockUnlock(sKextLock);
1321
1322 return;
1323 }
1324
1325 /*********************************************************************
1326 * OSKextLib.cpp might need access to this someday but for now it's
1327 * private.
1328 *********************************************************************/
1329 extern "C" {
1330 extern void ipc_port_release_send(ipc_port_t);
1331 };
1332
1333 /* static */
1334 OSReturn
1335 OSKext::pingIOKitDaemon(void)
1336 {
1337 OSReturn result = kOSReturnError;
1338 #if !NO_KEXTD
1339 mach_port_t kextd_port = IPC_PORT_NULL;
1340
1341 if (!sIOKitDaemonActive) {
1342 result = kOSKextReturnDisabled; // basically unavailable
1343 goto finish;
1344 }
1345
1346 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1347 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1348 OSKextLog(/* kext */ NULL,
1349 kOSKextLogErrorLevel |
1350 kOSKextLogIPCFlag,
1351 "Can't get " kIOKitDaemonName " port.");
1352 goto finish;
1353 }
1354
1355 result = kextd_ping(kextd_port);
1356 if (result != KERN_SUCCESS) {
1357 OSKextLog(/* kext */ NULL,
1358 kOSKextLogErrorLevel |
1359 kOSKextLogIPCFlag,
1360 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1361 goto finish;
1362 }
1363
1364 finish:
1365 if (IPC_PORT_VALID(kextd_port)) {
1366 ipc_port_release_send(kextd_port);
1367 }
1368 #endif
1369
1370 return result;
1371 }
1372
1373 /*********************************************************************
1374 *********************************************************************/
1375 /* static */
1376 void
1377 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1378 {
1379 IORecursiveLockLock(sKextLock);
1380 sDeferredLoadSucceeded = succeeded;
1381 IORecursiveLockUnlock(sKextLock);
1382
1383 return;
1384 }
1385
1386 /*********************************************************************
1387 * Called from IOSystemShutdownNotification.
1388 *********************************************************************/
1389 /* static */
1390 void
1391 OSKext::willShutdown(void)
1392 {
1393 #if !NO_KEXTD
1394 OSReturn checkResult = kOSReturnError;
1395 #endif
1396 OSSharedPtr<OSDictionary> exitRequest;
1397
1398 IORecursiveLockLock(sKextLock);
1399
1400 OSKext::setLoadEnabled(false);
1401 OSKext::setUnloadEnabled(false);
1402 OSKext::setAutounloadsEnabled(false);
1403 OSKext::setKernelRequestsEnabled(false);
1404
1405 #if defined(__x86_64__) || defined(__i386__)
1406 if (IOPMRootDomainGetWillShutdown()) {
1407 OSKext::freeKCFileSetcontrol();
1408 }
1409 #endif // (__x86_64__) || defined(__i386__)
1410
1411 #if !NO_KEXTD
1412 OSKextLog(/* kext */ NULL,
1413 kOSKextLogProgressLevel |
1414 kOSKextLogGeneralFlag,
1415 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1416
1417 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1418 exitRequest);
1419 if (checkResult != kOSReturnSuccess) {
1420 goto finish;
1421 }
1422 if (!sKernelRequests->setObject(exitRequest.get())) {
1423 goto finish;
1424 }
1425
1426 OSKext::pingIOKitDaemon();
1427
1428 finish:
1429 #endif
1430
1431 IORecursiveLockUnlock(sKextLock);
1432 return;
1433 }
1434
1435 void
1436 OSKext::willUserspaceReboot(void)
1437 {
1438 OSKext::willShutdown();
1439 IOService::userSpaceWillReboot();
1440 gIOCatalogue->terminateDriversForUserspaceReboot();
1441 }
1442
1443 void
1444 OSKext::resetAfterUserspaceReboot(void)
1445 {
1446 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1447 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1448
1449 IORecursiveLockLock(sKextLock);
1450 gIOCatalogue->resetAfterUserspaceReboot();
1451 IOService::userSpaceDidReboot();
1452 OSKext::setLoadEnabled(true);
1453 OSKext::setUnloadEnabled(true);
1454 OSKext::setAutounloadsEnabled(true);
1455 OSKext::setKernelRequestsEnabled(true);
1456 sOSKextWasResetAfterUserspaceReboot = true;
1457 IORecursiveLockUnlock(sKextLock);
1458 }
1459
1460 extern "C" void
1461 OSKextResetAfterUserspaceReboot(void)
1462 {
1463 OSKext::resetAfterUserspaceReboot();
1464 }
1465
1466 /*********************************************************************
1467 *********************************************************************/
1468 /* static */
1469 bool
1470 OSKext::getLoadEnabled(void)
1471 {
1472 bool result;
1473
1474 IORecursiveLockLock(sKextLock);
1475 result = sLoadEnabled;
1476 IORecursiveLockUnlock(sKextLock);
1477 return result;
1478 }
1479
1480 /*********************************************************************
1481 *********************************************************************/
1482 /* static */
1483 bool
1484 OSKext::setLoadEnabled(bool flag)
1485 {
1486 bool result;
1487
1488 IORecursiveLockLock(sKextLock);
1489 result = sLoadEnabled;
1490 sLoadEnabled = (flag ? true : false);
1491
1492 if (sLoadEnabled != result) {
1493 OSKextLog(/* kext */ NULL,
1494 kOSKextLogBasicLevel |
1495 kOSKextLogLoadFlag,
1496 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1497 }
1498
1499 IORecursiveLockUnlock(sKextLock);
1500
1501 return result;
1502 }
1503
1504 /*********************************************************************
1505 *********************************************************************/
1506 /* static */
1507 bool
1508 OSKext::getUnloadEnabled(void)
1509 {
1510 bool result;
1511
1512 IORecursiveLockLock(sKextLock);
1513 result = sUnloadEnabled;
1514 IORecursiveLockUnlock(sKextLock);
1515 return result;
1516 }
1517
1518 /*********************************************************************
1519 *********************************************************************/
1520 /* static */
1521 bool
1522 OSKext::setUnloadEnabled(bool flag)
1523 {
1524 bool result;
1525
1526 IORecursiveLockLock(sKextLock);
1527 result = sUnloadEnabled;
1528 sUnloadEnabled = (flag ? true : false);
1529 IORecursiveLockUnlock(sKextLock);
1530
1531 if (sUnloadEnabled != result) {
1532 OSKextLog(/* kext */ NULL,
1533 kOSKextLogBasicLevel |
1534 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1535 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1536 }
1537
1538 return result;
1539 }
1540
1541 /*********************************************************************
1542 * Do not call any function that takes sKextLock here!
1543 *********************************************************************/
1544 /* static */
1545 bool
1546 OSKext::getAutounloadEnabled(void)
1547 {
1548 bool result;
1549
1550 IORecursiveLockLock(sKextInnerLock);
1551 result = sAutounloadEnabled ? true : false;
1552 IORecursiveLockUnlock(sKextInnerLock);
1553 return result;
1554 }
1555
1556 /*********************************************************************
1557 * Do not call any function that takes sKextLock here!
1558 *********************************************************************/
1559 /* static */
1560 bool
1561 OSKext::setAutounloadsEnabled(bool flag)
1562 {
1563 bool result;
1564
1565 IORecursiveLockLock(sKextInnerLock);
1566
1567 result = sAutounloadEnabled;
1568 sAutounloadEnabled = (flag ? true : false);
1569 if (!sAutounloadEnabled && sUnloadCallout) {
1570 thread_call_cancel(sUnloadCallout);
1571 }
1572
1573 if (sAutounloadEnabled != result) {
1574 OSKextLog(/* kext */ NULL,
1575 kOSKextLogBasicLevel |
1576 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1577 "Kext autounloading now %sabled.",
1578 sAutounloadEnabled ? "en" : "dis");
1579 }
1580
1581 IORecursiveLockUnlock(sKextInnerLock);
1582
1583 return result;
1584 }
1585
1586 /*********************************************************************
1587 *********************************************************************/
1588 /* instance method operating on OSKext field */
1589 bool
1590 OSKext::setAutounloadEnabled(bool flag)
1591 {
1592 bool result = flags.autounloadEnabled ? true : false;
1593 flags.autounloadEnabled = flag ? 1 : 0;
1594
1595 if (result != (flag ? true : false)) {
1596 OSKextLog(this,
1597 kOSKextLogProgressLevel |
1598 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1599 "Autounloading for kext %s now %sabled.",
1600 getIdentifierCString(),
1601 flags.autounloadEnabled ? "en" : "dis");
1602 }
1603 return result;
1604 }
1605
1606 /*********************************************************************
1607 *********************************************************************/
1608 /* static */
1609 bool
1610 OSKext::setKernelRequestsEnabled(bool flag)
1611 {
1612 bool result;
1613
1614 IORecursiveLockLock(sKextLock);
1615 result = sKernelRequestsEnabled;
1616 sKernelRequestsEnabled = flag ? true : false;
1617
1618 if (sKernelRequestsEnabled != result) {
1619 OSKextLog(/* kext */ NULL,
1620 kOSKextLogBasicLevel |
1621 kOSKextLogGeneralFlag,
1622 "Kernel requests now %sabled.",
1623 sKernelRequestsEnabled ? "en" : "dis");
1624 }
1625 IORecursiveLockUnlock(sKextLock);
1626 return result;
1627 }
1628
1629 /*********************************************************************
1630 *********************************************************************/
1631 /* static */
1632 bool
1633 OSKext::getKernelRequestsEnabled(void)
1634 {
1635 bool result;
1636
1637 IORecursiveLockLock(sKextLock);
1638 result = sKernelRequestsEnabled;
1639 IORecursiveLockUnlock(sKextLock);
1640 return result;
1641 }
1642
1643 static bool
1644 segmentIsMutable(kernel_segment_command_t *seg)
1645 {
1646 /* Mutable segments have to have VM_PROT_WRITE */
1647 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1648 return false;
1649 }
1650 /* Exclude the __DATA_CONST segment */
1651 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1652 return false;
1653 }
1654 /* Exclude __LINKEDIT */
1655 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1656 return false;
1657 }
1658 return true;
1659 }
1660
1661 #if PRAGMA_MARK
1662 #pragma mark Kext Life Cycle
1663 #endif
1664 /*********************************************************************
1665 *********************************************************************/
1666 OSSharedPtr<OSKext>
1667 OSKext::withPrelinkedInfoDict(
1668 OSDictionary * anInfoDict,
1669 bool doCoalescedSlides,
1670 kc_kind_t type)
1671 {
1672 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1673
1674 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1675 return NULL;
1676 }
1677
1678 return newKext;
1679 }
1680
1681 /*********************************************************************
1682 *********************************************************************/
1683 bool
1684 OSKext::initWithPrelinkedInfoDict(
1685 OSDictionary * anInfoDict,
1686 bool doCoalescedSlides,
1687 kc_kind_t type)
1688 {
1689 bool result = false;
1690 OSString * kextPath = NULL; // do not release
1691 OSNumber * addressNum = NULL; // reused; do not release
1692 OSNumber * lengthNum = NULL; // reused; do not release
1693 OSBoolean * scratchBool = NULL; // do not release
1694 void * data = NULL; // do not free
1695 void * srcData = NULL; // do not free
1696 OSSharedPtr<OSData> prelinkedExecutable;
1697 uint32_t length = 0; // reused
1698 uintptr_t kext_slide = PE_get_kc_slide(type);
1699 bool shouldSaveSegments = false;
1700
1701 if (!super::init()) {
1702 goto finish;
1703 }
1704
1705 /* Get the path. Don't look for an arch-specific path property.
1706 */
1707 kextPath = OSDynamicCast(OSString,
1708 anInfoDict->getObject(kPrelinkBundlePathKey));
1709
1710 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1711 goto finish;
1712 }
1713
1714 #if KASLR_KEXT_DEBUG
1715 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1716 #endif
1717
1718 /* Also get the executable's bundle-relative path if present.
1719 * Don't look for an arch-specific path property.
1720 */
1721 executableRelPath.reset(OSDynamicCast(OSString,
1722 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1723 userExecutableRelPath.reset(OSDynamicCast(OSString,
1724 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1725
1726 /* Don't need the paths to be in the info dictionary any more.
1727 */
1728 anInfoDict->removeObject(kPrelinkBundlePathKey);
1729 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1730
1731 scratchBool = OSDynamicCast(OSBoolean,
1732 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1733 if (scratchBool == kOSBooleanTrue) {
1734 flags.requireExplicitLoad = 1;
1735 }
1736
1737 /* Create an OSData wrapper around the linked executable.
1738 */
1739 addressNum = OSDynamicCast(OSNumber,
1740 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1741 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1742 lengthNum = OSDynamicCast(OSNumber,
1743 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1744 if (!lengthNum) {
1745 OSKextLog(this,
1746 kOSKextLogErrorLevel |
1747 kOSKextLogArchiveFlag,
1748 "Kext %s can't find prelinked kext executable size.",
1749 getIdentifierCString());
1750 return result;
1751 }
1752
1753 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1754 length = (uint32_t) (lengthNum->unsigned32BitValue());
1755
1756 #if KASLR_KEXT_DEBUG
1757 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1758 (unsigned long)ml_static_unslide((vm_offset_t)data),
1759 (unsigned long)data,
1760 length);
1761 #endif
1762
1763 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1764 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1765
1766 /* If the kext's load address differs from its source address, allocate
1767 * space in the kext map at the load address and copy the kext over.
1768 */
1769 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1770 if (addressNum) {
1771 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1772
1773 #if KASLR_KEXT_DEBUG
1774 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1775 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1776 (unsigned long)srcData);
1777 #endif
1778
1779 if (data != srcData) {
1780 #if __LP64__
1781 kern_return_t alloc_result;
1782
1783 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1784 if (alloc_result != KERN_SUCCESS) {
1785 OSKextLog(this,
1786 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1787 "Failed to allocate space for prelinked kext %s.",
1788 getIdentifierCString());
1789 goto finish;
1790 }
1791 memcpy(data, srcData, length);
1792 #else
1793 OSKextLog(this,
1794 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1795 "Error: prelinked kext %s - source and load addresses "
1796 "differ on ILP32 architecture.",
1797 getIdentifierCString());
1798 goto finish;
1799 #endif /* __LP64__ */
1800 }
1801
1802 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1803 }
1804
1805 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1806 if (!prelinkedExecutable) {
1807 OSKextLog(this,
1808 kOSKextLogErrorLevel |
1809 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1810 "Kext %s failed to create executable wrapper.",
1811 getIdentifierCString());
1812 goto finish;
1813 }
1814
1815 #if VM_MAPPED_KEXTS
1816 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1817 #else
1818 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1819 #endif
1820 setLinkedExecutable(prelinkedExecutable.get());
1821 addressNum = OSDynamicCast(OSNumber,
1822 anInfoDict->getObject(kPrelinkKmodInfoKey));
1823 if (!addressNum) {
1824 OSKextLog(this,
1825 kOSKextLogErrorLevel |
1826 kOSKextLogArchiveFlag,
1827 "Kext %s can't find prelinked kext kmod_info address.",
1828 getIdentifierCString());
1829 goto finish;
1830 }
1831
1832 if (addressNum->unsigned64BitValue() != 0) {
1833 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1834 if (kmod_info->address) {
1835 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
1836 } else {
1837 kmod_info->address = (uintptr_t)data;
1838 kmod_info->size = length;
1839 }
1840 #if KASLR_KEXT_DEBUG
1841 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1842 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
1843 (unsigned long)kmod_info);
1844 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1845 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
1846 (unsigned long)kmod_info->address);
1847 #endif
1848 }
1849
1850 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1851 }
1852
1853 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
1854 uintptr_t builtinTextStart;
1855 uintptr_t builtinTextEnd;
1856
1857 flags.builtin = true;
1858 builtinKmodIdx = addressNum->unsigned32BitValue();
1859 assert(builtinKmodIdx < gBuiltinKmodsCount);
1860
1861 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1862 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1863
1864 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1865 kmod_info->address = builtinTextStart;
1866 kmod_info->size = builtinTextEnd - builtinTextStart;
1867 }
1868
1869 /* If the plist has a UUID for an interface, save that off.
1870 */
1871 if (isInterface()) {
1872 interfaceUUID.reset(OSDynamicCast(OSData,
1873 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
1874 if (interfaceUUID) {
1875 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1876 }
1877 }
1878
1879 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
1880 if (!result) {
1881 goto finish;
1882 }
1883
1884 kc_type = type;
1885 /* Exclude builtin and codeless kexts */
1886 if (prelinkedExecutable && kmod_info) {
1887 switch (kc_type) {
1888 case KCKindPrimary:
1889 shouldSaveSegments = (
1890 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
1891 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
1892 if (shouldSaveSegments) {
1893 flags.resetSegmentsFromImmutableCopy = 1;
1894 }
1895 break;
1896 case KCKindPageable:
1897 flags.resetSegmentsFromVnode = 1;
1898 break;
1899 case KCKindAuxiliary:
1900 if (!pageableKCloaded) {
1901 flags.resetSegmentsFromImmutableCopy = 1;
1902 } else if (resetAuxKCSegmentOnUnload) {
1903 flags.resetSegmentsFromVnode = 1;
1904 }
1905 break;
1906 default:
1907 break;
1908 }
1909 }
1910
1911 if (flags.resetSegmentsFromImmutableCopy) {
1912 /* Save a pristine copy of the mutable segments */
1913 kernel_segment_command_t *seg = NULL;
1914 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
1915
1916 savedMutableSegments = OSArray::withCapacity(0);
1917
1918 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
1919 if (!segmentIsMutable(seg)) {
1920 continue;
1921 }
1922 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
1923 uint64_t vmsize = seg->vmsize;
1924 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1925 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1926 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
1927 if (!savedSegment) {
1928 OSKextLog(this,
1929 kOSKextLogErrorLevel |
1930 kOSKextLogGeneralFlag,
1931 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1932 result = kOSKextReturnInternalError;
1933 goto finish;
1934 }
1935 savedMutableSegments->setObject(savedSegment);
1936 }
1937 }
1938
1939 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
1940 /*
1941 * set VM protections now, wire pages for the old style Aux KC now,
1942 * wire pages for the rest of the KC types at load time.
1943 */
1944 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
1945 if (!result) {
1946 goto finish;
1947 }
1948 }
1949
1950 flags.prelinked = true;
1951
1952 /* If we created a kext from prelink info,
1953 * we must be booting from a prelinked kernel.
1954 */
1955 sPrelinkBoot = true;
1956
1957 result = registerIdentifier();
1958
1959 finish:
1960 return result;
1961 }
1962
1963 /*********************************************************************
1964 *********************************************************************/
1965 /* static */
1966 OSSharedPtr<OSKext>
1967 OSKext::withCodelessInfo(OSDictionary * anInfoDict)
1968 {
1969 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
1970
1971 if (newKext && !newKext->initWithCodelessInfo(anInfoDict)) {
1972 return NULL;
1973 }
1974
1975 return newKext;
1976 }
1977
1978 /*********************************************************************
1979 *********************************************************************/
1980 bool
1981 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
1982 {
1983 bool result = false;
1984 OSString * kextPath = NULL; // do not release
1985 OSBoolean * scratchBool = NULL; // do not release
1986
1987 if (anInfoDict == NULL || !super::init()) {
1988 goto finish;
1989 }
1990
1991 /*
1992 * Get the path. Don't look for an arch-specific path property.
1993 */
1994 kextPath = OSDynamicCast(OSString,
1995 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
1996 if (!kextPath) {
1997 OSKextLog(NULL,
1998 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1999 "Requested codeless kext dictionary does not contain the '%s' key",
2000 kKextRequestArgumentCodelessInfoBundlePathKey);
2001 goto finish;
2002 }
2003
2004 uniquePersonalityProperties(anInfoDict);
2005
2006 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2007 goto finish;
2008 }
2009
2010 /*
2011 * This path is meant to initialize codeless kexts only. Refuse
2012 * anything that looks like it has an executable and/or declares
2013 * itself as a kernel component.
2014 */
2015 if (declaresExecutable() || isKernelComponent()) {
2016 OSKextLog(NULL,
2017 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2018 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2019 getIdentifierCString());
2020 goto finish;
2021 }
2022
2023 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2024 boolean_t updated = updateExcludeList(infoDict.get());
2025 if (updated) {
2026 OSKextLog(this,
2027 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2028 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2029 }
2030 }
2031
2032 kc_type = KCKindNone;
2033
2034 scratchBool = OSDynamicCast(OSBoolean,
2035 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2036 if (scratchBool == kOSBooleanTrue) {
2037 flags.requireExplicitLoad = 1;
2038 }
2039
2040 /* Also get the executable's bundle-relative path if present.
2041 * Don't look for an arch-specific path property.
2042 */
2043 userExecutableRelPath.reset(OSDynamicCast(OSString,
2044 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2045
2046 /* remove unnecessary paths from the info dict */
2047 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2048
2049 result = registerIdentifier();
2050
2051 finish:
2052 return result;
2053 }
2054
2055 /*********************************************************************
2056 *********************************************************************/
2057 /* static */
2058 void
2059 OSKext::setAllVMAttributes(void)
2060 {
2061 OSSharedPtr<OSCollectionIterator> kextIterator;
2062 const OSSymbol * thisID = NULL; // do not release
2063
2064 IORecursiveLockLock(sKextLock);
2065
2066 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2067 if (!kextIterator) {
2068 goto finish;
2069 }
2070
2071 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2072 OSKext * thisKext; // do not release
2073
2074 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2075 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2076 continue;
2077 }
2078
2079 if (!thisKext->flags.resetSegmentsFromVnode) {
2080 /*
2081 * set VM protections now, wire pages for the old style Aux KC now,
2082 * wire pages for the rest of the KC types at load time.
2083 */
2084 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2085 }
2086 }
2087
2088 finish:
2089 IORecursiveLockUnlock(sKextLock);
2090
2091 return;
2092 }
2093
2094 /*********************************************************************
2095 *********************************************************************/
2096 OSSharedPtr<OSKext>
2097 OSKext::withBooterData(
2098 OSString * deviceTreeName,
2099 OSData * booterData)
2100 {
2101 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2102
2103 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2104 return NULL;
2105 }
2106
2107 return newKext;
2108 }
2109
2110 /*********************************************************************
2111 *********************************************************************/
2112 typedef struct _BooterKextFileInfo {
2113 uint32_t infoDictPhysAddr;
2114 uint32_t infoDictLength;
2115 uint32_t executablePhysAddr;
2116 uint32_t executableLength;
2117 uint32_t bundlePathPhysAddr;
2118 uint32_t bundlePathLength;
2119 } _BooterKextFileInfo;
2120
2121 bool
2122 OSKext::initWithBooterData(
2123 OSString * deviceTreeName,
2124 OSData * booterData)
2125 {
2126 bool result = false;
2127 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2128 char * infoDictAddr = NULL; // do not free
2129 void * executableAddr = NULL; // do not free
2130 char * bundlePathAddr = NULL; // do not free
2131
2132 OSDictionary * theInfoDict = NULL; // do not release
2133 OSSharedPtr<OSObject> parsedXML;
2134 OSSharedPtr<OSString> kextPath;
2135
2136 OSSharedPtr<OSString> errorString;
2137 OSSharedPtr<OSData> executable;
2138
2139 if (!super::init()) {
2140 goto finish;
2141 }
2142
2143 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2144 if (!kextFileInfo) {
2145 OSKextLog(this,
2146 kOSKextLogErrorLevel |
2147 kOSKextLogGeneralFlag,
2148 "No booter-provided data for kext device tree entry %s.",
2149 deviceTreeName->getCStringNoCopy());
2150 goto finish;
2151 }
2152
2153 /* The info plist must exist or we can't read the kext.
2154 */
2155 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2156 OSKextLog(this,
2157 kOSKextLogErrorLevel |
2158 kOSKextLogGeneralFlag,
2159 "No kext info dictionary for booter device tree entry %s.",
2160 deviceTreeName->getCStringNoCopy());
2161 goto finish;
2162 }
2163
2164 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2165 if (!infoDictAddr) {
2166 OSKextLog(this,
2167 kOSKextLogErrorLevel |
2168 kOSKextLogGeneralFlag,
2169 "Can't translate physical address 0x%x of kext info dictionary "
2170 "for device tree entry %s.",
2171 (int)kextFileInfo->infoDictPhysAddr,
2172 deviceTreeName->getCStringNoCopy());
2173 goto finish;
2174 }
2175
2176 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2177 if (parsedXML) {
2178 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2179 }
2180 if (!theInfoDict) {
2181 const char * errorCString = "(unknown error)";
2182
2183 if (errorString && errorString->getCStringNoCopy()) {
2184 errorCString = errorString->getCStringNoCopy();
2185 } else if (parsedXML) {
2186 errorCString = "not a dictionary";
2187 }
2188 OSKextLog(this,
2189 kOSKextLogErrorLevel |
2190 kOSKextLogGeneralFlag,
2191 "Error unserializing info dictionary for device tree entry %s: %s.",
2192 deviceTreeName->getCStringNoCopy(), errorCString);
2193 goto finish;
2194 }
2195
2196 /* A bundle path is not mandatory.
2197 */
2198 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2199 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2200 if (!bundlePathAddr) {
2201 OSKextLog(this,
2202 kOSKextLogErrorLevel |
2203 kOSKextLogGeneralFlag,
2204 "Can't translate physical address 0x%x of kext bundle path "
2205 "for device tree entry %s.",
2206 (int)kextFileInfo->bundlePathPhysAddr,
2207 deviceTreeName->getCStringNoCopy());
2208 goto finish;
2209 }
2210 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2211
2212 kextPath = OSString::withCString(bundlePathAddr);
2213 if (!kextPath) {
2214 OSKextLog(this,
2215 kOSKextLogErrorLevel |
2216 kOSKextLogGeneralFlag,
2217 "Failed to create wrapper for device tree entry %s kext path %s.",
2218 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2219 goto finish;
2220 }
2221 }
2222
2223 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2224 goto finish;
2225 }
2226
2227 /* An executable is not mandatory.
2228 */
2229 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2230 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2231 if (!executableAddr) {
2232 OSKextLog(this,
2233 kOSKextLogErrorLevel |
2234 kOSKextLogGeneralFlag,
2235 "Can't translate physical address 0x%x of kext executable "
2236 "for device tree entry %s.",
2237 (int)kextFileInfo->executablePhysAddr,
2238 deviceTreeName->getCStringNoCopy());
2239 goto finish;
2240 }
2241
2242 executable = OSData::withBytesNoCopy(executableAddr,
2243 kextFileInfo->executableLength);
2244 if (!executable) {
2245 OSKextLog(this,
2246 kOSKextLogErrorLevel |
2247 kOSKextLogGeneralFlag,
2248 "Failed to create executable wrapper for device tree entry %s.",
2249 deviceTreeName->getCStringNoCopy());
2250 goto finish;
2251 }
2252
2253 /* A kext with an executable needs to retain the whole booterData
2254 * object to keep the executable in memory.
2255 */
2256 if (!setExecutable(executable.get(), booterData)) {
2257 OSKextLog(this,
2258 kOSKextLogErrorLevel |
2259 kOSKextLogGeneralFlag,
2260 "Failed to set kext executable for device tree entry %s.",
2261 deviceTreeName->getCStringNoCopy());
2262 goto finish;
2263 }
2264 }
2265
2266 result = registerIdentifier();
2267
2268 finish:
2269 return result;
2270 }
2271
2272 /*********************************************************************
2273 *********************************************************************/
2274 bool
2275 OSKext::registerIdentifier(void)
2276 {
2277 bool result = false;
2278 OSKext * existingKext = NULL; // do not release
2279 bool existingIsLoaded = false;
2280 bool existingIsPrelinked = false;
2281 bool existingIsCodeless = false;
2282 bool existingIsDext = false;
2283 OSKextVersion newVersion = -1;
2284 OSKextVersion existingVersion = -1;
2285 char newVersionCString[kOSKextVersionMaxLength];
2286 char existingVersionCString[kOSKextVersionMaxLength];
2287 OSSharedPtr<OSData> newUUID;
2288 OSSharedPtr<OSData> existingUUID;
2289
2290 IORecursiveLockLock(sKextLock);
2291
2292 /* Get the new kext's version for checks & log messages.
2293 */
2294 newVersion = getVersion();
2295 OSKextVersionGetString(newVersion, newVersionCString,
2296 kOSKextVersionMaxLength);
2297
2298 /* If we don't have an existing kext with this identifier,
2299 * just record the new kext and we're done!
2300 */
2301 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2302 if (!existingKext) {
2303 sKextsByID->setObject(bundleID.get(), this);
2304 result = true;
2305 goto finish;
2306 }
2307
2308 /* Get the existing kext's version for checks & log messages.
2309 */
2310 existingVersion = existingKext->getVersion();
2311 OSKextVersionGetString(existingVersion,
2312 existingVersionCString, kOSKextVersionMaxLength);
2313
2314 existingIsLoaded = existingKext->isLoaded();
2315 existingIsPrelinked = existingKext->isPrelinked();
2316 existingIsDext = existingKext->isDriverKit();
2317 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2318
2319 /* If we have a non-codeless kext with this identifier that's already
2320 * loaded/prelinked, we can't use the new one, but let's be really
2321 * thorough and check how the two are related for a precise diagnostic
2322 * log message.
2323 *
2324 * This check is valid for kexts that declare an executable and for
2325 * dexts, but not for codeless kexts - we can just replace those.
2326 */
2327 if ((!existingIsCodeless || existingIsDext) &&
2328 (existingIsLoaded || existingIsPrelinked)) {
2329 bool sameVersion = (newVersion == existingVersion);
2330 bool sameExecutable = true; // assume true unless we have UUIDs
2331
2332 /* Only get the UUID if the existing kext is loaded. Doing so
2333 * might have to uncompress an mkext executable and we shouldn't
2334 * take that hit when neither kext is loaded.
2335 *
2336 * Note: there is no decompression that happens when all kexts
2337 * are loaded from kext collecitons.
2338 */
2339 newUUID = copyUUID();
2340 existingUUID = existingKext->copyUUID();
2341
2342 if (existingIsDext && !isDriverKit()) {
2343 OSKextLog(this,
2344 kOSKextLogWarningLevel |
2345 kOSKextLogKextBookkeepingFlag,
2346 "Notice - new kext %s, v%s matches a %s dext"
2347 "with the same bundle ID, v%s.",
2348 getIdentifierCString(), newVersionCString,
2349 (existingIsLoaded ? "loaded" : "prelinked"),
2350 existingVersionCString);
2351 goto finish;
2352 }
2353
2354 /* I'm entirely too paranoid about checking equivalence of executables,
2355 * but I remember nasty problems with it in the past.
2356 *
2357 * - If we have UUIDs for both kexts, compare them.
2358 * - If only one kext has a UUID, they're definitely different.
2359 */
2360 if (newUUID && existingUUID) {
2361 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2362 } else if (newUUID || existingUUID) {
2363 sameExecutable = false;
2364 }
2365
2366 if (!newUUID && !existingUUID) {
2367 /* If there are no UUIDs, we can't really tell that the executables
2368 * are *different* without a lot of work; the loaded kext's
2369 * unrelocated executable is no longer around (and we never had it
2370 * in-kernel for a prelinked kext). We certainly don't want to do
2371 * a whole fake link for the new kext just to compare, either.
2372 */
2373 OSKextLog(this,
2374 kOSKextLogWarningLevel |
2375 kOSKextLogKextBookkeepingFlag,
2376 "Notice - new kext %s, v%s matches %s kext "
2377 "but can't determine if executables are the same (no UUIDs).",
2378 getIdentifierCString(),
2379 newVersionCString,
2380 (existingIsLoaded ? "loaded" : "prelinked"));
2381 }
2382
2383 if (sameVersion && sameExecutable) {
2384 OSKextLog(this,
2385 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2386 kOSKextLogKextBookkeepingFlag,
2387 "Refusing new kext %s, v%s: a %s copy is already present "
2388 "(same version and executable).",
2389 getIdentifierCString(), newVersionCString,
2390 (existingIsLoaded ? "loaded" : "prelinked"));
2391 } else {
2392 if (!sameVersion) {
2393 /* This condition is significant so log it under warnings.
2394 */
2395 OSKextLog(this,
2396 kOSKextLogWarningLevel |
2397 kOSKextLogKextBookkeepingFlag,
2398 "Refusing new kext %s, v%s: already have %s v%s.",
2399 getIdentifierCString(),
2400 newVersionCString,
2401 (existingIsLoaded ? "loaded" : "prelinked"),
2402 existingVersionCString);
2403 } else {
2404 /* This condition is significant so log it under warnings.
2405 */
2406 OSKextLog(this,
2407 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2408 "Refusing new kext %s, v%s: a %s copy with a different "
2409 "executable UUID is already present.",
2410 getIdentifierCString(), newVersionCString,
2411 (existingIsLoaded ? "loaded" : "prelinked"));
2412 }
2413 }
2414 goto finish;
2415 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2416
2417 /* Refuse to allow an existing loaded codeless kext be replaced by a
2418 * normal kext with the same bundle ID.
2419 */
2420 if (existingIsCodeless && declaresExecutable()) {
2421 OSKextLog(this,
2422 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2423 "Refusing new kext %s, v%s: a codeless copy is already %s",
2424 getIdentifierCString(), newVersionCString,
2425 (existingIsLoaded ? "loaded" : "prelinked"));
2426 goto finish;
2427 }
2428
2429 /* Dexts packaged in the BootKC will be protected against replacement
2430 * by non-dexts by the logic above which checks if they are prelinked.
2431 * Dexts which are prelinked into the System KC will be registered
2432 * before any other kexts in the AuxKC are registered, and we never
2433 * put dexts in the AuxKC. Therefore, there is no need to check if an
2434 * existing object is a dext and is being replaced by a non-dext.
2435 * The scenario cannot happen by construction.
2436 *
2437 * See: OSKext::loadFileSetKexts()
2438 */
2439
2440 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2441 * user loads are happening or if we're still in early boot. User agents are
2442 * supposed to resolve dependencies topside and include only the exact
2443 * kexts needed; so we always accept the new kext (in fact we should never
2444 * see an older unloaded copy hanging around).
2445 */
2446 if (sUserLoadsActive) {
2447 sKextsByID->setObject(bundleID.get(), this);
2448 result = true;
2449
2450 OSKextLog(this,
2451 kOSKextLogStepLevel |
2452 kOSKextLogKextBookkeepingFlag,
2453 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2454 getIdentifierCString(),
2455 existingVersionCString,
2456 newVersionCString);
2457
2458 goto finish;
2459 }
2460
2461 /* During early boot, the kext with the highest version always wins out.
2462 * Prelinked kernels will never hit this, but mkexts and booter-read
2463 * kexts might have duplicates.
2464 */
2465 if (newVersion > existingVersion) {
2466 sKextsByID->setObject(bundleID.get(), this);
2467 result = true;
2468
2469 OSKextLog(this,
2470 kOSKextLogStepLevel |
2471 kOSKextLogKextBookkeepingFlag,
2472 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2473 existingVersionCString,
2474 getIdentifierCString(),
2475 newVersionCString);
2476 } else {
2477 OSKextLog(this,
2478 kOSKextLogStepLevel |
2479 kOSKextLogKextBookkeepingFlag,
2480 "Kext %s is already registered with a higher/same version (v%s); "
2481 "dropping newly-added (v%s).",
2482 getIdentifierCString(),
2483 existingVersionCString,
2484 newVersionCString);
2485 }
2486
2487 /* result has been set appropriately by now. */
2488
2489 finish:
2490
2491 IORecursiveLockUnlock(sKextLock);
2492
2493 if (result) {
2494 OSKextLog(this,
2495 kOSKextLogStepLevel |
2496 kOSKextLogKextBookkeepingFlag,
2497 "Kext %s, v%s registered and available for loading.",
2498 getIdentifierCString(), newVersionCString);
2499 }
2500
2501 return result;
2502 }
2503
2504 /*********************************************************************
2505 * Does the bare minimum validation to look up a kext.
2506 * All other validation is done on the spot as needed.
2507 **********************************************************************/
2508 bool
2509 OSKext::setInfoDictionaryAndPath(
2510 OSDictionary * aDictionary,
2511 OSString * aPath)
2512 {
2513 bool result = false;
2514 OSString * bundleIDString = NULL; // do not release
2515 OSString * versionString = NULL; // do not release
2516 OSString * compatibleVersionString = NULL; // do not release
2517 const char * versionCString = NULL; // do not free
2518 const char * compatibleVersionCString = NULL; // do not free
2519 OSBoolean * scratchBool = NULL; // do not release
2520 OSDictionary * scratchDict = NULL; // do not release
2521
2522 if (infoDict) {
2523 panic("Attempt to set info dictionary on a kext "
2524 "that already has one (%s).",
2525 getIdentifierCString());
2526 }
2527
2528 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2529 goto finish;
2530 }
2531
2532 infoDict.reset(aDictionary, OSRetain);
2533
2534 /* Check right away if the info dictionary has any log flags.
2535 */
2536 scratchBool = OSDynamicCast(OSBoolean,
2537 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2538 if (scratchBool == kOSBooleanTrue) {
2539 flags.loggingEnabled = 1;
2540 }
2541
2542 /* The very next thing to get is the bundle identifier. Unlike
2543 * in user space, a kext with no bundle identifier gets axed
2544 * immediately.
2545 */
2546 bundleIDString = OSDynamicCast(OSString,
2547 getPropertyForHostArch(kCFBundleIdentifierKey));
2548 if (!bundleIDString) {
2549 OSKextLog(this,
2550 kOSKextLogErrorLevel |
2551 kOSKextLogValidationFlag,
2552 "CFBundleIdentifier missing/invalid type in kext %s.",
2553 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2554 goto finish;
2555 }
2556 bundleID = OSSymbol::withString(bundleIDString);
2557 if (!bundleID) {
2558 OSKextLog(this,
2559 kOSKextLogErrorLevel |
2560 kOSKextLogValidationFlag,
2561 "Can't copy bundle identifier as symbol for kext %s.",
2562 bundleIDString->getCStringNoCopy());
2563 goto finish;
2564 }
2565
2566 /* Save the path if we got one (it should always be available but it's
2567 * just something nice to have for bookkeeping).
2568 */
2569 if (aPath) {
2570 path.reset(aPath, OSRetain);
2571 }
2572
2573 /*****
2574 * Minimal validation to initialize. We'll do other validation on the spot.
2575 */
2576 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2577 OSKextLog(this,
2578 kOSKextLogErrorLevel |
2579 kOSKextLogValidationFlag,
2580 "Kext %s error - CFBundleIdentifier over max length %d.",
2581 getIdentifierCString(), KMOD_MAX_NAME - 1);
2582 goto finish;
2583 }
2584
2585 version = compatibleVersion = -1;
2586
2587 versionString = OSDynamicCast(OSString,
2588 getPropertyForHostArch(kCFBundleVersionKey));
2589 if (!versionString) {
2590 OSKextLog(this,
2591 kOSKextLogErrorLevel |
2592 kOSKextLogValidationFlag,
2593 "Kext %s error - CFBundleVersion missing/invalid type.",
2594 getIdentifierCString());
2595 goto finish;
2596 }
2597 versionCString = versionString->getCStringNoCopy();
2598 version = OSKextParseVersionString(versionCString);
2599 if (version < 0) {
2600 OSKextLog(this,
2601 kOSKextLogErrorLevel |
2602 kOSKextLogValidationFlag,
2603 "Kext %s error - CFBundleVersion bad value '%s'.",
2604 getIdentifierCString(), versionCString);
2605 goto finish;
2606 }
2607
2608 compatibleVersion = -1; // set to illegal value for kexts that don't have
2609
2610 compatibleVersionString = OSDynamicCast(OSString,
2611 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2612 if (compatibleVersionString) {
2613 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2614 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2615 if (compatibleVersion < 0) {
2616 OSKextLog(this,
2617 kOSKextLogErrorLevel |
2618 kOSKextLogValidationFlag,
2619 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2620 getIdentifierCString(), compatibleVersionCString);
2621 goto finish;
2622 }
2623
2624 if (compatibleVersion > version) {
2625 OSKextLog(this,
2626 kOSKextLogErrorLevel |
2627 kOSKextLogValidationFlag,
2628 "Kext %s error - %s %s > %s %s (must be <=).",
2629 getIdentifierCString(),
2630 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2631 kCFBundleVersionKey, versionCString);
2632 goto finish;
2633 }
2634 }
2635
2636 /* Check to see if this kext is in exclude list */
2637 if (isInExcludeList()) {
2638 OSKextLog(this,
2639 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2640 "Kext %s is in exclude list, not loadable",
2641 getIdentifierCString());
2642 goto finish;
2643 }
2644
2645 /* Set flags for later use if the infoDict gets flushed. We only
2646 * check for true values, not false ones(!)
2647 */
2648 scratchBool = OSDynamicCast(OSBoolean,
2649 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2650 if (scratchBool == kOSBooleanTrue) {
2651 flags.interface = 1;
2652 }
2653
2654 scratchBool = OSDynamicCast(OSBoolean,
2655 getPropertyForHostArch(kOSKernelResourceKey));
2656 if (scratchBool == kOSBooleanTrue) {
2657 flags.kernelComponent = 1;
2658 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2659 flags.started = 1;
2660
2661 /* A kernel component has one implicit dependency on the kernel.
2662 */
2663 flags.hasAllDependencies = 1;
2664 }
2665
2666 /* Make sure common string values in personalities are uniqued to OSSymbols.
2667 */
2668 scratchDict = OSDynamicCast(OSDictionary,
2669 getPropertyForHostArch(kIOKitPersonalitiesKey));
2670 if (scratchDict) {
2671 uniquePersonalityProperties(scratchDict);
2672 }
2673
2674 result = true;
2675
2676 finish:
2677
2678 return result;
2679 }
2680
2681 /*********************************************************************
2682 * Not used for prelinked kernel boot as there is no unrelocated
2683 * executable.
2684 *********************************************************************/
2685 bool
2686 OSKext::setExecutable(
2687 OSData * anExecutable,
2688 OSData * externalData,
2689 bool externalDataIsMkext)
2690 {
2691 bool result = false;
2692 const char * executableKey = NULL; // do not free
2693
2694 if (!anExecutable) {
2695 infoDict->removeObject(_kOSKextExecutableKey);
2696 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2697 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2698 result = true;
2699 goto finish;
2700 }
2701
2702 if (infoDict->getObject(_kOSKextExecutableKey) ||
2703 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2704 panic("Attempt to set an executable on a kext "
2705 "that already has one (%s).",
2706 getIdentifierCString());
2707 goto finish;
2708 }
2709
2710 if (externalDataIsMkext) {
2711 executableKey = _kOSKextMkextExecutableReferenceKey;
2712 } else {
2713 executableKey = _kOSKextExecutableKey;
2714 }
2715
2716 if (anExecutable) {
2717 infoDict->setObject(executableKey, anExecutable);
2718 if (externalData) {
2719 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2720 }
2721 }
2722
2723 result = true;
2724
2725 finish:
2726 return result;
2727 }
2728
2729 /*********************************************************************
2730 *********************************************************************/
2731 static void
2732 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2733 {
2734 OSObject * value = NULL; // do not release
2735 OSString * stringValue = NULL; // do not release
2736 OSSharedPtr<const OSSymbol> symbolValue;
2737
2738 value = dict->getObject(key);
2739 if (!value) {
2740 goto finish;
2741 }
2742 if (OSDynamicCast(OSSymbol, value)) {
2743 /* this is already an OSSymbol: we're good */
2744 goto finish;
2745 }
2746
2747 stringValue = OSDynamicCast(OSString, value);
2748 if (!stringValue) {
2749 goto finish;
2750 }
2751
2752 symbolValue = OSSymbol::withString(stringValue);
2753 if (!symbolValue) {
2754 goto finish;
2755 }
2756
2757 dict->setObject(key, symbolValue.get());
2758
2759 finish:
2760 return;
2761 }
2762
2763 /*********************************************************************
2764 *********************************************************************/
2765 static void
2766 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2767 {
2768 OSObject * value = NULL; // do not release
2769 OSString * stringValue = NULL; // do not release
2770 OSSharedPtr<const OSSymbol> symbolValue;
2771
2772 value = dict->getObject(key);
2773 if (!value) {
2774 goto finish;
2775 }
2776 if (OSDynamicCast(OSSymbol, value)) {
2777 /* this is already an OSSymbol: we're good */
2778 goto finish;
2779 }
2780
2781 stringValue = OSDynamicCast(OSString, value);
2782 if (!stringValue) {
2783 goto finish;
2784 }
2785
2786 symbolValue = OSSymbol::withString(stringValue);
2787 if (!symbolValue) {
2788 goto finish;
2789 }
2790
2791 dict->setObject(key, symbolValue.get());
2792
2793 finish:
2794 return;
2795 }
2796
2797 void
2798 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2799 {
2800 OSKext::uniquePersonalityProperties(personalityDict, true);
2801 }
2802
2803 /*********************************************************************
2804 * Replace common personality property values with uniqued instances
2805 * to save on wired memory.
2806 *********************************************************************/
2807 /* static */
2808 void
2809 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
2810 {
2811 /* Properties every personality has.
2812 */
2813 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2814 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2815 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
2816 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
2817 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
2818 } else if (defaultAddKernelBundleIdentifier) {
2819 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
2820 }
2821
2822 /* Other commonly used properties.
2823 */
2824 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2825 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2826 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2827
2828 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2829 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2830 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2831 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2832 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2833 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2834 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2835 uniqueStringPlistProperty(personalityDict, "Vendor");
2836 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2837 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2838 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2839 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2840 uniqueStringPlistProperty(personalityDict, "idProduct");
2841
2842 return;
2843 }
2844
2845 /*********************************************************************
2846 *********************************************************************/
2847 void
2848 OSKext::free(void)
2849 {
2850 if (isLoaded()) {
2851 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2852 }
2853
2854 infoDict.reset();
2855 bundleID.reset();
2856 path.reset();
2857 executableRelPath.reset();
2858 userExecutableRelPath.reset();
2859 dependencies.reset();
2860 linkedExecutable.reset();
2861 metaClasses.reset();
2862 interfaceUUID.reset();
2863 driverKitUUID.reset();
2864
2865 if (isInterface() && kmod_info) {
2866 kfree(kmod_info, sizeof(kmod_info_t));
2867 }
2868
2869 super::free();
2870 return;
2871 }
2872
2873 #if PRAGMA_MARK
2874 #pragma mark Mkext files
2875 #endif
2876
2877 #if CONFIG_KXLD
2878 /*
2879 * mkext archives are really only relevant on kxld-enabled kernels.
2880 * Without a dynamic kernel linker, we don't need to support any mkexts.
2881 */
2882
2883 /*********************************************************************
2884 *********************************************************************/
2885 OSReturn
2886 OSKext::readMkextArchive(OSData * mkextData,
2887 uint32_t * checksumPtr)
2888 {
2889 OSReturn result = kOSKextReturnBadData;
2890 uint32_t mkextLength = 0;
2891 mkext_header * mkextHeader = NULL; // do not free
2892 uint32_t mkextVersion = 0;
2893
2894 /* Note default return of kOSKextReturnBadData above.
2895 */
2896 mkextLength = mkextData->getLength();
2897 if (mkextLength < sizeof(mkext_basic_header)) {
2898 OSKextLog(/* kext */ NULL,
2899 kOSKextLogErrorLevel |
2900 kOSKextLogArchiveFlag,
2901 "Mkext archive too small to be valid.");
2902 goto finish;
2903 }
2904
2905 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2906
2907 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2908 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2909 OSKextLog(/* kext */ NULL,
2910 kOSKextLogErrorLevel |
2911 kOSKextLogArchiveFlag,
2912 "Mkext archive has invalid magic or signature.");
2913 goto finish;
2914 }
2915
2916 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2917 OSKextLog(/* kext */ NULL,
2918 kOSKextLogErrorLevel |
2919 kOSKextLogArchiveFlag,
2920 "Mkext archive recorded length doesn't match actual file length.");
2921 goto finish;
2922 }
2923
2924 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2925
2926 if (mkextVersion == MKEXT_VERS_2) {
2927 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2928 } else {
2929 OSKextLog(/* kext */ NULL,
2930 kOSKextLogErrorLevel |
2931 kOSKextLogArchiveFlag,
2932 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2933 result = kOSKextReturnUnsupported;
2934 }
2935
2936 finish:
2937 return result;
2938 }
2939
2940 /*********************************************************************
2941 * Assumes magic, signature, version, length have been checked.
2942 * xxx - need to add further bounds checking for each file entry
2943 *
2944 * Should keep track of all kexts created so far, and if we hit a
2945 * fatal error halfway through, remove those kexts. If we've dropped
2946 * an older version that had already been read, whoops! Might want to
2947 * add a level of buffering?
2948 *********************************************************************/
2949 /* static */
2950 OSReturn
2951 OSKext::readMkext2Archive(
2952 OSData * mkextData,
2953 OSDictionary ** mkextPlistOut,
2954 uint32_t * checksumPtr)
2955 {
2956 OSReturn result = kOSReturnError;
2957 uint32_t mkextLength;
2958 mkext2_header * mkextHeader = NULL; // do not free
2959 void * mkextEnd = NULL; // do not free
2960 uint32_t mkextVersion;
2961 uint8_t * crc_address = NULL;
2962 size_t crc_buffer_size = 0;
2963 uint32_t checksum;
2964 uint32_t mkextPlistOffset;
2965 uint32_t mkextPlistCompressedSize;
2966 char * mkextPlistEnd = NULL; // do not free
2967 uint32_t mkextPlistFullSize;
2968 OSSharedPtr<OSString> errorString;
2969 OSSharedPtr<OSData> mkextPlistUncompressedData;
2970 const char * mkextPlistDataBuffer = NULL; // do not free
2971 OSSharedPtr<OSObject> parsedXML;
2972 OSDictionary * mkextPlist = NULL; // do not release
2973 OSArray * mkextInfoDictArray = NULL; // do not release
2974 uint32_t count, i;
2975 kc_format_t kc_format;
2976
2977 if (!PE_get_primary_kc_format(&kc_format)) {
2978 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2979 "Unable to determine primary KC format");
2980 goto finish;
2981 }
2982
2983 mkextLength = mkextData->getLength();
2984 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
2985 mkextEnd = (char *)mkextHeader + mkextLength;
2986 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2987
2988 crc_address = (u_int8_t *)&mkextHeader->version;
2989 crc_buffer_size = (uintptr_t)mkextHeader +
2990 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
2991 if (crc_buffer_size > INT32_MAX) {
2992 OSKextLog(/* kext */ NULL,
2993 kOSKextLogErrorLevel |
2994 kOSKextLogArchiveFlag,
2995 "Mkext archive size is too large (%lu > INT32_MAX).",
2996 crc_buffer_size);
2997 result = kOSKextReturnBadData;
2998 goto finish;
2999 }
3000 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3001
3002 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3003 OSKextLog(/* kext */ NULL,
3004 kOSKextLogErrorLevel |
3005 kOSKextLogArchiveFlag,
3006 "Mkext archive has bad checksum.");
3007 result = kOSKextReturnBadData;
3008 goto finish;
3009 }
3010
3011 if (checksumPtr) {
3012 *checksumPtr = checksum;
3013 }
3014
3015 /* Check that the CPU type & subtype match that of the running kernel. */
3016 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3017 OSKextLog(/* kext */ NULL,
3018 kOSKextLogErrorLevel |
3019 kOSKextLogArchiveFlag,
3020 "Mkext archive must have a specific CPU type.");
3021 result = kOSKextReturnBadData;
3022 goto finish;
3023 } else {
3024 if ((UInt32)_mh_execute_header.cputype !=
3025 MKEXT_GET_CPUTYPE(mkextHeader)) {
3026 OSKextLog(/* kext */ NULL,
3027 kOSKextLogErrorLevel |
3028 kOSKextLogArchiveFlag,
3029 "Mkext archive does not match the running kernel's CPU type.");
3030 result = kOSKextReturnArchNotFound;
3031 goto finish;
3032 }
3033 }
3034
3035 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3036 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3037 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3038 mkextPlistCompressedSize;
3039 if (mkextPlistEnd > mkextEnd) {
3040 OSKextLog(/* kext */ NULL,
3041 kOSKextLogErrorLevel |
3042 kOSKextLogArchiveFlag,
3043 "Mkext archive file overrun.");
3044 result = kOSKextReturnBadData;
3045 }
3046
3047 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3048 if (mkextPlistCompressedSize) {
3049 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3050 (UInt8 *)mkextHeader + mkextPlistOffset,
3051 "plist",
3052 mkextPlistCompressedSize, mkextPlistFullSize);
3053 if (!mkextPlistUncompressedData) {
3054 goto finish;
3055 }
3056 mkextPlistDataBuffer = (const char *)
3057 mkextPlistUncompressedData->getBytesNoCopy();
3058 } else {
3059 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3060 }
3061
3062 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3063 */
3064 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3065 if (parsedXML) {
3066 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3067 }
3068 if (!mkextPlist) {
3069 const char * errorCString = "(unknown error)";
3070
3071 if (errorString && errorString->getCStringNoCopy()) {
3072 errorCString = errorString->getCStringNoCopy();
3073 } else if (parsedXML) {
3074 errorCString = "not a dictionary";
3075 }
3076 OSKextLog(/* kext */ NULL,
3077 kOSKextLogErrorLevel |
3078 kOSKextLogArchiveFlag,
3079 "Error unserializing mkext plist: %s.", errorCString);
3080 goto finish;
3081 }
3082
3083 mkextInfoDictArray = OSDynamicCast(OSArray,
3084 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3085 if (!mkextInfoDictArray) {
3086 OSKextLog(/* kext */ NULL,
3087 kOSKextLogErrorLevel |
3088 kOSKextLogArchiveFlag,
3089 "Mkext archive contains no kext info dictionaries.");
3090 goto finish;
3091 }
3092
3093 count = mkextInfoDictArray->getCount();
3094 for (i = 0; i < count; i++) {
3095 OSDictionary * infoDict;
3096
3097
3098 infoDict = OSDynamicCast(OSDictionary,
3099 mkextInfoDictArray->getObject(i));
3100
3101 /* Create the kext for the entry, then release it, because the
3102 * kext system keeps them around until explicitly removed.
3103 * Any creation/registration failures are already logged for us.
3104 */
3105 if (infoDict) {
3106 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3107
3108 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3109 if (kc_format == KCFormatFileset &&
3110 newKext &&
3111 !(newKext->isPrelinked()) &&
3112 newKext->declaresExecutable()) {
3113 result = kOSReturnError;
3114 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3115 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3116
3117 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3118 "Dynamic loading of kext denied for kext %s\n",
3119 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3120 goto finish;
3121 }
3122 }
3123 }
3124
3125 /* If the caller needs the plist, hand them back our copy
3126 */
3127 if (mkextPlistOut) {
3128 *mkextPlistOut = mkextPlist;
3129 parsedXML.detach();
3130 }
3131
3132 /* Even if we didn't keep any kexts from the mkext, we may have a load
3133 * request to process, so we are successful (no errors occurred).
3134 */
3135 result = kOSReturnSuccess;
3136
3137 finish:
3138 return result;
3139 }
3140
3141 /* static */
3142 OSReturn
3143 OSKext::readMkext2Archive(
3144 OSData * mkextData,
3145 OSSharedPtr<OSDictionary> &mkextPlistOut,
3146 uint32_t * checksumPtr)
3147 {
3148 OSDictionary * mkextPlist = NULL;
3149 OSReturn ret;
3150
3151 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3152 &mkextPlist,
3153 checksumPtr))) {
3154 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3155 }
3156 return ret;
3157 }
3158
3159 /*********************************************************************
3160 *********************************************************************/
3161 /* static */
3162 OSSharedPtr<OSKext>
3163 OSKext::withMkext2Info(
3164 OSDictionary * anInfoDict,
3165 OSData * mkextData)
3166 {
3167 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3168
3169 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3170 return NULL;
3171 }
3172
3173 return newKext;
3174 }
3175
3176 /*********************************************************************
3177 *********************************************************************/
3178 bool
3179 OSKext::initWithMkext2Info(
3180 OSDictionary * anInfoDict,
3181 OSData * mkextData)
3182 {
3183 bool result = false;
3184 OSString * kextPath = NULL; // do not release
3185 OSNumber * executableOffsetNum = NULL; // do not release
3186 OSSharedPtr<OSData> executable;
3187
3188 if (anInfoDict == NULL || !super::init()) {
3189 goto finish;
3190 }
3191
3192 /* Get the path. Don't look for an arch-specific path property.
3193 */
3194 kextPath = OSDynamicCast(OSString,
3195 anInfoDict->getObject(kMKEXTBundlePathKey));
3196
3197 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3198 goto finish;
3199 }
3200
3201 /* If we have a path to the executable, save it.
3202 */
3203 executableRelPath.reset(OSDynamicCast(OSString,
3204 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3205
3206 /* Don't need the paths to be in the info dictionary any more.
3207 */
3208 anInfoDict->removeObject(kMKEXTBundlePathKey);
3209 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3210
3211 executableOffsetNum = OSDynamicCast(OSNumber,
3212 infoDict->getObject(kMKEXTExecutableKey));
3213 if (executableOffsetNum) {
3214 executable = createMkext2FileEntry(mkextData,
3215 executableOffsetNum, "executable");
3216 infoDict->removeObject(kMKEXTExecutableKey);
3217 if (!executable) {
3218 goto finish;
3219 }
3220 if (!setExecutable(executable.get(), mkextData, true)) {
3221 goto finish;
3222 }
3223 }
3224
3225 result = registerIdentifier();
3226
3227 finish:
3228 return result;
3229 }
3230
3231 /*********************************************************************
3232 *********************************************************************/
3233 OSSharedPtr<OSData>
3234 OSKext::createMkext2FileEntry(
3235 OSData * mkextData,
3236 OSNumber * offsetNum,
3237 const char * name)
3238 {
3239 OSSharedPtr<OSData> result;
3240 MkextEntryRef entryRef;
3241 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3242 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3243
3244 result = OSData::withCapacity(sizeof(entryRef));
3245 if (!result) {
3246 goto finish;
3247 }
3248
3249 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3250 entryRef.fileinfo = mkextBuffer + entryOffset;
3251 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
3252 result.reset();
3253 goto finish;
3254 }
3255
3256 finish:
3257 if (!result) {
3258 OSKextLog(this,
3259 kOSKextLogErrorLevel |
3260 kOSKextLogArchiveFlag,
3261 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3262 name, getIdentifierCString());
3263 }
3264 return result;
3265 }
3266
3267 /*********************************************************************
3268 *********************************************************************/
3269 extern "C" {
3270 static void * z_alloc(void *, u_int items, u_int size);
3271 static void z_free(void *, void *ptr);
3272
3273 typedef struct z_mem {
3274 uint32_t alloc_size;
3275 uint8_t data[0];
3276 } z_mem;
3277
3278 /*
3279 * Space allocation and freeing routines for use by zlib routines.
3280 */
3281 void *
3282 z_alloc(void * notused __unused, u_int num_items, u_int size)
3283 {
3284 void * result = NULL;
3285 z_mem * zmem = NULL;
3286
3287 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3288 //Check for overflow due to multiplication
3289 if (total > UINT32_MAX) {
3290 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
3291 notused, num_items, size, num_items, size);
3292 }
3293
3294 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3295 //Check for overflow due to addition
3296 if (allocSize64 > UINT32_MAX) {
3297 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
3298 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3299 }
3300 uint32_t allocSize = (uint32_t)allocSize64;
3301
3302 zmem = (z_mem *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, allocSize,
3303 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
3304 if (!zmem) {
3305 goto finish;
3306 }
3307 zmem->alloc_size = allocSize;
3308 result = (void *)&(zmem->data);
3309 finish:
3310 return result;
3311 }
3312
3313 void
3314 z_free(void * notused __unused, void * ptr)
3315 {
3316 uint32_t * skipper = (uint32_t *)ptr - 1;
3317 z_mem * zmem = (z_mem *)skipper;
3318 kheap_free(KHEAP_DATA_BUFFERS, zmem, zmem->alloc_size);
3319 return;
3320 }
3321 };
3322
3323 OSSharedPtr<OSData>
3324 OSKext::extractMkext2FileData(
3325 UInt8 * data,
3326 const char * name,
3327 uint32_t compressedSize,
3328 uint32_t fullSize)
3329 {
3330 OSSharedPtr<OSData> result;
3331 OSSharedPtr<OSData> uncompressedData; // release on error
3332
3333 uint8_t * uncompressedDataBuffer = NULL; // do not free
3334 unsigned long uncompressedSize;
3335 z_stream zstream;
3336 bool zstream_inited = false;
3337 int zlib_result;
3338
3339 /* If the file isn't compressed, we want to make a copy
3340 * so that we don't have the tie to the larger mkext file buffer any more.
3341 */
3342 if (!compressedSize) {
3343 uncompressedData = OSData::withBytes(data, fullSize);
3344 // xxx - no check for failure?
3345 result = uncompressedData;
3346 goto finish;
3347 }
3348
3349 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3350 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
3351 /* How's this for cheesy? The kernel is only asked to extract
3352 * kext plists so we tailor the log messages.
3353 */
3354 if (isKernel()) {
3355 OSKextLog(this,
3356 kOSKextLogErrorLevel |
3357 kOSKextLogArchiveFlag,
3358 "Allocation failure extracting %s from mkext.", name);
3359 } else {
3360 OSKextLog(this,
3361 kOSKextLogErrorLevel |
3362 kOSKextLogArchiveFlag,
3363 "Allocation failure extracting %s from mkext for kext %s.",
3364 name, getIdentifierCString());
3365 }
3366
3367 goto finish;
3368 }
3369 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3370 if (!uncompressedData) {
3371 if (isKernel()) {
3372 OSKextLog(this,
3373 kOSKextLogErrorLevel |
3374 kOSKextLogArchiveFlag,
3375 "Allocation failure extracting %s from mkext.", name);
3376 } else {
3377 OSKextLog(this,
3378 kOSKextLogErrorLevel |
3379 kOSKextLogArchiveFlag,
3380 "Allocation failure extracting %s from mkext for kext %s.",
3381 name, getIdentifierCString());
3382 }
3383 goto finish;
3384 }
3385 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3386
3387 if (isKernel()) {
3388 OSKextLog(this,
3389 kOSKextLogDetailLevel |
3390 kOSKextLogArchiveFlag,
3391 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3392 name, compressedSize, fullSize);
3393 } else {
3394 OSKextLog(this,
3395 kOSKextLogDetailLevel |
3396 kOSKextLogArchiveFlag,
3397 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3398 getIdentifierCString(), name, compressedSize, fullSize);
3399 }
3400
3401 bzero(&zstream, sizeof(zstream));
3402 zstream.next_in = (UInt8 *)data;
3403 zstream.avail_in = compressedSize;
3404
3405 zstream.next_out = uncompressedDataBuffer;
3406 zstream.avail_out = fullSize;
3407
3408 zstream.zalloc = z_alloc;
3409 zstream.zfree = z_free;
3410
3411 zlib_result = inflateInit(&zstream);
3412 if (Z_OK != zlib_result) {
3413 if (isKernel()) {
3414 OSKextLog(this,
3415 kOSKextLogErrorLevel |
3416 kOSKextLogArchiveFlag,
3417 "Mkext error; zlib inflateInit failed (%d) for %s.",
3418 zlib_result, name);
3419 } else {
3420 OSKextLog(this,
3421 kOSKextLogErrorLevel |
3422 kOSKextLogArchiveFlag,
3423 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3424 getIdentifierCString(), zlib_result, name);
3425 }
3426 goto finish;
3427 } else {
3428 zstream_inited = true;
3429 }
3430
3431 zlib_result = inflate(&zstream, Z_FINISH);
3432
3433 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3434 uncompressedSize = zstream.total_out;
3435 } else {
3436 if (isKernel()) {
3437 OSKextLog(this,
3438 kOSKextLogErrorLevel |
3439 kOSKextLogArchiveFlag,
3440 "Mkext error; zlib inflate failed (%d) for %s.",
3441 zlib_result, name);
3442 } else {
3443 OSKextLog(this,
3444 kOSKextLogErrorLevel |
3445 kOSKextLogArchiveFlag,
3446 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3447 getIdentifierCString(), zlib_result, name);
3448 }
3449 if (zstream.msg) {
3450 OSKextLog(this,
3451 kOSKextLogErrorLevel |
3452 kOSKextLogArchiveFlag,
3453 "zlib error: %s.", zstream.msg);
3454 }
3455 goto finish;
3456 }
3457
3458 if (uncompressedSize != fullSize) {
3459 if (isKernel()) {
3460 OSKextLog(this,
3461 kOSKextLogErrorLevel |
3462 kOSKextLogArchiveFlag,
3463 "Mkext error; zlib inflate discrepancy for %s, "
3464 "uncompressed size != original size.", name);
3465 } else {
3466 OSKextLog(this,
3467 kOSKextLogErrorLevel |
3468 kOSKextLogArchiveFlag,
3469 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3470 "uncompressed size != original size.",
3471 getIdentifierCString(), name);
3472 }
3473 goto finish;
3474 }
3475
3476 result = os::move(uncompressedData);
3477
3478 finish:
3479 /* Don't bother checking return, nothing we can do on fail.
3480 */
3481 if (zstream_inited) {
3482 inflateEnd(&zstream);
3483 }
3484
3485 return result;
3486 }
3487
3488 /*********************************************************************
3489 *********************************************************************/
3490 /* static */
3491 OSReturn
3492 OSKext::loadFromMkext(
3493 OSKextLogSpec clientLogFilter,
3494 char * mkextBuffer,
3495 uint32_t mkextBufferLength,
3496 char ** logInfoOut,
3497 uint32_t * logInfoLengthOut)
3498 {
3499 OSReturn result = kOSReturnError;
3500 OSReturn tempResult = kOSReturnError;
3501
3502 OSSharedPtr<OSData> mkextData;
3503 OSSharedPtr<OSDictionary> mkextPlist;
3504
3505 OSSharedPtr<OSArray> logInfoArray;
3506 OSSharedPtr<OSSerialize> serializer;
3507
3508 OSString * predicate = NULL; // do not release
3509 OSDictionary * requestArgs = NULL; // do not release
3510
3511 OSString * kextIdentifier = NULL; // do not release
3512 OSNumber * startKextExcludeNum = NULL; // do not release
3513 OSNumber * startMatchingExcludeNum = NULL; // do not release
3514 OSBoolean * delayAutounloadBool = NULL; // do not release
3515 OSArray * personalityNames = NULL; // do not release
3516
3517 /* Default values for these two options: regular autounload behavior,
3518 * load all kexts, send no personalities.
3519 */
3520 Boolean delayAutounload = false;
3521 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3522 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3523
3524 IORecursiveLockLock(sKextLock);
3525
3526 if (logInfoOut) {
3527 *logInfoOut = NULL;
3528 *logInfoLengthOut = 0;
3529 }
3530
3531 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3532
3533 OSKextLog(/* kext */ NULL,
3534 kOSKextLogDebugLevel |
3535 kOSKextLogIPCFlag,
3536 "Received kext load request from user space.");
3537
3538 /* Regardless of processing, the fact that we have gotten here means some
3539 * user-space program is up and talking to us, so we'll switch our kext
3540 * registration to reflect that.
3541 */
3542 if (!sUserLoadsActive) {
3543 OSKextLog(/* kext */ NULL,
3544 kOSKextLogProgressLevel |
3545 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3546 "Switching to late startup (user-space) kext loading policy.");
3547
3548 sUserLoadsActive = true;
3549 }
3550
3551 if (!sLoadEnabled) {
3552 OSKextLog(/* kext */ NULL,
3553 kOSKextLogErrorLevel |
3554 kOSKextLogLoadFlag,
3555 "Kext loading is disabled.");
3556 result = kOSKextReturnDisabled;
3557 goto finish;
3558 }
3559
3560 /* Note that we do not set a dealloc function on this OSData
3561 * object! No references to it can remain after the loadFromMkext()
3562 * call since we are in a MIG function, and will vm_deallocate()
3563 * the buffer.
3564 */
3565 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3566 mkextBufferLength);
3567 if (!mkextData) {
3568 OSKextLog(/* kext */ NULL,
3569 kOSKextLogErrorLevel |
3570 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3571 "Failed to create wrapper for kext load request.");
3572 result = kOSKextReturnNoMemory;
3573 goto finish;
3574 }
3575
3576 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3577 if (result != kOSReturnSuccess) {
3578 OSKextLog(/* kext */ NULL,
3579 kOSKextLogErrorLevel |
3580 kOSKextLogLoadFlag,
3581 "Failed to read kext load request.");
3582 goto finish;
3583 }
3584
3585 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3586 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3587 OSKextLog(/* kext */ NULL,
3588 kOSKextLogErrorLevel |
3589 kOSKextLogLoadFlag,
3590 "Received kext load request with no predicate; skipping.");
3591 result = kOSKextReturnInvalidArgument;
3592 goto finish;
3593 }
3594
3595 requestArgs = OSDynamicCast(OSDictionary,
3596 mkextPlist->getObject(kKextRequestArgumentsKey));
3597 if (!requestArgs || !requestArgs->getCount()) {
3598 OSKextLog(/* kext */ NULL,
3599 kOSKextLogErrorLevel |
3600 kOSKextLogLoadFlag,
3601 "Received kext load request with no arguments.");
3602 result = kOSKextReturnInvalidArgument;
3603 goto finish;
3604 }
3605
3606 kextIdentifier = OSDynamicCast(OSString,
3607 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3608
3609 if (!kextIdentifier) {
3610 OSKextLog(/* kext */ NULL,
3611 kOSKextLogErrorLevel |
3612 kOSKextLogLoadFlag,
3613 "Received kext load request with no kext identifier.");
3614 result = kOSKextReturnInvalidArgument;
3615 goto finish;
3616 }
3617
3618 startKextExcludeNum = OSDynamicCast(OSNumber,
3619 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3620 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3621 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3622 delayAutounloadBool = OSDynamicCast(OSBoolean,
3623 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3624 personalityNames = OSDynamicCast(OSArray,
3625 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3626
3627 if (delayAutounloadBool) {
3628 delayAutounload = delayAutounloadBool->getValue();
3629 }
3630 if (startKextExcludeNum) {
3631 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3632 }
3633 if (startMatchingExcludeNum) {
3634 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3635 }
3636
3637 OSKextLog(/* kext */ NULL,
3638 kOSKextLogProgressLevel |
3639 kOSKextLogIPCFlag,
3640 "Received request from user space to load kext %s.",
3641 kextIdentifier->getCStringNoCopy());
3642
3643 /* Load the kext, with no deferral, since this is a load from outside
3644 * the kernel.
3645 * xxx - Would like a better way to handle the default values for the
3646 * xxx - start/match opt args.
3647 */
3648 result = OSKext::loadKextWithIdentifier(
3649 kextIdentifier,
3650 /* kextRef */ NULL,
3651 /* allowDefer */ false,
3652 delayAutounload,
3653 startKextExcludeLevel,
3654 startMatchingExcludeLevel,
3655 personalityNames);
3656 if (result != kOSReturnSuccess) {
3657 goto finish;
3658 }
3659 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3660 * for matching via a separate IOKit calldown.
3661 */
3662
3663 finish:
3664
3665 /* Gather up the collected log messages for user space. Any
3666 * error messages past this call will not make it up as log messages
3667 * but will be in the system log.
3668 */
3669 logInfoArray = OSKext::clearUserSpaceLogFilter();
3670
3671 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3672 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3673 logInfoOut, logInfoLengthOut);
3674 if (tempResult != kOSReturnSuccess) {
3675 result = tempResult;
3676 }
3677 }
3678
3679 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3680
3681 IORecursiveLockUnlock(sKextLock);
3682
3683 /* Note: mkextDataObject will have been retained by every kext w/an
3684 * executable in it. That should all have been flushed out at the
3685 * and of the load operation, but you never know....
3686 */
3687 if (mkextData && mkextData->getRetainCount() > 1) {
3688 OSKextLog(/* kext */ NULL,
3689 kOSKextLogErrorLevel |
3690 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3691 "Kext load request buffer from user space still retained by a kext; "
3692 "probable memory leak.");
3693 }
3694
3695 return result;
3696 }
3697
3698 #endif // CONFIG_KXLD
3699
3700 /*********************************************************************
3701 *********************************************************************/
3702 /* static */
3703 OSReturn
3704 OSKext::serializeLogInfo(
3705 OSArray * logInfoArray,
3706 char ** logInfoOut,
3707 uint32_t * logInfoLengthOut)
3708 {
3709 OSReturn result = kOSReturnError;
3710 char * buffer = NULL;
3711 kern_return_t kmem_result = KERN_FAILURE;
3712 OSSharedPtr<OSSerialize> serializer;
3713 char * logInfo = NULL; // returned by reference
3714 uint32_t logInfoLength = 0;
3715
3716 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3717 OSKextLog(/* kext */ NULL,
3718 kOSKextLogErrorLevel |
3719 kOSKextLogIPCFlag,
3720 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3721 /* Bad programmer. */
3722 result = kOSKextReturnInvalidArgument;
3723 goto finish;
3724 }
3725
3726 serializer = OSSerialize::withCapacity(0);
3727 if (!serializer) {
3728 OSKextLog(/* kext */ NULL,
3729 kOSKextLogErrorLevel |
3730 kOSKextLogIPCFlag,
3731 "Failed to create serializer on log info for request from user space.");
3732 /* Incidental error; we're going to (try to) allow the request
3733 * itself to succeed. */
3734 }
3735
3736 if (!logInfoArray->serialize(serializer.get())) {
3737 OSKextLog(/* kext */ NULL,
3738 kOSKextLogErrorLevel |
3739 kOSKextLogIPCFlag,
3740 "Failed to serialize log info for request from user space.");
3741 /* Incidental error; we're going to (try to) allow the request
3742 * itself to succeed. */
3743 } else {
3744 logInfo = serializer->text();
3745 logInfoLength = serializer->getLength();
3746
3747 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3748 if (kmem_result != KERN_SUCCESS) {
3749 OSKextLog(/* kext */ NULL,
3750 kOSKextLogErrorLevel |
3751 kOSKextLogIPCFlag,
3752 "Failed to copy log info for request from user space.");
3753 /* Incidental error; we're going to (try to) allow the request
3754 * to succeed. */
3755 } else {
3756 /* 11981737 - clear uninitialized data in last page */
3757 bzero((void *)(buffer + logInfoLength),
3758 (round_page(logInfoLength) - logInfoLength));
3759 memcpy(buffer, logInfo, logInfoLength);
3760 *logInfoOut = buffer;
3761 *logInfoLengthOut = logInfoLength;
3762 }
3763 }
3764
3765 result = kOSReturnSuccess;
3766 finish:
3767 return result;
3768 }
3769
3770 #if PRAGMA_MARK
3771 #pragma mark Instance Management Methods
3772 #endif
3773 /*********************************************************************
3774 *********************************************************************/
3775 OSSharedPtr<OSKext>
3776 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3777 {
3778 OSSharedPtr<OSKext> foundKext;
3779
3780 IORecursiveLockLock(sKextLock);
3781 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
3782 IORecursiveLockUnlock(sKextLock);
3783
3784 return foundKext;
3785 }
3786
3787 /*********************************************************************
3788 *********************************************************************/
3789 OSSharedPtr<OSKext>
3790 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3791 {
3792 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3793 }
3794
3795 /*********************************************************************
3796 *********************************************************************/
3797 OSSharedPtr<OSKext>
3798 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3799 {
3800 OSSharedPtr<OSKext> foundKext; // returned
3801 uint32_t i, j;
3802 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3803 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3804
3805 IORecursiveLockLock(sKextLock);
3806
3807 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3808 for (i = 0; i < count[j]; i++) {
3809 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3810 if (thisKext->getLoadTag() == aTag) {
3811 foundKext.reset(thisKext, OSRetain);
3812 goto finish;
3813 }
3814 }
3815 }
3816
3817 finish:
3818 IORecursiveLockUnlock(sKextLock);
3819
3820 return foundKext;
3821 }
3822
3823 /*********************************************************************
3824 *********************************************************************/
3825 OSSharedPtr<OSKext>
3826 OSKext::lookupKextWithAddress(vm_address_t address)
3827 {
3828 OSSharedPtr<OSKext> foundKext; // returned
3829 uint32_t count, i;
3830 kmod_info_t *kmod_info;
3831 #if defined(__arm64__)
3832 uint64_t textExecBase;
3833 size_t textExecSize;
3834 #endif /* defined(__arm64__) */
3835
3836 #if __has_feature(ptrauth_calls)
3837 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3838 #endif /* __has_feature(ptrauth_calls) */
3839
3840 IORecursiveLockLock(sKextLock);
3841
3842 count = sLoadedKexts->getCount();
3843 for (i = 0; i < count; i++) {
3844 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3845 if (thisKext == sKernelKext) {
3846 continue;
3847 }
3848 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3849 kmod_info = thisKext->kmod_info;
3850 vm_address_t kext_start = kmod_info->address;
3851 vm_address_t kext_end = kext_start + kmod_info->size;
3852 if ((kext_start <= address) && (address < kext_end)) {
3853 foundKext.reset(thisKext, OSRetain);
3854 goto finish;
3855 }
3856 #if defined(__arm64__)
3857 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3858 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3859 foundKext.reset(thisKext, OSRetain);
3860 goto finish;
3861 }
3862 #endif /* defined (__arm64__) */
3863 }
3864 }
3865 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3866 foundKext.reset(sKernelKext, OSRetain);
3867 goto finish;
3868 }
3869 /*
3870 * DriverKit userspace executables do not have a kernel linkedExecutable,
3871 * so we "fake" their address range with the LoadTag.
3872 *
3873 * This is supposed to be used for logging reasons only. When logd
3874 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3875 * remove it here before checking it against the LoadTag.
3876 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3877 */
3878
3879 address = address & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
3880 count = sLoadedDriverKitKexts->getCount();
3881 for (i = 0; i < count; i++) {
3882 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
3883 if (thisKext->getLoadTag() == address) {
3884 foundKext.reset(thisKext, OSRetain);
3885 }
3886 }
3887
3888 finish:
3889 IORecursiveLockUnlock(sKextLock);
3890
3891 return foundKext;
3892 }
3893
3894 OSSharedPtr<OSData>
3895 OSKext::copyKextUUIDForAddress(OSNumber *address)
3896 {
3897 OSSharedPtr<OSData> uuid;
3898 OSSharedPtr<OSKext> kext;
3899
3900 if (!address) {
3901 return NULL;
3902 }
3903
3904 uintptr_t addr = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3905 if (addr == 0) {
3906 return NULL;
3907 }
3908 #if __has_feature(ptrauth_calls)
3909 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
3910 #endif /* __has_feature(ptrauth_calls) */
3911
3912 #if CONFIG_MACF
3913 /* Is the calling process allowed to query kext info? */
3914 if (current_task() != kernel_task) {
3915 int macCheckResult = 0;
3916 kauth_cred_t cred = NULL;
3917
3918 cred = kauth_cred_get_with_ref();
3919 macCheckResult = mac_kext_check_query(cred);
3920 kauth_cred_unref(&cred);
3921
3922 if (macCheckResult != 0) {
3923 OSKextLog(/* kext */ NULL,
3924 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3925 "Failed to query kext UUID (MAC policy error 0x%x).",
3926 macCheckResult);
3927 return NULL;
3928 }
3929 }
3930 #endif
3931 kext = lookupKextWithAddress(addr);
3932 if (kext) {
3933 uuid = kext->copyTextUUID();
3934 }
3935 return uuid;
3936 }
3937
3938 /*********************************************************************
3939 *********************************************************************/
3940 OSSharedPtr<OSKext>
3941 OSKext::lookupKextWithUUID(uuid_t wanted)
3942 {
3943 OSSharedPtr<OSKext> foundKext; // returned
3944 uint32_t j, i;
3945 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3946 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3947
3948
3949 IORecursiveLockLock(sKextLock);
3950
3951 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3952 for (i = 0; i < count[j]; i++) {
3953 OSKext * thisKext = NULL;
3954
3955 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3956 if (!thisKext) {
3957 continue;
3958 }
3959
3960 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
3961 if (!uuid_data) {
3962 continue;
3963 }
3964
3965 uuid_t uuid;
3966 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
3967
3968 if (0 == uuid_compare(wanted, uuid)) {
3969 foundKext.reset(thisKext, OSRetain);
3970 goto finish;
3971 }
3972 }
3973 }
3974 finish:
3975 IORecursiveLockUnlock(sKextLock);
3976
3977 return foundKext;
3978 }
3979
3980
3981
3982
3983 /*********************************************************************
3984 *********************************************************************/
3985 /* static */
3986 bool
3987 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
3988 {
3989 bool result = false;
3990 OSKext * foundKext = NULL; // returned
3991
3992 IORecursiveLockLock(sKextLock);
3993
3994 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
3995 if (foundKext && foundKext->isLoaded()) {
3996 result = true;
3997 }
3998
3999 IORecursiveLockUnlock(sKextLock);
4000
4001 return result;
4002 }
4003
4004 /*********************************************************************
4005 * xxx - should spawn a separate thread so a kext can safely have
4006 * xxx - itself unloaded.
4007 *********************************************************************/
4008 /* static */
4009 OSReturn
4010 OSKext::removeKext(
4011 OSKext * aKext,
4012 #if CONFIG_EMBEDDED
4013 __unused
4014 #endif
4015 bool terminateServicesAndRemovePersonalitiesFlag)
4016 {
4017 #if CONFIG_EMBEDDED
4018 OSKextLog(aKext,
4019 kOSKextLogErrorLevel |
4020 kOSKextLogKextBookkeepingFlag,
4021 "removeKext() called for %s, not supported on embedded",
4022 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4023
4024 return kOSReturnSuccess;
4025 #else /* CONFIG_EMBEDDED */
4026
4027 OSReturn result = kOSKextReturnInUse;
4028 OSKext * checkKext = NULL; // do not release
4029 #if CONFIG_MACF
4030 int macCheckResult = 0;
4031 kauth_cred_t cred = NULL;
4032 #endif
4033
4034 IORecursiveLockLock(sKextLock);
4035
4036 /* If the kext has no identifier, it failed to init
4037 * so isn't in sKextsByID and it isn't loaded.
4038 */
4039 if (!aKext->getIdentifier()) {
4040 result = kOSReturnSuccess;
4041 goto finish;
4042 }
4043
4044 checkKext = OSDynamicCast(OSKext,
4045 sKextsByID->getObject(aKext->getIdentifier()));
4046 if (checkKext != aKext) {
4047 result = kOSKextReturnNotFound;
4048 goto finish;
4049 }
4050
4051 if (aKext->isLoaded()) {
4052 #if CONFIG_MACF
4053 if (current_task() != kernel_task) {
4054 cred = kauth_cred_get_with_ref();
4055 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4056 kauth_cred_unref(&cred);
4057 }
4058
4059 if (macCheckResult != 0) {
4060 result = kOSReturnError;
4061 OSKextLog(aKext,
4062 kOSKextLogErrorLevel |
4063 kOSKextLogKextBookkeepingFlag,
4064 "Failed to remove kext %s (MAC policy error 0x%x).",
4065 aKext->getIdentifierCString(), macCheckResult);
4066 goto finish;
4067 }
4068 #endif
4069
4070 /* make sure there are no resource requests in flight - 17187548 */
4071 if (aKext->countRequestCallbacks()) {
4072 goto finish;
4073 }
4074
4075 /* If we are terminating, send the request to the IOCatalogue
4076 * (which will actually call us right back but that's ok we have
4077 * a recursive lock don't you know) but do not ask the IOCatalogue
4078 * to call back with an unload, we'll do that right here.
4079 */
4080 if (terminateServicesAndRemovePersonalitiesFlag) {
4081 result = gIOCatalogue->terminateDriversForModule(
4082 aKext->getIdentifierCString(), /* unload */ false);
4083 if (result != kOSReturnSuccess) {
4084 OSKextLog(aKext,
4085 kOSKextLogErrorLevel |
4086 kOSKextLogKextBookkeepingFlag,
4087 "Can't remove kext %s; services failed to terminate - 0x%x.",
4088 aKext->getIdentifierCString(), result);
4089 goto finish;
4090 }
4091 }
4092
4093 result = aKext->unload();
4094 if (result != kOSReturnSuccess) {
4095 goto finish;
4096 }
4097 }
4098
4099 /* Remove personalities as requested. This is a bit redundant for a loaded
4100 * kext as IOCatalogue::terminateDriversForModule() removes driver
4101 * personalities, but it doesn't restart matching, which we always want
4102 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4103 * that happens.
4104 */
4105 if (terminateServicesAndRemovePersonalitiesFlag) {
4106 aKext->removePersonalitiesFromCatalog();
4107 }
4108
4109 if (aKext->isInFileset()) {
4110 OSKextLog(aKext,
4111 kOSKextLogProgressLevel |
4112 kOSKextLogKextBookkeepingFlag,
4113 "Fileset kext %s unloaded.",
4114 aKext->getIdentifierCString());
4115 } else {
4116 OSKextLog(aKext,
4117 kOSKextLogProgressLevel |
4118 kOSKextLogKextBookkeepingFlag,
4119 "Removing kext %s.",
4120 aKext->getIdentifierCString());
4121
4122 sKextsByID->removeObject(aKext->getIdentifier());
4123 }
4124 result = kOSReturnSuccess;
4125
4126 finish:
4127 IORecursiveLockUnlock(sKextLock);
4128 return result;
4129 #endif /* CONFIG_EMBEDDED */
4130 }
4131
4132 /*********************************************************************
4133 *********************************************************************/
4134 /* static */
4135 OSReturn
4136 OSKext::removeKextWithIdentifier(
4137 const char * kextIdentifier,
4138 bool terminateServicesAndRemovePersonalitiesFlag)
4139 {
4140 OSReturn result = kOSReturnError;
4141
4142 IORecursiveLockLock(sKextLock);
4143
4144 OSKext * aKext = OSDynamicCast(OSKext,
4145 sKextsByID->getObject(kextIdentifier));
4146 if (!aKext) {
4147 result = kOSKextReturnNotFound;
4148 OSKextLog(/* kext */ NULL,
4149 kOSKextLogErrorLevel |
4150 kOSKextLogKextBookkeepingFlag,
4151 "Can't remove kext %s - not found.",
4152 kextIdentifier);
4153 goto finish;
4154 }
4155
4156 result = OSKext::removeKext(aKext,
4157 terminateServicesAndRemovePersonalitiesFlag);
4158
4159 finish:
4160 IORecursiveLockUnlock(sKextLock);
4161
4162 return result;
4163 }
4164
4165 /*********************************************************************
4166 *********************************************************************/
4167 /* static */
4168 OSReturn
4169 OSKext::removeKextWithLoadTag(
4170 OSKextLoadTag loadTag,
4171 bool terminateServicesAndRemovePersonalitiesFlag)
4172 {
4173 OSReturn result = kOSReturnError;
4174 OSKext * foundKext = NULL;
4175 uint32_t i, j;
4176 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4177 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4178
4179
4180 IORecursiveLockLock(sKextLock);
4181
4182 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4183 for (i = 0; i < count[j]; i++) {
4184 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4185 if (thisKext->loadTag == loadTag) {
4186 foundKext = thisKext;
4187 break;
4188 }
4189 }
4190 }
4191
4192 if (!foundKext) {
4193 result = kOSKextReturnNotFound;
4194 OSKextLog(/* kext */ NULL,
4195 kOSKextLogErrorLevel |
4196 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4197 "Can't remove kext with load tag %d - not found.",
4198 loadTag);
4199 goto finish;
4200 }
4201
4202 result = OSKext::removeKext(foundKext,
4203 terminateServicesAndRemovePersonalitiesFlag);
4204
4205 finish:
4206 IORecursiveLockUnlock(sKextLock);
4207
4208 return result;
4209 }
4210
4211 /*********************************************************************
4212 *********************************************************************/
4213 OSSharedPtr<OSDictionary>
4214 OSKext::copyKexts(void)
4215 {
4216 OSSharedPtr<OSDictionary> result;
4217
4218 IORecursiveLockLock(sKextLock);
4219 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4220 IORecursiveLockUnlock(sKextLock);
4221
4222 return result;
4223 }
4224
4225 /*********************************************************************
4226 *********************************************************************/
4227 #define BOOTER_KEXT_PREFIX "Driver-"
4228
4229 typedef struct _DeviceTreeBuffer {
4230 uint32_t paddr;
4231 uint32_t length;
4232 } _DeviceTreeBuffer;
4233
4234 /*********************************************************************
4235 * Create a dictionary of excluded kexts from the given booter data.
4236 *********************************************************************/
4237 /* static */
4238 void
4239 OSKext::createExcludeListFromBooterData(
4240 OSDictionary * theDictionary,
4241 OSCollectionIterator * theIterator )
4242 {
4243 OSString * deviceTreeName = NULL; // do not release
4244 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4245 char * booterDataPtr = NULL; // do not release
4246 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4247 char * infoDictAddr = NULL; // do not release
4248 OSSharedPtr<OSObject> parsedXML;
4249 OSDictionary * theInfoDict = NULL; // do not release
4250
4251 theIterator->reset();
4252
4253 /* look for AppleKextExcludeList.kext */
4254 while ((deviceTreeName =
4255 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4256 const char * devTreeNameCString;
4257 OSData * deviceTreeEntry; // do not release
4258 OSString * myBundleID; // do not release
4259
4260 deviceTreeEntry =
4261 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4262 if (!deviceTreeEntry) {
4263 continue;
4264 }
4265
4266 /* Make sure it is a kext */
4267 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4268 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4269 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4270 OSKextLog(NULL,
4271 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4272 "\"%s\" not a kext",
4273 devTreeNameCString);
4274 continue;
4275 }
4276
4277 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4278 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4279 if (!deviceTreeBuffer) {
4280 continue;
4281 }
4282
4283 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4284 if (!booterDataPtr) {
4285 continue;
4286 }
4287
4288 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4289 if (!kextFileInfo->infoDictPhysAddr ||
4290 !kextFileInfo->infoDictLength) {
4291 continue;
4292 }
4293
4294 infoDictAddr = (char *)
4295 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4296 if (!infoDictAddr) {
4297 continue;
4298 }
4299
4300 parsedXML = OSUnserializeXML(infoDictAddr);
4301 if (!parsedXML) {
4302 continue;
4303 }
4304
4305 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4306 if (!theInfoDict) {
4307 continue;
4308 }
4309
4310 myBundleID =
4311 OSDynamicCast(OSString,
4312 theInfoDict->getObject(kCFBundleIdentifierKey));
4313 if (myBundleID &&
4314 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4315 boolean_t updated = updateExcludeList(theInfoDict);
4316 if (!updated) {
4317 /* 25322874 */
4318 panic("Missing OSKextExcludeList dictionary\n");
4319 }
4320 break;
4321 }
4322 } // while ( (deviceTreeName = ...) )
4323
4324 return;
4325 }
4326
4327 /*********************************************************************
4328 * Create a dictionary of excluded kexts from the given prelink
4329 * info (kernelcache).
4330 *********************************************************************/
4331 /* static */
4332 void
4333 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4334 {
4335 OSDictionary * myInfoDict = NULL; // do not release
4336 OSString * myBundleID; // do not release
4337 u_int i;
4338
4339 /* Find the Apple Kext Exclude List. */
4340 for (i = 0; i < theInfoArray->getCount(); i++) {
4341 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4342 if (!myInfoDict) {
4343 continue;
4344 }
4345 myBundleID =
4346 OSDynamicCast(OSString,
4347 myInfoDict->getObject(kCFBundleIdentifierKey));
4348 if (myBundleID &&
4349 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4350 boolean_t updated = updateExcludeList(myInfoDict);
4351 if (!updated) {
4352 /* 25322874 */
4353 panic("Missing OSKextExcludeList dictionary\n");
4354 }
4355 break;
4356 }
4357 } // for (i = 0; i < theInfoArray->getCount()...
4358
4359 return;
4360 }
4361
4362 /* static */
4363 boolean_t
4364 OSKext::updateExcludeList(OSDictionary *infoDict)
4365 {
4366 OSDictionary *myTempDict = NULL; // do not free
4367 OSString *myTempString = NULL; // do not free
4368 OSKextVersion newVersion = 0;
4369 boolean_t updated = false;
4370
4371 if (!infoDict) {
4372 return false;
4373 }
4374
4375 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4376 if (!myTempDict) {
4377 return false;
4378 }
4379
4380 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4381 if (!myTempString) {
4382 return false;
4383 }
4384
4385 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4386 if (newVersion == 0) {
4387 return false;
4388 }
4389
4390 IORecursiveLockLock(sKextLock);
4391
4392 if (newVersion > sExcludeListVersion) {
4393 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4394 sExcludeListVersion = newVersion;
4395 updated = true;
4396 }
4397
4398 IORecursiveLockUnlock(sKextLock);
4399 return updated;
4400 }
4401
4402 #if PRAGMA_MARK
4403 #pragma mark Accessors
4404 #endif
4405 /*********************************************************************
4406 *********************************************************************/
4407 const OSSymbol *
4408 OSKext::getIdentifier(void)
4409 {
4410 return bundleID.get();
4411 }
4412
4413 /*********************************************************************
4414 * A kext must have a bundle identifier to even survive initialization;
4415 * this is guaranteed to exist past then.
4416 *********************************************************************/
4417 const char *
4418 OSKext::getIdentifierCString(void)
4419 {
4420 return bundleID->getCStringNoCopy();
4421 }
4422
4423 /*********************************************************************
4424 *********************************************************************/
4425 OSKextVersion
4426 OSKext::getVersion(void)
4427 {
4428 return version;
4429 }
4430
4431 /*********************************************************************
4432 *********************************************************************/
4433 OSKextVersion
4434 OSKext::getCompatibleVersion(void)
4435 {
4436 return compatibleVersion;
4437 }
4438
4439 /*********************************************************************
4440 *********************************************************************/
4441 bool
4442 OSKext::isLibrary(void)
4443 {
4444 return getCompatibleVersion() > 0;
4445 }
4446
4447 /*********************************************************************
4448 *********************************************************************/
4449 bool
4450 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4451 {
4452 if ((compatibleVersion > -1 && version > -1) &&
4453 (compatibleVersion <= version && aVersion <= version)) {
4454 return true;
4455 }
4456 return false;
4457 }
4458
4459 /*********************************************************************
4460 *********************************************************************/
4461 bool
4462 OSKext::declaresExecutable(void)
4463 {
4464 if (isDriverKit()) {
4465 return false;
4466 }
4467 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4468 }
4469
4470 /*********************************************************************
4471 *********************************************************************/
4472 OSData *
4473 OSKext::getExecutable(void)
4474 {
4475 OSData * result = NULL;
4476 OSSharedPtr<OSData> extractedExecutable;
4477
4478 if (flags.builtin) {
4479 return sKernelKext->linkedExecutable.get();
4480 }
4481
4482 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4483 if (result) {
4484 return result;
4485 }
4486
4487 #if CONFIG_KXLD
4488 OSData * mkextExecutableRef = NULL; // do not release
4489 mkextExecutableRef = OSDynamicCast(OSData,
4490 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4491
4492 if (mkextExecutableRef) {
4493 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4494 mkextExecutableRef->getBytesNoCopy();
4495 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4496 if (mkextVersion == MKEXT_VERS_2) {
4497 mkext2_file_entry * fileinfo =
4498 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4499 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4500 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4501 extractedExecutable = extractMkext2FileData(
4502 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4503 compressedSize, fullSize);
4504 } else {
4505 OSKextLog(this, kOSKextLogErrorLevel |
4506 kOSKextLogArchiveFlag,
4507 "Kext %s - unknown mkext version 0x%x for executable.",
4508 getIdentifierCString(), mkextVersion);
4509 }
4510
4511 /* Regardless of success, remove the mkext executable,
4512 * and drop one reference on the mkext. (setExecutable() does not
4513 * replace, it removes, or panics if asked to replace.)
4514 */
4515 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4516 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4517
4518 if (extractedExecutable && extractedExecutable->getLength()) {
4519 if (!setExecutable(extractedExecutable.get())) {
4520 goto finish;
4521 }
4522 result = extractedExecutable.get();
4523 } else {
4524 goto finish;
4525 }
4526 }
4527
4528 finish:
4529 #endif // CONFIG_KXLD
4530 return result;
4531 }
4532
4533 /*********************************************************************
4534 *********************************************************************/
4535 bool
4536 OSKext::isInterface(void)
4537 {
4538 return flags.interface;
4539 }
4540
4541 /*********************************************************************
4542 *********************************************************************/
4543 bool
4544 OSKext::isKernel(void)
4545 {
4546 return this == sKernelKext;
4547 }
4548
4549 /*********************************************************************
4550 *********************************************************************/
4551 bool
4552 OSKext::isKernelComponent(void)
4553 {
4554 return flags.kernelComponent ? true : false;
4555 }
4556
4557 /*********************************************************************
4558 *********************************************************************/
4559 bool
4560 OSKext::isExecutable(void)
4561 {
4562 return !isKernel() && !isInterface() && declaresExecutable();
4563 }
4564
4565 /*********************************************************************
4566 * We might want to check this recursively for all dependencies,
4567 * since a subtree of dependencies could get loaded before we hit
4568 * a dependency that isn't safe-boot-loadable.
4569 *
4570 * xxx - Might want to return false if OSBundleEnableKextLogging or
4571 * OSBundleDebugLevel
4572 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4573 * the point except it's usually development drivers, which might
4574 * cause panics on startup, that have those properties). Heh; could
4575 * use a "kx" boot-arg!
4576 *********************************************************************/
4577 bool
4578 OSKext::isLoadableInSafeBoot(void)
4579 {
4580 bool result = false;
4581 OSString * required = NULL; // do not release
4582
4583 if (isKernel()) {
4584 result = true;
4585 goto finish;
4586 }
4587
4588 if (isDriverKit()) {
4589 result = true;
4590 goto finish;
4591 }
4592
4593 required = OSDynamicCast(OSString,
4594 getPropertyForHostArch(kOSBundleRequiredKey));
4595 if (!required) {
4596 goto finish;
4597 }
4598 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4599 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4600 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4601 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4602 required->isEqualTo(kOSBundleRequiredConsole)) {
4603 result = true;
4604 }
4605
4606 finish:
4607 return result;
4608 }
4609
4610 /*********************************************************************
4611 *********************************************************************/
4612 bool
4613 OSKext::isPrelinked(void)
4614 {
4615 return flags.prelinked ? true : false;
4616 }
4617
4618 /*********************************************************************
4619 *********************************************************************/
4620 bool
4621 OSKext::isLoaded(void)
4622 {
4623 return flags.loaded ? true : false;
4624 }
4625
4626 /*********************************************************************
4627 *********************************************************************/
4628 bool
4629 OSKext::isStarted(void)
4630 {
4631 return flags.started ? true : false;
4632 }
4633
4634 /*********************************************************************
4635 *********************************************************************/
4636 bool
4637 OSKext::isCPPInitialized(void)
4638 {
4639 return flags.CPPInitialized;
4640 }
4641
4642 /*********************************************************************
4643 *********************************************************************/
4644 void
4645 OSKext::setCPPInitialized(bool initialized)
4646 {
4647 flags.CPPInitialized = initialized;
4648 }
4649
4650 /*********************************************************************
4651 *********************************************************************/
4652 uint32_t
4653 OSKext::getLoadTag(void)
4654 {
4655 return loadTag;
4656 }
4657
4658 /*********************************************************************
4659 *********************************************************************/
4660 void
4661 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4662 {
4663 if (linkedExecutable) {
4664 *loadSize = linkedExecutable->getLength();
4665
4666 /* If we have a kmod_info struct, calculated the wired size
4667 * from that. Otherwise it's the full load size.
4668 */
4669 if (kmod_info) {
4670 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
4671 } else {
4672 *wiredSize = *loadSize;
4673 }
4674 } else {
4675 *wiredSize = 0;
4676 *loadSize = 0;
4677 }
4678 }
4679
4680 /*********************************************************************
4681 *********************************************************************/
4682 OSSharedPtr<OSData>
4683 OSKext::copyUUID(void)
4684 {
4685 OSSharedPtr<OSData> result;
4686 OSData * theExecutable = NULL; // do not release
4687 const kernel_mach_header_t * header;
4688
4689 /* An interface kext doesn't have a linked executable with an LC_UUID,
4690 * we create one when it's linked.
4691 */
4692 if (interfaceUUID) {
4693 result = interfaceUUID;
4694 goto finish;
4695 }
4696
4697 if (flags.builtin || isInterface()) {
4698 return sKernelKext->copyUUID();
4699 }
4700
4701 if (isDriverKit() && infoDict) {
4702 return driverKitUUID;
4703 }
4704
4705 /* For real kexts, try to get the UUID from the linked executable,
4706 * or if is hasn't been linked yet, the unrelocated executable.
4707 */
4708 theExecutable = linkedExecutable.get();
4709 if (!theExecutable) {
4710 theExecutable = getExecutable();
4711 }
4712
4713 if (!theExecutable) {
4714 goto finish;
4715 }
4716
4717 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4718 result = copyMachoUUID(header);
4719
4720 finish:
4721 return result;
4722 }
4723
4724 /*********************************************************************
4725 *********************************************************************/
4726 OSSharedPtr<OSData>
4727 OSKext::copyTextUUID(void)
4728 {
4729 if (flags.builtin) {
4730 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4731 }
4732 return copyUUID();
4733 }
4734
4735 /*********************************************************************
4736 *********************************************************************/
4737 OSSharedPtr<OSData>
4738 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4739 {
4740 OSSharedPtr<OSData> result;
4741 const struct load_command * load_cmd = NULL;
4742 const struct uuid_command * uuid_cmd = NULL;
4743 uint32_t i;
4744
4745 load_cmd = (const struct load_command *)&header[1];
4746
4747 if (header->magic != MH_MAGIC_KERNEL) {
4748 OSKextLog(NULL,
4749 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4750 "%s: bad header %p",
4751 __func__,
4752 header);
4753 goto finish;
4754 }
4755
4756 for (i = 0; i < header->ncmds; i++) {
4757 if (load_cmd->cmd == LC_UUID) {
4758 uuid_cmd = (struct uuid_command *)load_cmd;
4759 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4760 goto finish;
4761 }
4762 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4763 }
4764
4765 finish:
4766 return result;
4767 }
4768
4769 void
4770 OSKext::setDriverKitUUID(OSData *uuid)
4771 {
4772 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4773 OSSafeReleaseNULL(uuid);
4774 }
4775 }
4776
4777 /*********************************************************************
4778 *********************************************************************/
4779 #if defined (__arm__)
4780 #include <arm/arch.h>
4781 #endif
4782
4783 #if defined (__x86_64__)
4784 #define ARCHNAME "x86_64"
4785 #elif defined (__arm64__)
4786 #define ARCHNAME "arm64"
4787 #elif defined (__arm__)
4788
4789 #if defined (__ARM_ARCH_7S__)
4790 #define ARCHNAME "armv7s"
4791 #elif defined (__ARM_ARCH_7F__)
4792 #define ARCHNAME "armv7f"
4793 #elif defined (__ARM_ARCH_7K__)
4794 #define ARCHNAME "armv7k"
4795 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4796 #define ARCHNAME "armv7"
4797 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4798 #define ARCHNAME "armv6"
4799 #endif
4800
4801 #elif defined (__arm64__)
4802 #define ARCHNAME "arm64"
4803 #else
4804 #error architecture not supported
4805 #endif
4806
4807 #define ARCH_SEPARATOR_CHAR '_'
4808
4809 static char *
4810 makeHostArchKey(const char * key, size_t * keySizeOut)
4811 {
4812 char * result = NULL;
4813 size_t keyLength = strlen(key);
4814 size_t keySize;
4815
4816 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4817 */
4818 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4819 result = (char *)kheap_alloc_tag(KHEAP_TEMP, keySize,
4820 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4821
4822 if (!result) {
4823 goto finish;
4824 }
4825 strlcpy(result, key, keySize);
4826 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4827 result[keyLength] = '\0';
4828 strlcat(result, ARCHNAME, keySize);
4829 *keySizeOut = keySize;
4830
4831 finish:
4832 return result;
4833 }
4834
4835 /*********************************************************************
4836 *********************************************************************/
4837 OSObject *
4838 OSKext::getPropertyForHostArch(const char * key)
4839 {
4840 OSObject * result = NULL;// do not release
4841 size_t hostArchKeySize = 0;
4842 char * hostArchKey = NULL;// must kfree
4843
4844 if (!key || !infoDict) {
4845 goto finish;
4846 }
4847
4848 /* Some properties are not allowed to be arch-variant:
4849 * - Any CFBundle... property.
4850 * - OSBundleIsInterface.
4851 * - OSKernelResource.
4852 */
4853 if (STRING_HAS_PREFIX(key, "OS") ||
4854 STRING_HAS_PREFIX(key, "IO")) {
4855 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4856 if (!hostArchKey) {
4857 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4858 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4859 "Allocation failure.");
4860 goto finish;
4861 }
4862 result = infoDict->getObject(hostArchKey);
4863 }
4864
4865 if (!result) {
4866 result = infoDict->getObject(key);
4867 }
4868
4869 finish:
4870 if (hostArchKey) {
4871 kheap_free(KHEAP_TEMP, hostArchKey, hostArchKeySize);
4872 }
4873 return result;
4874 }
4875
4876 #if PRAGMA_MARK
4877 #pragma mark Load/Start/Stop/Unload
4878 #endif
4879
4880 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4881
4882 /*********************************************************************
4883 * sExcludeListByID is a dictionary with keys / values of:
4884 * key = bundleID string of kext we will not allow to load
4885 * value = version string(s) of the kext that is to be denied loading.
4886 * The version strings can be comma delimited. For example if kext
4887 * com.foocompany.fookext has two versions that we want to deny
4888 * loading then the version strings might look like:
4889 * 1.0.0, 1.0.1
4890 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4891 * not load the kext.
4892 *
4893 * Value may also be in the form of "LE 2.0.0" (version numbers
4894 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4895 * number less than 2.0.0 will not load)
4896 *
4897 * NOTE - we cannot use the characters "<=" or "<" because we have code
4898 * that serializes plists and treats '<' as a special character.
4899 *********************************************************************/
4900 bool
4901 OSKext::isInExcludeList(void)
4902 {
4903 OSString * versionString = NULL; // do not release
4904 char * versionCString = NULL; // do not free
4905 size_t i;
4906 boolean_t wantLessThan = false;
4907 boolean_t wantLessThanEqualTo = false;
4908 boolean_t isInExcludeList = true;
4909 char myBuffer[32];
4910
4911 IORecursiveLockLock(sKextLock);
4912
4913 if (!sExcludeListByID) {
4914 isInExcludeList = false;
4915 } else {
4916 /* look up by bundleID in our exclude list and if found get version
4917 * string (or strings) that we will not allow to load
4918 */
4919 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
4920 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
4921 isInExcludeList = false;
4922 }
4923 }
4924
4925 IORecursiveLockUnlock(sKextLock);
4926
4927 if (!isInExcludeList) {
4928 return false;
4929 }
4930
4931 /* parse version strings */
4932 versionCString = (char *) versionString->getCStringNoCopy();
4933
4934 /* look for "LT" or "LE" form of version string, must be in first two
4935 * positions.
4936 */
4937 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
4938 wantLessThan = true;
4939 versionCString += 2;
4940 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
4941 wantLessThanEqualTo = true;
4942 versionCString += 2;
4943 }
4944
4945 for (i = 0; *versionCString != 0x00; versionCString++) {
4946 /* skip whitespace */
4947 if (isWhiteSpace(*versionCString)) {
4948 continue;
4949 }
4950
4951 /* peek ahead for version string separator or null terminator */
4952 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
4953 /* OK, we have a version string */
4954 myBuffer[i++] = *versionCString;
4955 myBuffer[i] = 0x00;
4956
4957 OSKextVersion excludeVers;
4958 excludeVers = OSKextParseVersionString(myBuffer);
4959
4960 if (wantLessThanEqualTo) {
4961 if (version <= excludeVers) {
4962 return true;
4963 }
4964 } else if (wantLessThan) {
4965 if (version < excludeVers) {
4966 return true;
4967 }
4968 } else if (version == excludeVers) {
4969 return true;
4970 }
4971
4972 /* reset for the next (if any) version string */
4973 i = 0;
4974 wantLessThan = false;
4975 wantLessThanEqualTo = false;
4976 } else {
4977 /* save valid version character */
4978 myBuffer[i++] = *versionCString;
4979
4980 /* make sure bogus version string doesn't overrun local buffer */
4981 if (i >= sizeof(myBuffer)) {
4982 break;
4983 }
4984 }
4985 }
4986
4987 return false;
4988 }
4989
4990 /*********************************************************************
4991 * sNonLoadableKextsByID is a dictionary with keys / values of:
4992 * key = bundleID string of kext we will not allow to load
4993 * value = boolean (true == loadable, false == not loadable)
4994 *
4995 * Only kexts which are in the AuxKC will be marked as "not loadble,"
4996 * i.e., the value for the kext's bundleID will be false. All kexts in
4997 * the primary and system KCs will always be marked as "loadable."
4998 *
4999 * This list ultimately comes from kexts which have been uninstalled
5000 * in user space by deleting the kext from disk, but which have not
5001 * yet been removed from the AuxKC. Because the user could choose to
5002 * re-install the exact same version of the kext, we need to keep
5003 * a dictionary of boolean values so that user space only needs to
5004 * keep a simple list of "uninstalled" or "missing" bundles. When
5005 * a bundle is re-installed, the iokit daemon can use the
5006 * AucKCBundleAvailable predicate to set the individual kext's
5007 * availability to true.
5008 *********************************************************************/
5009 bool
5010 OSKext::isLoadable(void)
5011 {
5012 bool isLoadable = true;
5013
5014 if (kc_type != KCKindAuxiliary) {
5015 /* this filtering only applies to kexts in the auxkc */
5016 return true;
5017 }
5018
5019 IORecursiveLockLock(sKextLock);
5020
5021 if (sNonLoadableKextsByID) {
5022 /* look up by bundleID in our exclude list and if found get version
5023 * string (or strings) that we will not allow to load
5024 */
5025 OSBoolean *loadableVal;
5026 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5027 if (loadableVal && !loadableVal->getValue()) {
5028 isLoadable = false;
5029 }
5030 }
5031 IORecursiveLockUnlock(sKextLock);
5032
5033 return isLoadable;
5034 }
5035
5036 /*********************************************************************
5037 *********************************************************************/
5038 /* static */
5039 OSReturn
5040 OSKext::loadKextWithIdentifier(
5041 const char * kextIdentifierCString,
5042 Boolean allowDeferFlag,
5043 Boolean delayAutounloadFlag,
5044 OSKextExcludeLevel startOpt,
5045 OSKextExcludeLevel startMatchingOpt,
5046 OSArray * personalityNames)
5047 {
5048 OSReturn result = kOSReturnError;
5049 OSSharedPtr<OSString> kextIdentifier;
5050
5051 kextIdentifier = OSString::withCString(kextIdentifierCString);
5052 if (!kextIdentifier) {
5053 result = kOSKextReturnNoMemory;
5054 goto finish;
5055 }
5056 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5057 NULL /* kextRef */,
5058 allowDeferFlag, delayAutounloadFlag,
5059 startOpt, startMatchingOpt, personalityNames);
5060
5061 finish:
5062 return result;
5063 }
5064
5065 OSReturn
5066 OSKext::loadKextWithIdentifier(
5067 OSString * kextIdentifier,
5068 OSSharedPtr<OSObject> &kextRef,
5069 Boolean allowDeferFlag,
5070 Boolean delayAutounloadFlag,
5071 OSKextExcludeLevel startOpt,
5072 OSKextExcludeLevel startMatchingOpt,
5073 OSArray * personalityNames)
5074 {
5075 OSObject * kextRefRaw = NULL;
5076 OSReturn result;
5077
5078 result = loadKextWithIdentifier(kextIdentifier,
5079 &kextRefRaw,
5080 allowDeferFlag,
5081 delayAutounloadFlag,
5082 startOpt,
5083 startMatchingOpt,
5084 personalityNames);
5085 if ((kOSReturnSuccess == result) && kextRefRaw) {
5086 kextRef.reset(kextRefRaw, OSNoRetain);
5087 }
5088 return result;
5089 }
5090
5091 /*********************************************************************
5092 *********************************************************************/
5093 OSReturn
5094 OSKext::loadKextWithIdentifier(
5095 OSString * kextIdentifier,
5096 OSObject ** kextRef,
5097 Boolean allowDeferFlag,
5098 Boolean delayAutounloadFlag,
5099 OSKextExcludeLevel startOpt,
5100 OSKextExcludeLevel startMatchingOpt,
5101 OSArray * personalityNames)
5102 {
5103 OSReturn result = kOSReturnError;
5104 OSReturn pingResult = kOSReturnError;
5105 OSKext * theKext = NULL; // do not release
5106 OSSharedPtr<OSDictionary> loadRequest;
5107 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5108
5109 if (kextRef) {
5110 *kextRef = NULL;
5111 }
5112
5113 IORecursiveLockLock(sKextLock);
5114
5115 if (!kextIdentifier) {
5116 result = kOSKextReturnInvalidArgument;
5117 goto finish;
5118 }
5119
5120 OSKext::recordIdentifierRequest(kextIdentifier);
5121
5122 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5123 if (!theKext) {
5124 if (!allowDeferFlag) {
5125 OSKextLog(/* kext */ NULL,
5126 kOSKextLogErrorLevel |
5127 kOSKextLogLoadFlag,
5128 "Can't load kext %s - not found.",
5129 kextIdentifier->getCStringNoCopy());
5130 goto finish;
5131 }
5132
5133 if (!sKernelRequestsEnabled) {
5134 OSKextLog(theKext,
5135 kOSKextLogErrorLevel |
5136 kOSKextLogLoadFlag,
5137 "Can't load kext %s - requests to user space are disabled.",
5138 kextIdentifier->getCStringNoCopy());
5139 result = kOSKextReturnDisabled;
5140 goto finish;
5141 }
5142
5143 /* Create a new request unless one is already sitting
5144 * in sKernelRequests for this bundle identifier
5145 */
5146 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5147 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5148 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5149 loadRequest);
5150 if (result != kOSReturnSuccess) {
5151 goto finish;
5152 }
5153 if (!_OSKextSetRequestArgument(loadRequest.get(),
5154 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5155 result = kOSKextReturnNoMemory;
5156 goto finish;
5157 }
5158 if (!sKernelRequests->setObject(loadRequest.get())) {
5159 result = kOSKextReturnNoMemory;
5160 goto finish;
5161 }
5162
5163 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5164 result = kOSKextReturnNoMemory;
5165 goto finish;
5166 }
5167
5168 OSKextLog(theKext,
5169 kOSKextLogDebugLevel |
5170 kOSKextLogLoadFlag,
5171 "Kext %s not found; queued load request to user space.",
5172 kextIdentifier->getCStringNoCopy());
5173 }
5174
5175 pingResult = OSKext::pingIOKitDaemon();
5176 if (pingResult == kOSKextReturnDisabled) {
5177 OSKextLog(/* kext */ NULL,
5178 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5179 kOSKextLogLoadFlag,
5180 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5181 kextIdentifier->getCStringNoCopy());
5182 }
5183
5184 result = kOSKextReturnDeferred;
5185 goto finish;
5186 }
5187
5188 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5189
5190 if (result != kOSReturnSuccess) {
5191 OSKextLog(theKext,
5192 kOSKextLogErrorLevel |
5193 kOSKextLogLoadFlag,
5194 "Failed to load kext %s (error 0x%x).",
5195 kextIdentifier->getCStringNoCopy(), (int)result);
5196
5197 if (theKext->kc_type == KCKindUnknown) {
5198 OSKext::removeKext(theKext,
5199 /* terminateService/removePersonalities */ true);
5200 }
5201 goto finish;
5202 }
5203
5204 if (delayAutounloadFlag) {
5205 OSKextLog(theKext,
5206 kOSKextLogProgressLevel |
5207 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5208 "Setting delayed autounload for %s.",
5209 kextIdentifier->getCStringNoCopy());
5210 theKext->flags.delayAutounload = 1;
5211 }
5212
5213 finish:
5214 if ((kOSReturnSuccess == result) && kextRef) {
5215 *kextRef = theKext;
5216 theKext->matchingRefCount++;
5217 theKext->retain();
5218 }
5219
5220 IORecursiveLockUnlock(sKextLock);
5221
5222 return result;
5223 }
5224
5225 /*********************************************************************
5226 *********************************************************************/
5227 /* static */
5228 OSReturn
5229 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5230 {
5231 OSReturn result = kOSReturnError;
5232
5233 OSBoolean *delayAutounloadBool = NULL; // do not release
5234 OSNumber *startKextExcludeNum = NULL; // do not release
5235 OSNumber *startMatchingExcludeNum = NULL; // do not release
5236 OSArray *personalityNames = NULL; // do not release
5237
5238 /*
5239 * Default values for these options:
5240 * regular autounload behavior
5241 * start the kext
5242 * send all personalities to the catalog
5243 */
5244 Boolean delayAutounload = false;
5245 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5246 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5247
5248 IORecursiveLockLock(sKextLock);
5249
5250 OSKextLog(/* kext */ NULL,
5251 kOSKextLogDebugLevel |
5252 kOSKextLogIPCFlag,
5253 "Received kext KC load request from user space.");
5254
5255 /* Regardless of processing, the fact that we have gotten here means some
5256 * user-space program is up and talking to us, so we'll switch our kext
5257 * registration to reflect that.
5258 */
5259 if (!sUserLoadsActive) {
5260 OSKextLog(/* kext */ NULL,
5261 kOSKextLogProgressLevel |
5262 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5263 "Switching to late startup (user-space) kext loading policy.");
5264 sUserLoadsActive = true;
5265 }
5266
5267 delayAutounloadBool = OSDynamicCast(OSBoolean,
5268 _OSKextGetRequestArgument(requestDict,
5269 kKextRequestArgumentDelayAutounloadKey));
5270 startKextExcludeNum = OSDynamicCast(OSNumber,
5271 _OSKextGetRequestArgument(requestDict,
5272 kKextRequestArgumentStartExcludeKey));
5273 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5274 _OSKextGetRequestArgument(requestDict,
5275 kKextRequestArgumentStartMatchingExcludeKey));
5276 personalityNames = OSDynamicCast(OSArray,
5277 _OSKextGetRequestArgument(requestDict,
5278 kKextRequestArgumentPersonalityNamesKey));
5279
5280 if (delayAutounloadBool) {
5281 delayAutounload = delayAutounloadBool->getValue();
5282 }
5283 if (startKextExcludeNum) {
5284 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5285 }
5286 if (startMatchingExcludeNum) {
5287 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5288 }
5289
5290 OSKextLog(/* kext */ NULL,
5291 kOSKextLogProgressLevel |
5292 kOSKextLogIPCFlag,
5293 "Received request from user space to load KC kext %s.",
5294 theKext->getIdentifierCString());
5295
5296 /* this could be in the Auxiliary KC, so record the load request */
5297 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5298
5299 /*
5300 * Load the kext
5301 */
5302 result = theKext->load(startKextExcludeLevel,
5303 startMatchingExcludeLevel, personalityNames);
5304
5305 if (result != kOSReturnSuccess) {
5306 OSKextLog(theKext,
5307 kOSKextLogErrorLevel |
5308 kOSKextLogLoadFlag,
5309 "Failed to load kext %s (error 0x%x).",
5310 theKext->getIdentifierCString(), (int)result);
5311
5312 OSKext::removeKext(theKext,
5313 /* terminateService/removePersonalities */ true);
5314 goto finish;
5315 } else {
5316 OSKextLog(theKext,
5317 kOSKextLogProgressLevel |
5318 kOSKextLogLoadFlag,
5319 "Kext %s Loaded successfully from %s KC",
5320 theKext->getIdentifierCString(), theKext->getKCTypeString());
5321 }
5322
5323 if (delayAutounload) {
5324 OSKextLog(theKext,
5325 kOSKextLogProgressLevel |
5326 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5327 "Setting delayed autounload for %s.",
5328 theKext->getIdentifierCString());
5329 theKext->flags.delayAutounload = 1;
5330 }
5331
5332 finish:
5333 IORecursiveLockUnlock(sKextLock);
5334
5335 return result;
5336 }
5337
5338 /*********************************************************************
5339 *********************************************************************/
5340 /* static */
5341 OSReturn
5342 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5343 {
5344 OSReturn result = kOSReturnError;
5345 OSDictionary *anInfoDict = NULL; // do not release
5346
5347 anInfoDict = OSDynamicCast(OSDictionary,
5348 _OSKextGetRequestArgument(requestDict,
5349 kKextRequestArgumentCodelessInfoKey));
5350 if (anInfoDict == NULL) {
5351 OSKextLog(/* kext */ NULL,
5352 kOSKextLogErrorLevel |
5353 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5354 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5355 kextIdentifier->getCStringNoCopy());
5356 return kOSKextReturnInvalidArgument;
5357 }
5358
5359 IORecursiveLockLock(sKextLock);
5360
5361 OSKextLog(/* kext */ NULL,
5362 kOSKextLogProgressLevel |
5363 kOSKextLogIPCFlag,
5364 "Received request from user space to load codeless kext %s.",
5365 kextIdentifier->getCStringNoCopy());
5366
5367 {
5368 // instantiate a new kext, and don't hold a reference
5369 // (the kext subsystem will hold one implicitly)
5370 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5371 if (!newKext) {
5372 OSKextLog(/* kext */ NULL,
5373 kOSKextLogErrorLevel |
5374 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5375 "Could not instantiate codeless kext.");
5376 result = kOSKextReturnNotLoadable;
5377 goto finish;
5378 }
5379 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5380 OSKextLog(/* kext */ NULL,
5381 kOSKextLogErrorLevel |
5382 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5383 "Codeless kext identifiers don't match '%s' != '%s'",
5384 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5385
5386 OSKext::removeKext(newKext.get(), false);
5387 result = kOSKextReturnInvalidArgument;
5388 goto finish;
5389 }
5390
5391 /* Record the request for the codeless kext */
5392 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5393
5394 result = kOSReturnSuccess;
5395 /* send the kext's personalities to the IOCatalog */
5396 if (!newKext->flags.requireExplicitLoad) {
5397 result = newKext->sendPersonalitiesToCatalog(true, NULL);
5398 }
5399 }
5400
5401 finish:
5402 IORecursiveLockUnlock(sKextLock);
5403
5404 return result;
5405 }
5406
5407 /*********************************************************************
5408 *********************************************************************/
5409 /* static */
5410 void
5411 OSKext::dropMatchingReferences(
5412 OSSet * kexts)
5413 {
5414 IORecursiveLockLock(sKextLock);
5415 kexts->iterateObjects(^bool (OSObject * obj) {
5416 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5417 if (!thisKext) {
5418 return false;
5419 }
5420 thisKext->matchingRefCount--;
5421 return false;
5422 });
5423 IORecursiveLockUnlock(sKextLock);
5424 }
5425
5426 /*********************************************************************
5427 *********************************************************************/
5428 /* static */
5429 void
5430 OSKext::recordIdentifierRequest(
5431 OSString * kextIdentifier)
5432 {
5433 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5434 bool fail = false;
5435
5436 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5437 goto finish;
5438 }
5439
5440 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5441 if (!kextIdentifierSymbol) {
5442 // xxx - this is really a basic alloc failure
5443 fail = true;
5444 goto finish;
5445 }
5446
5447 IORecursiveLockLock(sKextLock);
5448 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5449 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5450 fail = true;
5451 } else {
5452 // xxx - need to find a way to associate this whole func w/the kext
5453 OSKextLog(/* kext */ NULL,
5454 // xxx - check level
5455 kOSKextLogStepLevel |
5456 kOSKextLogArchiveFlag,
5457 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5458 kextIdentifier->getCStringNoCopy());
5459 }
5460 }
5461 IORecursiveLockUnlock(sKextLock);
5462
5463 finish:
5464
5465 if (fail) {
5466 OSKextLog(/* kext */ NULL,
5467 kOSKextLogErrorLevel |
5468 kOSKextLogArchiveFlag,
5469 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5470 kextIdentifier->getCStringNoCopy());
5471 }
5472 return;
5473 }
5474
5475 /*********************************************************************
5476 *********************************************************************/
5477 OSReturn
5478 OSKext::load(
5479 OSKextExcludeLevel startOpt,
5480 OSKextExcludeLevel startMatchingOpt,
5481 OSArray * personalityNames)
5482 {
5483 OSReturn result = kOSReturnError;
5484 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5485 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5486 unsigned int i, count;
5487 Boolean alreadyLoaded = false;
5488 OSKext * lastLoadedKext = NULL; // do not release
5489
5490 if (isInExcludeList()) {
5491 OSKextLog(this,
5492 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5493 kOSKextLogLoadFlag,
5494 "Kext %s is in exclude list, not loadable",
5495 getIdentifierCString());
5496
5497 result = kOSKextReturnNotLoadable;
5498 goto finish;
5499 }
5500 if (!isLoadable()) {
5501 OSKextLog(this,
5502 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5503 kOSKextLogLoadFlag,
5504 "Kext %s is not loadable",
5505 getIdentifierCString());
5506
5507 result = kOSKextReturnNotLoadable;
5508 goto finish;
5509 }
5510
5511 if (isLoaded()) {
5512 alreadyLoaded = true;
5513 result = kOSReturnSuccess;
5514
5515 OSKextLog(this,
5516 kOSKextLogDebugLevel |
5517 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5518 "Kext %s is already loaded.",
5519 getIdentifierCString());
5520 goto loaded;
5521 }
5522
5523 #if CONFIG_MACF && XNU_TARGET_OS_OSX
5524 #if CONFIG_KXLD
5525 if (current_task() != kernel_task) {
5526 #else
5527 /*
5528 * On non-kxld systems, only check the mac-hook for kexts in the
5529 * Pageable and Aux KCs. This means on Apple silicon devices that
5530 * the mac hook will only be useful to block 3rd party kexts.
5531 *
5532 * Note that this should _not_ be called on kexts loaded from the
5533 * kernel bootstrap thread as the kernel proc's cred struct is not
5534 * yet initialized! This won't happen on macOS because all the kexts
5535 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5536 */
5537 if (kc_type != KCKindPrimary && kc_type != KCKindUnknown) {
5538 #endif /* CONFIG_KXLD */
5539 int macCheckResult = 0;
5540 kauth_cred_t cred = NULL;
5541
5542 cred = kauth_cred_get_with_ref();
5543 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5544 kauth_cred_unref(&cred);
5545
5546 if (macCheckResult != 0) {
5547 result = kOSReturnError;
5548 OSKextLog(this,
5549 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5550 "Failed to load kext %s (MAC policy error 0x%x).",
5551 getIdentifierCString(), macCheckResult);
5552 goto finish;
5553 }
5554 }
5555 #endif
5556
5557 if (!sLoadEnabled) {
5558 OSKextLog(this,
5559 kOSKextLogErrorLevel |
5560 kOSKextLogLoadFlag,
5561 "Kext loading is disabled (attempt to load kext %s).",
5562 getIdentifierCString());
5563 result = kOSKextReturnDisabled;
5564 goto finish;
5565 }
5566
5567 /* If we've pushed the next available load tag to the invalid value,
5568 * we can't load any more kexts.
5569 */
5570 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5571 OSKextLog(this,
5572 kOSKextLogErrorLevel |
5573 kOSKextLogLoadFlag,
5574 "Can't load kext %s - no more load tags to assign.",
5575 getIdentifierCString());
5576 result = kOSKextReturnNoResources;
5577 goto finish;
5578 }
5579
5580 /* This is a bit of a hack, because we shouldn't be handling
5581 * personalities within the load function.
5582 */
5583 if (!declaresExecutable()) {
5584 /* There is a special case where a non-executable kext can be loaded: the
5585 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5586 * load its metadata into the global data structures, if appropriate
5587 */
5588 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5589 boolean_t updated = updateExcludeList(infoDict.get());
5590 if (updated) {
5591 OSKextLog(this,
5592 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5593 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5594 }
5595 }
5596
5597 if (isDriverKit()) {
5598 if (loadTag == 0) {
5599 sLoadedDriverKitKexts->setObject(this);
5600 loadTag = sNextLoadTag++;
5601 }
5602 }
5603 result = kOSReturnSuccess;
5604 goto loaded;
5605 }
5606
5607 /* Are we in safe boot?
5608 */
5609 if (sSafeBoot && !isLoadableInSafeBoot()) {
5610 OSKextLog(this,
5611 kOSKextLogErrorLevel |
5612 kOSKextLogLoadFlag,
5613 "Can't load kext %s - not loadable during safe boot.",
5614 getIdentifierCString());
5615 result = kOSKextReturnBootLevel;
5616 goto finish;
5617 }
5618
5619 OSKextLog(this,
5620 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5621 "Loading kext %s.",
5622 getIdentifierCString());
5623
5624 #if !VM_MAPPED_KEXTS
5625 if (isPrelinked() == false) {
5626 OSKextLog(this,
5627 kOSKextLogErrorLevel |
5628 kOSKextLogLoadFlag,
5629 "Can't load kext %s - not in a kext collection.",
5630 getIdentifierCString());
5631 result = kOSKextReturnDisabled;
5632 goto finish;
5633 }
5634 #endif /* defined(__x86_64__) */
5635
5636 #if CONFIG_KXLD
5637 if (!sKxldContext) {
5638 kern_return_t kxldResult;
5639 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5640 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5641 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5642 if (kxldResult) {
5643 OSKextLog(this,
5644 kOSKextLogErrorLevel |
5645 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5646 "Can't load kext %s - failed to create link context.",
5647 getIdentifierCString());
5648 result = kOSKextReturnNoMemory;
5649 goto finish;
5650 }
5651 }
5652 #endif // CONFIG_KXLD
5653
5654 /* We only need to resolve dependencies once for the whole graph, but
5655 * resolveDependencies will just return if there's no work to do, so it's
5656 * safe to call it more than once.
5657 */
5658 if (!resolveDependencies()) {
5659 // xxx - check resolveDependencies() for log msg
5660 OSKextLog(this,
5661 kOSKextLogErrorLevel |
5662 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5663 "Can't load kext %s - failed to resolve library dependencies.",
5664 getIdentifierCString());
5665 result = kOSKextReturnDependencies;
5666 goto finish;
5667 }
5668
5669 /* If we are excluding just the kext being loaded now (and not its
5670 * dependencies), drop the exclusion level to none so dependencies
5671 * start and/or add their personalities.
5672 */
5673 if (dependenciesStartOpt == kOSKextExcludeKext) {
5674 dependenciesStartOpt = kOSKextExcludeNone;
5675 }
5676
5677 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5678 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5679 }
5680
5681 /* Load the dependencies, recursively.
5682 */
5683 count = getNumDependencies();
5684 for (i = 0; i < count; i++) {
5685 OSKext * dependency = OSDynamicCast(OSKext,
5686 dependencies->getObject(i));
5687 if (dependency == NULL) {
5688 OSKextLog(this,
5689 kOSKextLogErrorLevel |
5690 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5691 "Internal error loading kext %s; dependency disappeared.",
5692 getIdentifierCString());
5693 result = kOSKextReturnInternalError;
5694 goto finish;
5695 }
5696
5697 /* Dependencies must be started accorting to the opt,
5698 * but not given the personality names of the main kext.
5699 */
5700 result = dependency->load(dependenciesStartOpt,
5701 dependenciesStartMatchingOpt,
5702 /* personalityNames */ NULL);
5703 if (result != KERN_SUCCESS) {
5704 OSKextLog(this,
5705 kOSKextLogErrorLevel |
5706 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5707 "Dependency %s of kext %s failed to load.",
5708 dependency->getIdentifierCString(),
5709 getIdentifierCString());
5710
5711 OSKext::removeKext(dependency,
5712 /* terminateService/removePersonalities */ true);
5713 result = kOSKextReturnDependencyLoadError;
5714
5715 goto finish;
5716 }
5717 }
5718
5719 result = loadExecutable();
5720 if (result != KERN_SUCCESS) {
5721 goto finish;
5722 }
5723
5724 pendingPgoHead.next = &pendingPgoHead;
5725 pendingPgoHead.prev = &pendingPgoHead;
5726
5727 // The kernel PRNG is not initialized when the first kext is
5728 // loaded, so use early random
5729 uuid_generate_early_random(instance_uuid);
5730 account = IONew(OSKextAccount, 1);
5731 if (!account) {
5732 result = KERN_MEMORY_ERROR;
5733 goto finish;
5734 }
5735 bzero(account, sizeof(*account));
5736 account->loadTag = kmod_info->id;
5737 account->site.refcount = 0;
5738 account->site.flags = VM_TAG_KMOD;
5739 account->kext = this;
5740 if (gIOSurfaceIdentifier == bundleID) {
5741 vm_tag_alloc(&account->site);
5742 gIOSurfaceTag = account->site.tag;
5743 }
5744
5745 flags.loaded = true;
5746
5747 /* Add the kext to the list of loaded kexts and update the kmod_info
5748 * struct to point to that of the last loaded kext (which is the way
5749 * it's always been done, though I'd rather do them in order now).
5750 */
5751 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5752 sLoadedKexts->setObject(this);
5753
5754 /* Keep the kernel itself out of the kmod list.
5755 */
5756 if (lastLoadedKext->isKernel()) {
5757 lastLoadedKext = NULL;
5758 }
5759
5760 if (lastLoadedKext) {
5761 kmod_info->next = lastLoadedKext->kmod_info;
5762 }
5763
5764 notifyKextLoadObservers(this, kmod_info);
5765
5766 /* Make the global kmod list point at the just-loaded kext. Note that the
5767 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5768 * although we do report it in kextstat these days by using the newer
5769 * OSArray of loaded kexts, which does contain it.
5770 *
5771 * (The OSKext object representing the kernel doesn't even have a kmod_info
5772 * struct, though I suppose we could stick a pointer to it from the
5773 * static struct in OSRuntime.cpp.)
5774 */
5775 kmod = kmod_info;
5776
5777 /* Save the list of loaded kexts in case we panic.
5778 */
5779 OSKext::saveLoadedKextPanicList();
5780
5781 if (isExecutable()) {
5782 OSKext::updateLoadedKextSummaries();
5783 savePanicString(/* isLoading */ true);
5784
5785 #if CONFIG_DTRACE
5786 registerWithDTrace();
5787 #else
5788 jettisonLinkeditSegment();
5789 #endif /* CONFIG_DTRACE */
5790
5791 #if !VM_MAPPED_KEXTS
5792 /* If there is a page (or more) worth of padding after the end
5793 * of the last data section but before the end of the data segment
5794 * then free it in the same manner the LinkeditSegment is freed
5795 */
5796 jettisonDATASegmentPadding();
5797 #endif
5798 }
5799
5800 loaded:
5801 if (isExecutable() && !flags.started) {
5802 if (startOpt == kOSKextExcludeNone) {
5803 result = start();
5804 if (result != kOSReturnSuccess) {
5805 OSKextLog(this,
5806 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5807 "Kext %s start failed (result 0x%x).",
5808 getIdentifierCString(), result);
5809 result = kOSKextReturnStartStopError;
5810 }
5811 }
5812 }
5813
5814 /* If not excluding matching, send the personalities to the kernel.
5815 * This never affects the result of the load operation.
5816 * This is a bit of a hack, because we shouldn't be handling
5817 * personalities within the load function.
5818 */
5819 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5820 result = sendPersonalitiesToCatalog(true, personalityNames);
5821 }
5822
5823 finish:
5824
5825 if (result != kOSReturnSuccess) {
5826 OSKextLog(this,
5827 kOSKextLogErrorLevel |
5828 kOSKextLogLoadFlag,
5829 "Kext %s failed to load (0x%x).",
5830 getIdentifierCString(), (int)result);
5831 } else if (!alreadyLoaded) {
5832 OSKextLog(this,
5833 kOSKextLogProgressLevel |
5834 kOSKextLogLoadFlag,
5835 "Kext %s loaded.",
5836 getIdentifierCString());
5837
5838 queueKextNotification(kKextRequestPredicateLoadNotification,
5839 OSDynamicCast(OSString, bundleID.get()));
5840 }
5841 return result;
5842 }
5843
5844 #if CONFIG_KXLD
5845 /*********************************************************************
5846 *
5847 *********************************************************************/
5848 static char *
5849 strdup(const char * string)
5850 {
5851 char * result = NULL;
5852 size_t size;
5853
5854 if (!string) {
5855 goto finish;
5856 }
5857
5858 size = 1 + strlen(string);
5859 result = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, size,
5860 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5861 if (!result) {
5862 goto finish;
5863 }
5864
5865 memcpy(result, string, size);
5866
5867 finish:
5868 return result;
5869 }
5870 #endif // CONFIG_KXLD
5871
5872 /*********************************************************************
5873 *
5874 *********************************************************************/
5875
5876 kernel_section_t *
5877 OSKext::lookupSection(const char *segname, const char *secname)
5878 {
5879 kernel_section_t * found_section = NULL;
5880 kernel_mach_header_t * mh = NULL;
5881 kernel_segment_command_t * seg = NULL;
5882 kernel_section_t * sec = NULL;
5883
5884 if (!linkedExecutable) {
5885 return NULL;
5886 }
5887
5888 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5889
5890 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5891 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
5892 continue;
5893 }
5894
5895 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5896 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
5897 found_section = sec;
5898 goto out;
5899 }
5900 }
5901 }
5902
5903 out:
5904 return found_section;
5905 }
5906
5907 /*********************************************************************
5908 *
5909 *********************************************************************/
5910
5911 OSReturn
5912 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
5913 {
5914 OSReturn result = kOSKextReturnBadData;
5915 kernel_mach_header_t * mh = NULL;
5916 kernel_segment_command_t * seg = NULL;
5917 kernel_segment_command_t * linkeditSeg = NULL;
5918 kernel_section_t * sec = NULL;
5919 char * linkeditBase = NULL;
5920 bool haveLinkeditBase = false;
5921 char * relocBase = NULL;
5922 bool haveRelocBase = false;
5923 struct dysymtab_command * dysymtab = NULL;
5924 struct linkedit_data_command * segmentSplitInfo = NULL;
5925 struct symtab_command * symtab = NULL;
5926 kernel_nlist_t * sym = NULL;
5927 struct relocation_info * reloc = NULL;
5928 uint32_t i = 0;
5929 int reloc_size;
5930 vm_offset_t new_kextsize;
5931
5932 if (linkedExecutable == NULL || flags.builtin) {
5933 result = kOSReturnSuccess;
5934 goto finish;
5935 }
5936
5937 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5938 if (kernel_mach_header_is_in_fileset(mh)) {
5939 // kexts in filesets are slid as part of collection sliding
5940 result = kOSReturnSuccess;
5941 goto finish;
5942 }
5943
5944 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
5945
5946 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5947 if (!seg->vmaddr) {
5948 continue;
5949 }
5950
5951 seg->vmaddr = ml_static_slide(seg->vmaddr);
5952
5953 #if KASLR_KEXT_DEBUG
5954 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5955 seg->segname,
5956 (unsigned long)ml_static_unslide(seg->vmaddr),
5957 (unsigned long)seg->vmaddr);
5958 #endif
5959
5960 if (!haveRelocBase) {
5961 relocBase = (char *) seg->vmaddr;
5962 haveRelocBase = true;
5963 }
5964 if (!strcmp(seg->segname, "__LINKEDIT")) {
5965 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
5966 haveLinkeditBase = true;
5967 linkeditSeg = seg;
5968 }
5969 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5970 sec->addr = ml_static_slide(sec->addr);
5971
5972 #if KASLR_KEXT_DEBUG
5973 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
5974 sec->sectname,
5975 (unsigned long)ml_static_unslide(sec->addr),
5976 (unsigned long)sec->addr);
5977 #endif
5978 }
5979 }
5980
5981 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
5982
5983 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
5984
5985 if (symtab != NULL && doCoalescedSlides == false) {
5986 /* Some pseudo-kexts have symbol tables without segments.
5987 * Ignore them. */
5988 if (symtab->nsyms > 0 && haveLinkeditBase) {
5989 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
5990 for (i = 0; i < symtab->nsyms; i++) {
5991 if (sym[i].n_type & N_STAB) {
5992 continue;
5993 }
5994 sym[i].n_value = ml_static_slide(sym[i].n_value);
5995
5996 #if KASLR_KEXT_DEBUG
5997 #define MAX_SYMS_TO_LOG 5
5998 if (i < MAX_SYMS_TO_LOG) {
5999 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6000 (unsigned long)ml_static_unslide(sym[i].n_value),
6001 (unsigned long)sym[i].n_value);
6002 }
6003 #endif
6004 }
6005 }
6006 }
6007
6008 if (dysymtab != NULL && doCoalescedSlides == false) {
6009 if (dysymtab->nextrel > 0) {
6010 OSKextLog(this,
6011 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6012 kOSKextLogLinkFlag,
6013 "Sliding kext %s: External relocations found.",
6014 getIdentifierCString());
6015 goto finish;
6016 }
6017
6018 if (dysymtab->nlocrel > 0) {
6019 if (!haveLinkeditBase) {
6020 OSKextLog(this,
6021 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6022 kOSKextLogLinkFlag,
6023 "Sliding kext %s: No linkedit segment.",
6024 getIdentifierCString());
6025 goto finish;
6026 }
6027
6028 if (!haveRelocBase) {
6029 OSKextLog(this,
6030 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6031 kOSKextLogLinkFlag,
6032 #if __x86_64__
6033 "Sliding kext %s: No writable segments.",
6034 #else
6035 "Sliding kext %s: No segments.",
6036 #endif
6037 getIdentifierCString());
6038 goto finish;
6039 }
6040
6041 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6042 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6043
6044 for (i = 0; i < dysymtab->nlocrel; i++) {
6045 if (reloc[i].r_extern != 0
6046 || reloc[i].r_type != 0
6047 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6048 ) {
6049 OSKextLog(this,
6050 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6051 kOSKextLogLinkFlag,
6052 "Sliding kext %s: Unexpected relocation found.",
6053 getIdentifierCString());
6054 goto finish;
6055 }
6056 if (reloc[i].r_pcrel != 0) {
6057 continue;
6058 }
6059 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6060 *relocAddr = ml_static_slide(*relocAddr);
6061
6062 #if KASLR_KEXT_DEBUG
6063 #define MAX_DYSYMS_TO_LOG 5
6064 if (i < MAX_DYSYMS_TO_LOG) {
6065 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6066 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6067 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6068 }
6069 #endif
6070 }
6071
6072 /* We should free these relocations, not just delete the reference to them.
6073 * <rdar://problem/10535549> Free relocations from PIE kexts.
6074 *
6075 * For now, we do not free LINKEDIT for kexts with split segments.
6076 */
6077 new_kextsize = round_page(kmod_info->size - reloc_size);
6078 if (new_kextsize > UINT_MAX) {
6079 OSKextLog(this,
6080 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6081 kOSKextLogLinkFlag,
6082 "Kext %s: new kext size is too large.",
6083 getIdentifierCString());
6084 goto finish;
6085 }
6086 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6087 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6088 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6089 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6090 size_t bytes_remaining = endofkext - endofrelocInfo;
6091 OSSharedPtr<OSData> new_osdata;
6092
6093 /* fix up symbol offsets if they are after the dsymtab local relocs */
6094 if (symtab) {
6095 if (dysymtab->locreloff < symtab->symoff) {
6096 symtab->symoff -= reloc_size;
6097 }
6098 if (dysymtab->locreloff < symtab->stroff) {
6099 symtab->stroff -= reloc_size;
6100 }
6101 }
6102 if (dysymtab->locreloff < dysymtab->extreloff) {
6103 dysymtab->extreloff -= reloc_size;
6104 }
6105
6106 /* move data behind reloc info down to new offset */
6107 if (endofrelocInfo < endofkext) {
6108 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6109 }
6110
6111 /* Create a new OSData for the smaller kext object and reflect
6112 * new linkedit segment size.
6113 */
6114 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6115 linkeditSeg->filesize = linkeditSeg->vmsize;
6116
6117 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6118 if (new_osdata) {
6119 /* Fix up kmod info and linkedExecutable.
6120 */
6121 kmod_info->size = new_kextsize;
6122 #if VM_MAPPED_KEXTS
6123 new_osdata->setDeallocFunction(osdata_kext_free);
6124 #else
6125 new_osdata->setDeallocFunction(osdata_phys_free);
6126 #endif
6127 linkedExecutable->setDeallocFunction(NULL);
6128 linkedExecutable = os::move(new_osdata);
6129
6130 #if VM_MAPPED_KEXTS
6131 kext_free(new_endofkext, (endofkext - new_endofkext));
6132 #else
6133 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6134 #endif
6135 }
6136 }
6137 dysymtab->nlocrel = 0;
6138 dysymtab->locreloff = 0;
6139 }
6140 }
6141
6142 result = kOSReturnSuccess;
6143 finish:
6144 return result;
6145 }
6146
6147 /*********************************************************************
6148 * called only by load()
6149 *********************************************************************/
6150 OSReturn
6151 OSKext::loadExecutable()
6152 {
6153 OSReturn result = kOSReturnError;
6154 OSSharedPtr<OSArray> linkDependencies;
6155 uint32_t num_kmod_refs = 0;
6156 OSData * theExecutable = NULL; // do not release
6157 OSString * versString = NULL; // do not release
6158 const char * versCString = NULL; // do not free
6159 const char * string = NULL; // do not free
6160
6161 #if CONFIG_KXLD
6162 unsigned int i;
6163 uint32_t numDirectDependencies = 0;
6164 kern_return_t kxldResult;
6165 KXLDDependency * kxlddeps = NULL; // must kfree
6166 uint32_t num_kxlddeps = 0;
6167 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6168 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6169 #endif // CONFIG_KXLD
6170
6171 /* We need the version string for a variety of bits below.
6172 */
6173 versString = OSDynamicCast(OSString,
6174 getPropertyForHostArch(kCFBundleVersionKey));
6175 if (!versString) {
6176 goto finish;
6177 }
6178 versCString = versString->getCStringNoCopy();
6179
6180 if (isKernelComponent()) {
6181 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6182 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6183 OSKextLog(this,
6184 kOSKextLogErrorLevel |
6185 kOSKextLogLoadFlag,
6186 "Kernel component %s has incorrect version %s; "
6187 "expected %s.",
6188 getIdentifierCString(),
6189 versCString, KERNEL6_VERSION);
6190 result = kOSKextReturnInternalError;
6191 goto finish;
6192 } else if (strcmp(versCString, osrelease)) {
6193 OSKextLog(this,
6194 kOSKextLogErrorLevel |
6195 kOSKextLogLoadFlag,
6196 "Kernel component %s has incorrect version %s; "
6197 "expected %s.",
6198 getIdentifierCString(),
6199 versCString, osrelease);
6200 result = kOSKextReturnInternalError;
6201 goto finish;
6202 }
6203 }
6204 }
6205
6206 #if defined(__x86_64__) || defined(__i386__)
6207 if (flags.resetSegmentsFromVnode) {
6208 /* Fixup the chains and slide the mach headers */
6209 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6210
6211 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6212 result = kOSKextReturnValidation;
6213 goto finish;
6214 }
6215 }
6216 #endif //(__x86_64__) || defined(__i386__)
6217
6218 if (isPrelinked()) {
6219 goto register_kmod;
6220 }
6221
6222 /* <rdar://problem/21444003> all callers must be entitled */
6223 if (FALSE == IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement)) {
6224 OSKextLog(this,
6225 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6226 "Not entitled to link kext '%s'",
6227 getIdentifierCString());
6228 result = kOSKextReturnNotPrivileged;
6229 goto finish;
6230 }
6231
6232 theExecutable = getExecutable();
6233 if (!theExecutable) {
6234 if (declaresExecutable()) {
6235 OSKextLog(this,
6236 kOSKextLogErrorLevel |
6237 kOSKextLogLoadFlag,
6238 "Can't load kext %s - executable is missing.",
6239 getIdentifierCString());
6240 result = kOSKextReturnValidation;
6241 goto finish;
6242 }
6243 goto register_kmod;
6244 }
6245
6246 if (isInterface()) {
6247 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6248 if (executableCopy) {
6249 setLinkedExecutable(executableCopy.get());
6250 }
6251 goto register_kmod;
6252 }
6253
6254 #if CONFIG_KXLD
6255 numDirectDependencies = getNumDependencies();
6256
6257 if (flags.hasBleedthrough) {
6258 linkDependencies = dependencies;
6259 } else {
6260 linkDependencies = OSArray::withArray(dependencies.get());
6261 if (!linkDependencies) {
6262 OSKextLog(this,
6263 kOSKextLogErrorLevel |
6264 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6265 "Can't allocate link dependencies to load kext %s.",
6266 getIdentifierCString());
6267 goto finish;
6268 }
6269
6270 for (i = 0; i < numDirectDependencies; ++i) {
6271 OSKext * dependencyKext = OSDynamicCast(OSKext,
6272 dependencies->getObject(i));
6273 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
6274 }
6275 }
6276
6277 num_kxlddeps = linkDependencies->getCount();
6278 if (!num_kxlddeps) {
6279 OSKextLog(this,
6280 kOSKextLogErrorLevel |
6281 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6282 "Can't load kext %s - it has no library dependencies.",
6283 getIdentifierCString());
6284 goto finish;
6285 }
6286
6287 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
6288 if (!kxlddeps) {
6289 OSKextLog(this,
6290 kOSKextLogErrorLevel |
6291 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6292 "Can't allocate link context to load kext %s.",
6293 getIdentifierCString());
6294 goto finish;
6295 }
6296 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6297
6298 for (i = 0; i < num_kxlddeps; ++i) {
6299 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6300
6301 if (dependency->isInterface()) {
6302 OSKext *interfaceTargetKext = NULL; //do not release
6303 OSData * interfaceTarget = NULL; //do not release
6304
6305 if (dependency->isKernelComponent()) {
6306 interfaceTargetKext = sKernelKext;
6307 interfaceTarget = sKernelKext->linkedExecutable.get();
6308 } else {
6309 interfaceTargetKext = OSDynamicCast(OSKext,
6310 dependency->dependencies->getObject(0));
6311
6312 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
6313 }
6314
6315 if (!interfaceTarget) {
6316 // panic?
6317 goto finish;
6318 }
6319
6320 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6321 * it will be useful to have them in the debugger.
6322 * strdup() failing isn't critical right here so we don't check that.
6323 */
6324 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6325 kxlddeps[i].kext_size = interfaceTarget->getLength();
6326 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6327
6328 if (dependency->linkedExecutable != NULL) {
6329 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6330 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6331 } else {
6332 kxlddeps[i].interface = (u_char *) NULL;
6333 kxlddeps[i].interface_size = 0;
6334 }
6335 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6336 } else {
6337 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6338 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6339 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6340 }
6341
6342 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6343 }
6344
6345 kxldHeaderPtr = &kxld_header;
6346
6347 #if DEBUG
6348 OSKextLog(this,
6349 kOSKextLogExplicitLevel |
6350 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6351 "Kext %s - calling kxld_link_file:\n"
6352 " kxld_context: %p\n"
6353 " executable: %p executable_length: %d\n"
6354 " user_data: %p\n"
6355 " kxld_dependencies: %p num_dependencies: %d\n"
6356 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6357 getIdentifierCString(), sKxldContext,
6358 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6359 this, kxlddeps, num_kxlddeps,
6360 kxldHeaderPtr, &kmod_info);
6361 #endif
6362
6363 /* After this call, the linkedExecutable instance variable
6364 * should exist.
6365 */
6366 kxldResult = kxld_link_file(sKxldContext,
6367 (u_char *)theExecutable->getBytesNoCopy(),
6368 theExecutable->getLength(),
6369 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6370 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6371
6372 if (kxldResult != KERN_SUCCESS) {
6373 // xxx - add kxldResult here?
6374 OSKextLog(this,
6375 kOSKextLogErrorLevel |
6376 kOSKextLogLoadFlag,
6377 "Can't load kext %s - link failed.",
6378 getIdentifierCString());
6379 result = kOSKextReturnLinkError;
6380 goto finish;
6381 }
6382
6383 /* We've written data & instructions into kernel memory, so flush the data
6384 * cache and invalidate the instruction cache.
6385 * I/D caches are coherent on x86
6386 */
6387 #if !defined(__i386__) && !defined(__x86_64__)
6388 flush_dcache(kmod_info->address, kmod_info->size, false);
6389 invalidate_icache(kmod_info->address, kmod_info->size, false);
6390 #endif
6391
6392 #else // !CONFIG_KXLD
6393 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6394 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6395 result = kOSKextReturnLinkError;
6396 goto finish;
6397 #endif // CONFIG_KXLD
6398
6399 register_kmod:
6400
6401 if (isInterface()) {
6402 /* Whip up a fake kmod_info entry for the interface kext.
6403 */
6404 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
6405 if (!kmod_info) {
6406 result = KERN_MEMORY_ERROR;
6407 goto finish;
6408 }
6409
6410 /* A pseudokext has almost nothing in its kmod_info struct.
6411 */
6412 bzero(kmod_info, sizeof(kmod_info_t));
6413
6414 kmod_info->info_version = KMOD_INFO_VERSION;
6415
6416 /* An interface kext doesn't have a linkedExecutable, so save a
6417 * copy of the UUID out of the original executable via copyUUID()
6418 * while we still have the original executable.
6419 */
6420 interfaceUUID = copyUUID();
6421 }
6422
6423 kmod_info->id = loadTag = sNextLoadTag++;
6424 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
6425
6426 /* Stamp the bundle ID and version from the OSKext over anything
6427 * resident inside the kmod_info.
6428 */
6429 string = getIdentifierCString();
6430 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6431
6432 string = versCString;
6433 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6434
6435 /* Add the dependencies' kmod_info structs as kmod_references.
6436 */
6437 num_kmod_refs = getNumDependencies();
6438 if (num_kmod_refs) {
6439 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
6440 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
6441 if (!kmod_info->reference_list) {
6442 result = KERN_MEMORY_ERROR;
6443 goto finish;
6444 }
6445 bzero(kmod_info->reference_list,
6446 num_kmod_refs * sizeof(kmod_reference_t));
6447 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6448 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6449 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6450 ref->info = refKext->kmod_info;
6451 ref->info->reference_count++;
6452
6453 if (refIndex + 1 < num_kmod_refs) {
6454 ref->next = kmod_info->reference_list + refIndex + 1;
6455 }
6456 }
6457 }
6458
6459 if (kmod_info->hdr_size > UINT32_MAX) {
6460 OSKextLog(this,
6461 kOSKextLogErrorLevel |
6462 kOSKextLogLoadFlag,
6463 #if __LP64__
6464 "Kext %s header size is too large (%lu > UINT32_MAX).",
6465 #else
6466 "Kext %s header size is too large (%u > UINT32_MAX).",
6467 #endif
6468 kmod_info->name,
6469 kmod_info->hdr_size);
6470 result = KERN_FAILURE;
6471 goto finish;
6472 }
6473
6474 if (kmod_info->size > UINT32_MAX) {
6475 OSKextLog(this,
6476 kOSKextLogErrorLevel |
6477 kOSKextLogLoadFlag,
6478 #if __LP64__
6479 "Kext %s size is too large (%lu > UINT32_MAX).",
6480 #else
6481 "Kext %s size is too large (%u > UINT32_MAX).",
6482 #endif
6483 kmod_info->name,
6484 kmod_info->size);
6485 result = KERN_FAILURE;
6486 goto finish;
6487 }
6488
6489 if (!isInterface() && linkedExecutable) {
6490 OSKextLog(this,
6491 kOSKextLogProgressLevel |
6492 kOSKextLogLoadFlag,
6493 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6494 kmod_info->name,
6495 (unsigned)kmod_info->size / PAGE_SIZE,
6496 (unsigned long)ml_static_unslide(kmod_info->address),
6497 (unsigned)kmod_info->id);
6498 }
6499
6500 /* VM protections and wiring for the Aux KC are done at collection loading time */
6501 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6502 /* if prelinked and primary KC, VM protections are already set */
6503 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6504 if (result != KERN_SUCCESS) {
6505 goto finish;
6506 }
6507 }
6508
6509 #if KASAN
6510 if (linkedExecutable) {
6511 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6512 linkedExecutable->getLength(), getIdentifierCString());
6513 }
6514 #else
6515 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6516 OSKextLog(this,
6517 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6518 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6519 getIdentifierCString()
6520 );
6521 result = KERN_FAILURE;
6522 goto finish;
6523 }
6524 #endif
6525
6526 result = kOSReturnSuccess;
6527
6528 finish:
6529
6530 #if CONFIG_KXLD
6531 /* Clear up locally allocated dependency info.
6532 */
6533 for (i = 0; i < num_kxlddeps; ++i) {
6534 size_t size;
6535
6536 if (kxlddeps[i].kext_name) {
6537 size = 1 + strlen(kxlddeps[i].kext_name);
6538 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].kext_name, size);
6539 }
6540 if (kxlddeps[i].interface_name) {
6541 size = 1 + strlen(kxlddeps[i].interface_name);
6542 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].interface_name, size);
6543 }
6544 }
6545 if (kxlddeps) {
6546 kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
6547 }
6548 #endif // CONFIG_KXLD
6549
6550 /* We no longer need the unrelocated executable (which the linker
6551 * has altered anyhow).
6552 */
6553 setExecutable(NULL);
6554
6555 if (result != kOSReturnSuccess) {
6556 OSKextLog(this,
6557 kOSKextLogErrorLevel |
6558 kOSKextLogLoadFlag,
6559 "Failed to load executable for kext %s.",
6560 getIdentifierCString());
6561
6562 if (kmod_info && kmod_info->reference_list) {
6563 kfree(kmod_info->reference_list,
6564 num_kmod_refs * sizeof(kmod_reference_t));
6565 }
6566 if (isInterface()) {
6567 kfree(kmod_info, sizeof(kmod_info_t));
6568 kmod_info = NULL;
6569 }
6570 if (kc_type == KCKindUnknown) {
6571 kmod_info = NULL;
6572 if (linkedExecutable) {
6573 linkedExecutable.reset();
6574 }
6575 }
6576 }
6577
6578 return result;
6579 }
6580
6581 #if VM_MAPPED_KEXTS
6582 /* static */
6583 void
6584 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6585 {
6586 kernel_segment_command_t *linkeditseg = NULL;
6587
6588 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6589 assert(linkeditseg != NULL);
6590
6591 /* BootKC on x86_64 is not vm mapped */
6592 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6593
6594 OSKextLog(/* kext */ NULL,
6595 kOSKextLogProgressLevel |
6596 kOSKextLogGeneralFlag,
6597 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6598 linkeditseg->vmaddr, linkeditseg->vmsize);
6599 }
6600 #endif /* VM_MAPPED_KEXTS */
6601
6602 /*********************************************************************
6603 * The linkedit segment is used by the kext linker for dependency
6604 * resolution, and by dtrace for probe initialization. We can free it
6605 * for non-library kexts, since no kexts depend on non-library kexts
6606 * by definition, once dtrace has been initialized.
6607 *********************************************************************/
6608 void
6609 OSKext::jettisonLinkeditSegment(void)
6610 {
6611 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6612 kernel_segment_command_t * linkedit = NULL;
6613 vm_offset_t start;
6614 vm_size_t linkeditsize, kextsize;
6615 OSSharedPtr<OSData> data;
6616
6617 if (isInFileset()) {
6618 return;
6619 }
6620
6621 #if NO_KEXTD
6622 /* We can free symbol tables for all embedded kexts because we don't
6623 * support runtime kext linking.
6624 */
6625 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6626 #else
6627 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6628 #endif
6629 goto finish;
6630 }
6631
6632 /* Find the linkedit segment. If it's not the last segment, then freeing
6633 * it will fragment the kext into multiple VM regions, which OSKext is not
6634 * designed to handle, so we'll have to skip it.
6635 */
6636 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6637 if (!linkedit) {
6638 goto finish;
6639 }
6640
6641 if (round_page(kmod_info->address + kmod_info->size) !=
6642 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6643 goto finish;
6644 }
6645
6646 /* Create a new OSData for the smaller kext object.
6647 */
6648 linkeditsize = round_page(linkedit->vmsize);
6649 kextsize = kmod_info->size - linkeditsize;
6650 start = linkedit->vmaddr;
6651
6652 if (kextsize > UINT_MAX) {
6653 goto finish;
6654 }
6655 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6656 if (!data) {
6657 goto finish;
6658 }
6659
6660 /* Fix the kmod info and linkedExecutable.
6661 */
6662 kmod_info->size = kextsize;
6663
6664 #if VM_MAPPED_KEXTS
6665 data->setDeallocFunction(osdata_kext_free);
6666 #else
6667 data->setDeallocFunction(osdata_phys_free);
6668 #endif
6669 linkedExecutable->setDeallocFunction(NULL);
6670 linkedExecutable = os::move(data);
6671 flags.jettisonLinkeditSeg = 1;
6672
6673 /* Free the linkedit segment.
6674 */
6675 #if VM_MAPPED_KEXTS
6676 kext_free(start, linkeditsize);
6677 #else
6678 ml_static_mfree(start, linkeditsize);
6679 #endif
6680
6681 finish:
6682 return;
6683 }
6684
6685 /*********************************************************************
6686 * If there are whole pages that are unused betweem the last section
6687 * of the DATA segment and the end of the DATA segment then we can free
6688 * them
6689 *********************************************************************/
6690 void
6691 OSKext::jettisonDATASegmentPadding(void)
6692 {
6693 kernel_mach_header_t * mh;
6694 kernel_segment_command_t * dataSeg;
6695 kernel_section_t * sec, * lastSec;
6696 vm_offset_t dataSegEnd, lastSecEnd;
6697 vm_size_t padSize;
6698
6699 if (flags.builtin) {
6700 return;
6701 }
6702 mh = (kernel_mach_header_t *)kmod_info->address;
6703
6704 if (isInFileset()) {
6705 return;
6706 }
6707
6708 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6709 if (dataSeg == NULL) {
6710 return;
6711 }
6712
6713 lastSec = NULL;
6714 sec = firstsect(dataSeg);
6715 while (sec != NULL) {
6716 lastSec = sec;
6717 sec = nextsect(dataSeg, sec);
6718 }
6719
6720 if (lastSec == NULL) {
6721 return;
6722 }
6723
6724 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6725 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6726 return;
6727 }
6728
6729 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6730 lastSecEnd = round_page(lastSec->addr + lastSec->size);
6731
6732 if (dataSegEnd <= lastSecEnd) {
6733 return;
6734 }
6735
6736 padSize = dataSegEnd - lastSecEnd;
6737
6738 if (padSize >= PAGE_SIZE) {
6739 #if VM_MAPPED_KEXTS
6740 kext_free(lastSecEnd, padSize);
6741 #else
6742 ml_static_mfree(lastSecEnd, padSize);
6743 #endif
6744 }
6745 }
6746
6747 /*********************************************************************
6748 *********************************************************************/
6749 void
6750 OSKext::setLinkedExecutable(OSData * anExecutable)
6751 {
6752 if (linkedExecutable) {
6753 panic("Attempt to set linked executable on kext "
6754 "that already has one (%s).\n",
6755 getIdentifierCString());
6756 }
6757 linkedExecutable.reset(anExecutable, OSRetain);
6758 return;
6759 }
6760
6761 #if CONFIG_DTRACE
6762 /*********************************************************************
6763 * Go through all loaded kexts and tell them to register with dtrace.
6764 * The instance method only registers if necessary.
6765 *********************************************************************/
6766 /* static */
6767 void
6768 OSKext::registerKextsWithDTrace(void)
6769 {
6770 uint32_t count = sLoadedKexts->getCount();
6771 uint32_t i;
6772
6773 IORecursiveLockLock(sKextLock);
6774
6775 for (i = 0; i < count; i++) {
6776 OSKext * thisKext = NULL; // do not release
6777
6778 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6779 if (!thisKext || !thisKext->isExecutable()) {
6780 continue;
6781 }
6782
6783 thisKext->registerWithDTrace();
6784 }
6785
6786 IORecursiveLockUnlock(sKextLock);
6787
6788 return;
6789 }
6790
6791 extern "C" {
6792 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6793 extern int (*dtrace_modunload)(struct kmod_info *);
6794 };
6795
6796 /*********************************************************************
6797 *********************************************************************/
6798 void
6799 OSKext::registerWithDTrace(void)
6800 {
6801 /* Register kext with dtrace. A dtrace_modload failure should not
6802 * prevent a kext from loading, so we ignore the return code.
6803 */
6804 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6805 uint32_t modflag = 0;
6806 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
6807
6808 #if VM_MAPPED_KEXTS
6809 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6810 if (forceInit == kOSBooleanTrue) {
6811 /* Make sure the kext is not from the Boot KC */
6812 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6813 } else {
6814 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6815 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6816 }
6817 }
6818 #endif /* VM_MAPPED_KEXTS */
6819 if (forceInit == kOSBooleanTrue) {
6820 modflag |= KMOD_DTRACE_FORCE_INIT;
6821 }
6822 if (flags.builtin) {
6823 modflag |= KMOD_DTRACE_STATIC_KEXT;
6824 }
6825
6826 (void)(*dtrace_modload)(kmod_info, modflag);
6827 flags.dtraceInitialized = true;
6828 jettisonLinkeditSegment();
6829 }
6830 return;
6831 }
6832 /*********************************************************************
6833 *********************************************************************/
6834 void
6835 OSKext::unregisterWithDTrace(void)
6836 {
6837 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6838 * prevent a kext from loading, so we ignore the return code.
6839 */
6840 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6841 (void)(*dtrace_modunload)(kmod_info);
6842 flags.dtraceInitialized = false;
6843 }
6844 return;
6845 }
6846 #endif /* CONFIG_DTRACE */
6847
6848
6849 /*********************************************************************
6850 * called only by loadExecutable()
6851 *********************************************************************/
6852 #if !VM_MAPPED_KEXTS
6853 #if defined(__arm__) || defined(__arm64__)
6854 static inline kern_return_t
6855 OSKext_protect(
6856 kernel_mach_header_t *kext_mh,
6857 vm_map_t map,
6858 vm_map_offset_t start,
6859 vm_map_offset_t end,
6860 vm_prot_t new_prot,
6861 boolean_t set_max,
6862 kc_kind_t kc_type)
6863 {
6864 #pragma unused(kext_mh,map,kc_type)
6865 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
6866 assert(start <= end);
6867 if (start >= end) {
6868 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6869 } else if (set_max) {
6870 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
6871 } else {
6872 return ml_static_protect(start, end - start, new_prot);
6873 }
6874 }
6875
6876 static inline kern_return_t
6877 OSKext_wire(
6878 kernel_mach_header_t *kext_mh,
6879 vm_map_t map,
6880 vm_map_offset_t start,
6881 vm_map_offset_t end,
6882 vm_prot_t access_type,
6883 boolean_t user_wire,
6884 kc_kind_t kc_type)
6885 {
6886 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6887 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
6888 }
6889 #else
6890 #error Unrecognized architecture
6891 #endif
6892 #else
6893 static inline kern_return_t
6894 OSKext_protect(
6895 kernel_mach_header_t *kext_mh,
6896 vm_map_t map,
6897 vm_map_offset_t start,
6898 vm_map_offset_t end,
6899 vm_prot_t new_prot,
6900 boolean_t set_max,
6901 kc_kind_t kc_type)
6902 {
6903 if (start == end) { // 10538581
6904 return KERN_SUCCESS;
6905 }
6906 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6907 /*
6908 * XXX: This will probably need to be different for AuxKC and
6909 * pageableKC!
6910 */
6911 return ml_static_protect(start, end - start, new_prot);
6912 }
6913 return vm_map_protect(map, start, end, new_prot, set_max);
6914 }
6915
6916 static inline kern_return_t
6917 OSKext_wire(
6918 kernel_mach_header_t *kext_mh,
6919 vm_map_t map,
6920 vm_map_offset_t start,
6921 vm_map_offset_t end,
6922 vm_prot_t access_type,
6923 boolean_t user_wire,
6924 kc_kind_t kc_type)
6925 {
6926 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6927 /* TODO: we may need to hook this for the pageableKC */
6928 return KERN_SUCCESS;
6929 }
6930 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
6931 }
6932 #endif
6933
6934 OSReturn
6935 OSKext::setVMAttributes(bool protect, bool wire)
6936 {
6937 vm_map_t kext_map = NULL;
6938 kernel_segment_command_t * seg = NULL;
6939 vm_map_offset_t start_protect = 0;
6940 vm_map_offset_t start_wire = 0;
6941 vm_map_offset_t end_protect = 0;
6942 vm_map_offset_t end_wire = 0;
6943 OSReturn result = kOSReturnError;
6944
6945 if (isInterface() || !declaresExecutable() || flags.builtin) {
6946 result = kOSReturnSuccess;
6947 goto finish;
6948 }
6949
6950 /* Get the kext's vm map */
6951 kext_map = kext_get_vm_map(kmod_info);
6952 if (!kext_map) {
6953 result = KERN_MEMORY_ERROR;
6954 goto finish;
6955 }
6956
6957 #if !VM_MAPPED_KEXTS
6958 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
6959 /* This is a split kext in a prelinked kernelcache; we'll let the
6960 * platform code take care of protecting it. It is already wired.
6961 */
6962 /* TODO: Should this still allow protections for the first segment
6963 * to go through, in the event that we have a mix of split and
6964 * unsplit kexts?
6965 */
6966 result = KERN_SUCCESS;
6967 goto finish;
6968 }
6969
6970 if (isInFileset() && kc_type != KCKindPageable) {
6971 // kexts in filesets have protections setup as part of collection loading
6972 result = KERN_SUCCESS;
6973 goto finish;
6974 }
6975 #endif
6976
6977 /* Protect the headers as read-only; they do not need to be wired */
6978 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
6979 kext_map, kmod_info->address,
6980 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
6981 : KERN_SUCCESS;
6982 if (result != KERN_SUCCESS) {
6983 goto finish;
6984 }
6985
6986 /* Set the VM protections and wire down each of the segments */
6987 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6988 while (seg) {
6989 #if __arm__
6990 /* We build all ARM kexts, so we can ensure they are aligned */
6991 assert((seg->vmaddr & PAGE_MASK) == 0);
6992 assert((seg->vmsize & PAGE_MASK) == 0);
6993 #endif
6994
6995 /*
6996 * For the non page aligned segments, the range calculation for protection
6997 * and wiring differ as follows:
6998 *
6999 * Protection: The non page aligned data at the start or at the end of the
7000 * segment is excluded from the protection. This exclusion is needed to make
7001 * sure OSKext_protect is not called twice on same page, if the page is shared
7002 * between two segments.
7003 *
7004 * Wiring: The non page aligned data at the start or at the end of the
7005 * segment is included in the wiring range, this inclusion is needed to make sure
7006 * all the data of the segment is wired.
7007 */
7008 start_protect = round_page(seg->vmaddr);
7009 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7010
7011 start_wire = trunc_page(seg->vmaddr);
7012 end_wire = round_page(seg->vmaddr + seg->vmsize);
7013
7014 /*
7015 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7016 * across kexts and data from kexts is not page aligned
7017 */
7018 if (protect && (end_protect > start_protect) &&
7019 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7020 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7021 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7022 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7023 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7024 if (result != KERN_SUCCESS) {
7025 OSKextLog(this,
7026 kOSKextLogErrorLevel |
7027 kOSKextLogLoadFlag,
7028 "Kext %s failed to set maximum VM protections "
7029 "for segment %s - 0x%x.",
7030 getIdentifierCString(), seg->segname, (int)result);
7031 goto finish;
7032 }
7033
7034 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7035 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7036 if (result != KERN_SUCCESS) {
7037 OSKextLog(this,
7038 kOSKextLogErrorLevel |
7039 kOSKextLogLoadFlag,
7040 "Kext %s failed to set initial VM protections "
7041 "for segment %s - 0x%x.",
7042 getIdentifierCString(), seg->segname, (int)result);
7043 goto finish;
7044 }
7045 }
7046
7047 if (segmentShouldBeWired(seg) && wire) {
7048 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7049 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7050 if (result != KERN_SUCCESS) {
7051 goto finish;
7052 }
7053 }
7054
7055 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7056 }
7057
7058 finish:
7059 return result;
7060 }
7061
7062 /*********************************************************************
7063 *********************************************************************/
7064 boolean_t
7065 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7066 {
7067 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7068 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7069 }
7070
7071 /*********************************************************************
7072 *********************************************************************/
7073 OSReturn
7074 OSKext::validateKextMapping(bool startFlag)
7075 {
7076 OSReturn result = kOSReturnError;
7077 const char * whichOp = startFlag ? "start" : "stop";
7078 kern_return_t kern_result = 0;
7079 vm_map_t kext_map = NULL;
7080 kernel_segment_command_t * seg = NULL;
7081 mach_vm_address_t address = 0;
7082 mach_vm_size_t size = 0;
7083 uint32_t depth = 0;
7084 uint64_t kext_segbase = 0;
7085 uint64_t kext_segsize = 0;
7086 mach_msg_type_number_t count;
7087 vm_region_submap_short_info_data_64_t info;
7088 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7089
7090 if (flags.builtin) {
7091 return kOSReturnSuccess;
7092 }
7093
7094 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7095 bzero(&info, sizeof(info));
7096
7097 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7098 // xxx - sufficient?
7099
7100 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7101 */
7102 if (!kmod_info) {
7103 OSKextLog(this,
7104 kOSKextLogErrorLevel |
7105 kOSKextLogLoadFlag,
7106 "Kext %s - NULL kmod_info pointer.",
7107 getIdentifierCString());
7108 result = kOSKextReturnBadData;
7109 goto finish;
7110 }
7111
7112 if (startFlag) {
7113 address = (mach_vm_address_t)kmod_info->start;
7114 } else {
7115 address = (mach_vm_address_t)kmod_info->stop;
7116 }
7117
7118 if (!address) {
7119 OSKextLog(this,
7120 kOSKextLogErrorLevel |
7121 kOSKextLogLoadFlag,
7122 "Kext %s - NULL module %s pointer.",
7123 getIdentifierCString(), whichOp);
7124 result = kOSKextReturnBadData;
7125 goto finish;
7126 }
7127
7128 kext_map = kext_get_vm_map(kmod_info);
7129 depth = (kernel_map == kext_map) ? 1 : 2;
7130 if (isInFileset()) {
7131 #if defined(HAS_APPLE_PAC)
7132 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7133 #endif /* defined(HAS_APPLE_PAC) */
7134 }
7135
7136 /* Verify that the start/stop function lies within the kext's address range.
7137 */
7138 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7139 isInFileset()) {
7140 /* This will likely be how we deal with split kexts; walk the segments to
7141 * check that the function lies inside one of the segments of this kext.
7142 */
7143 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7144 seg != NULL;
7145 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7146 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7147 kext_segbase = seg->vmaddr;
7148 kext_segsize = seg->vmsize;
7149 break;
7150 }
7151 }
7152
7153 if (!seg) {
7154 OSKextLog(this,
7155 kOSKextLogErrorLevel |
7156 kOSKextLogLoadFlag,
7157 "Kext %s module %s pointer is outside of kext range "
7158 "(%s %p - kext starts at %p).",
7159 getIdentifierCString(),
7160 whichOp,
7161 whichOp,
7162 (void *)(((uintptr_t)address) - kext_slide),
7163 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7164 result = kOSKextReturnBadData;
7165 goto finish;
7166 }
7167
7168 seg = NULL;
7169 } else {
7170 if (address < kmod_info->address + kmod_info->hdr_size ||
7171 kmod_info->address + kmod_info->size <= address) {
7172 OSKextLog(this,
7173 kOSKextLogErrorLevel |
7174 kOSKextLogLoadFlag,
7175 "Kext %s module %s pointer is outside of kext range "
7176 "(%s %p - kext at %p-%p).",
7177 getIdentifierCString(),
7178 whichOp,
7179 whichOp,
7180 (void *)(((uintptr_t)address) - kext_slide),
7181 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7182 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7183 result = kOSKextReturnBadData;
7184 goto finish;
7185 }
7186 }
7187
7188 /* Only do these checks before calling the start function;
7189 * If anything goes wrong with the mapping while the kext is running,
7190 * we'll likely have panicked well before any attempt to stop the kext.
7191 */
7192 if (startFlag) {
7193 if (!isInFileset() || kc_type != KCKindPrimary) {
7194 /*
7195 * Verify that the start/stop function is executable.
7196 */
7197 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7198 (vm_region_recurse_info_t)&info, &count);
7199 if (kern_result != KERN_SUCCESS) {
7200 OSKextLog(this,
7201 kOSKextLogErrorLevel |
7202 kOSKextLogLoadFlag,
7203 "Kext %s - bad %s pointer %p.",
7204 getIdentifierCString(),
7205 whichOp, (void *)ml_static_unslide(address));
7206 result = kOSKextReturnBadData;
7207 goto finish;
7208 }
7209 } else {
7210 /*
7211 * Since kexts loaded from the primary KC are held in memory
7212 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7213 * discover that memory's protection flags. Instead, we need to
7214 * get that information from the kernel pmap itself. Above, we
7215 * (potentially) saved the size of the segment in which the address
7216 * in question was located. If we have a non-zero size, verify
7217 * that all pages in the (address, address + kext_segsize) range
7218 * are marked executable. If we somehow did not record the size
7219 * (or the base) just verify the single page that includes the address.
7220 */
7221 if (kext_segbase == 0 || kext_segsize == 0) {
7222 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7223 kext_segsize = PAGE_SIZE;
7224 }
7225 }
7226
7227 #if VM_MAPPED_KEXTS
7228 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7229 ((isInFileset() && kc_type == KCKindPrimary) &&
7230 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
7231 OSKextLog(this,
7232 kOSKextLogErrorLevel |
7233 kOSKextLogLoadFlag,
7234 "Kext %s - memory region containing module %s function "
7235 "is not executable.",
7236 getIdentifierCString(), whichOp);
7237 result = kOSKextReturnBadData;
7238 goto finish;
7239 }
7240 #endif
7241
7242 /* Verify that the kext's segments are backed by physical memory.
7243 */
7244 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7245 while (seg) {
7246 if (!verifySegmentMapping(seg)) {
7247 result = kOSKextReturnBadData;
7248 goto finish;
7249 }
7250
7251 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7252 }
7253 }
7254
7255 result = kOSReturnSuccess;
7256 finish:
7257 return result;
7258 }
7259
7260 /*********************************************************************
7261 *********************************************************************/
7262 boolean_t
7263 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7264 {
7265 mach_vm_address_t address = 0;
7266
7267 if (seg->vmsize > UINT32_MAX) {
7268 return false;
7269 }
7270
7271 if (!segmentShouldBeWired(seg)) {
7272 return true;
7273 }
7274
7275 for (address = seg->vmaddr;
7276 address < round_page(seg->vmaddr + seg->vmsize);
7277 address += PAGE_SIZE) {
7278 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7279 OSKextLog(this,
7280 kOSKextLogErrorLevel |
7281 kOSKextLogLoadFlag,
7282 "Kext %s - page %p is not backed by physical memory.",
7283 getIdentifierCString(),
7284 (void *)address);
7285 return false;
7286 }
7287 }
7288
7289 return true;
7290 }
7291
7292 /*********************************************************************
7293 *********************************************************************/
7294 static void
7295 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7296 {
7297 uint64_t stamp = 0;
7298 firehose_tracepoint_id_u trace_id;
7299 struct firehose_trace_uuid_info_s uuid_info_s;
7300 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7301 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
7302 OSSharedPtr<OSData> uuid_data;
7303
7304 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7305 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
7306
7307 uuid_data = aKext->copyTextUUID();
7308 if (uuid_data) {
7309 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
7310 }
7311
7312 uuid_info->ftui_size = size;
7313 if (aKext->isDriverKit()) {
7314 uuid_info->ftui_address = address;
7315 } else {
7316 uuid_info->ftui_address = ml_static_unslide(address);
7317 }
7318 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7319 return;
7320 }
7321
7322 void
7323 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7324 {
7325 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7326 }
7327
7328 /*********************************************************************
7329 *********************************************************************/
7330 OSReturn
7331 OSKext::start(bool startDependenciesFlag)
7332 {
7333 OSReturn result = kOSReturnError;
7334 kern_return_t (* startfunc)(kmod_info_t *, void *);
7335 unsigned int i, count;
7336 void * kmodStartData = NULL;
7337
7338 if (isStarted() || isInterface() || isKernelComponent()) {
7339 result = kOSReturnSuccess;
7340 goto finish;
7341 }
7342
7343 if (!isLoaded()) {
7344 OSKextLog(this,
7345 kOSKextLogErrorLevel |
7346 kOSKextLogLoadFlag,
7347 "Attempt to start nonloaded kext %s.",
7348 getIdentifierCString());
7349 result = kOSKextReturnInvalidArgument;
7350 goto finish;
7351 }
7352
7353 if (!sLoadEnabled) {
7354 OSKextLog(this,
7355 kOSKextLogErrorLevel |
7356 kOSKextLogLoadFlag,
7357 "Kext loading is disabled (attempt to start kext %s).",
7358 getIdentifierCString());
7359 result = kOSKextReturnDisabled;
7360 goto finish;
7361 }
7362
7363 result = validateKextMapping(/* start? */ true);
7364 if (result != kOSReturnSuccess) {
7365 goto finish;
7366 }
7367
7368 startfunc = kmod_info->start;
7369
7370 count = getNumDependencies();
7371 for (i = 0; i < count; i++) {
7372 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7373 if (dependency == NULL) {
7374 OSKextLog(this,
7375 kOSKextLogErrorLevel |
7376 kOSKextLogLoadFlag,
7377 "Kext %s start - internal error, dependency disappeared.",
7378 getIdentifierCString());
7379 goto finish;
7380 }
7381 if (!dependency->isStarted()) {
7382 if (startDependenciesFlag) {
7383 OSReturn dependencyResult =
7384 dependency->start(startDependenciesFlag);
7385 if (dependencyResult != KERN_SUCCESS) {
7386 OSKextLog(this,
7387 kOSKextLogErrorLevel |
7388 kOSKextLogLoadFlag,
7389 "Kext %s start - dependency %s failed to start (error 0x%x).",
7390 getIdentifierCString(),
7391 dependency->getIdentifierCString(),
7392 dependencyResult);
7393 goto finish;
7394 }
7395 } else {
7396 OSKextLog(this,
7397 kOSKextLogErrorLevel |
7398 kOSKextLogLoadFlag,
7399 "Not starting %s - dependency %s not started yet.",
7400 getIdentifierCString(),
7401 dependency->getIdentifierCString());
7402 result = kOSKextReturnStartStopError; // xxx - make new return?
7403 goto finish;
7404 }
7405 }
7406 }
7407
7408 OSKextLog(this,
7409 kOSKextLogDetailLevel |
7410 kOSKextLogLoadFlag,
7411 "Kext %s calling module start function.",
7412 getIdentifierCString());
7413
7414 flags.starting = 1;
7415
7416 // Drop a log message so logd can grab the needed information to decode this kext
7417 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7418 result = OSRuntimeInitializeCPP(this);
7419 if (result == KERN_SUCCESS) {
7420 result = startfunc(kmod_info, kmodStartData);
7421 }
7422
7423 flags.starting = 0;
7424
7425 /* On success overlap the setting of started/starting. On failure just
7426 * clear starting.
7427 */
7428 if (result == KERN_SUCCESS) {
7429 flags.started = 1;
7430
7431 // xxx - log start error from kernel?
7432 OSKextLog(this,
7433 kOSKextLogProgressLevel |
7434 kOSKextLogLoadFlag,
7435 "Kext %s is now started.",
7436 getIdentifierCString());
7437 } else {
7438 invokeOrCancelRequestCallbacks(
7439 /* result not actually used */ kOSKextReturnStartStopError,
7440 /* invokeFlag */ false);
7441 OSKextLog(this,
7442 kOSKextLogWarningLevel |
7443 kOSKextLogLoadFlag,
7444 "Kext %s did not start (return code 0x%x).",
7445 getIdentifierCString(), result);
7446 }
7447
7448 finish:
7449 return result;
7450 }
7451
7452 /*********************************************************************
7453 *********************************************************************/
7454 /* static */
7455 bool
7456 OSKext::canUnloadKextWithIdentifier(
7457 OSString * kextIdentifier,
7458 bool checkClassesFlag)
7459 {
7460 bool result = false;
7461 OSKext * aKext = NULL; // do not release
7462
7463 IORecursiveLockLock(sKextLock);
7464
7465 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7466
7467 if (!aKext) {
7468 goto finish; // can't unload what's not loaded
7469 }
7470
7471 if (aKext->isLoaded()) {
7472 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7473 goto finish;
7474 }
7475 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7476 goto finish;
7477 }
7478 }
7479
7480 result = true;
7481
7482 finish:
7483 IORecursiveLockUnlock(sKextLock);
7484 return result;
7485 }
7486
7487 /*********************************************************************
7488 *********************************************************************/
7489 OSReturn
7490 OSKext::stop(void)
7491 {
7492 OSReturn result = kOSReturnError;
7493 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7494
7495 if (!isStarted() || isInterface()) {
7496 result = kOSReturnSuccess;
7497 goto finish;
7498 }
7499
7500 if (!isLoaded()) {
7501 OSKextLog(this,
7502 kOSKextLogErrorLevel |
7503 kOSKextLogLoadFlag,
7504 "Attempt to stop nonloaded kext %s.",
7505 getIdentifierCString());
7506 result = kOSKextReturnInvalidArgument;
7507 goto finish;
7508 }
7509
7510 /* Refuse to stop if we have clients or instances. It is up to
7511 * the caller to make sure those aren't true.
7512 */
7513 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7514 OSKextLog(this,
7515 kOSKextLogErrorLevel |
7516 kOSKextLogLoadFlag,
7517 "Kext %s - C++ instances; can't stop.",
7518 getIdentifierCString());
7519 result = kOSKextReturnInUse;
7520 goto finish;
7521 }
7522
7523 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7524 OSKextLog(this,
7525 kOSKextLogErrorLevel |
7526 kOSKextLogLoadFlag,
7527 "Kext %s - has references (linkage or tracking object); "
7528 "can't stop.",
7529 getIdentifierCString());
7530 result = kOSKextReturnInUse;
7531 goto finish;
7532 }
7533
7534 /* Note: If validateKextMapping fails on the stop & unload path,
7535 * we are in serious trouble and a kernel panic is likely whether
7536 * we stop & unload the kext or not.
7537 */
7538 result = validateKextMapping(/* start? */ false);
7539 if (result != kOSReturnSuccess) {
7540 goto finish;
7541 }
7542
7543 stopfunc = kmod_info->stop;
7544 if (stopfunc) {
7545 OSKextLog(this,
7546 kOSKextLogDetailLevel |
7547 kOSKextLogLoadFlag,
7548 "Kext %s calling module stop function.",
7549 getIdentifierCString());
7550
7551 flags.stopping = 1;
7552
7553 result = stopfunc(kmod_info, /* userData */ NULL);
7554 if (result == KERN_SUCCESS) {
7555 result = OSRuntimeFinalizeCPP(this);
7556 }
7557
7558 flags.stopping = 0;
7559
7560 if (result == KERN_SUCCESS) {
7561 flags.started = 0;
7562
7563 OSKextLog(this,
7564 kOSKextLogDetailLevel |
7565 kOSKextLogLoadFlag,
7566 "Kext %s is now stopped and ready to unload.",
7567 getIdentifierCString());
7568 } else {
7569 OSKextLog(this,
7570 kOSKextLogErrorLevel |
7571 kOSKextLogLoadFlag,
7572 "Kext %s did not stop (return code 0x%x).",
7573 getIdentifierCString(), result);
7574 result = kOSKextReturnStartStopError;
7575 }
7576 }
7577
7578 finish:
7579 // Drop a log message so logd can update this kext's metadata
7580 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7581 return result;
7582 }
7583
7584 /*********************************************************************
7585 *********************************************************************/
7586 OSReturn
7587 OSKext::unload(void)
7588 {
7589 OSReturn result = kOSReturnError;
7590 unsigned int index;
7591 uint32_t num_kmod_refs = 0;
7592 OSKextAccount * freeAccount;
7593 bool in_fileset = false;
7594
7595 if (!sUnloadEnabled) {
7596 OSKextLog(this,
7597 kOSKextLogErrorLevel |
7598 kOSKextLogLoadFlag,
7599 "Kext unloading is disabled (%s).",
7600 this->getIdentifierCString());
7601
7602 result = kOSKextReturnDisabled;
7603 goto finish;
7604 }
7605
7606 // cache this result so we don't need to access the kmod_info after
7607 // it's been potentially free'd
7608 in_fileset = isInFileset();
7609
7610 /* Refuse to unload if we have clients or instances. It is up to
7611 * the caller to make sure those aren't true.
7612 */
7613 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7614 // xxx - Don't log under errors? this is more of an info thing
7615 OSKextLog(this,
7616 kOSKextLogErrorLevel |
7617 kOSKextLogKextBookkeepingFlag,
7618 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7619 getIdentifierCString());
7620 result = kOSKextReturnInUse;
7621 goto finish;
7622 }
7623
7624 if (isDriverKit()) {
7625 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7626 if (index != (unsigned int)-1) {
7627 sLoadedDriverKitKexts->removeObject(index);
7628 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7629 loadTag = 0;
7630 }
7631 }
7632
7633 if (!isLoaded()) {
7634 result = kOSReturnSuccess;
7635 goto finish;
7636 }
7637
7638 if (isKernelComponent()) {
7639 result = kOSKextReturnInvalidArgument;
7640 goto finish;
7641 }
7642
7643 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
7644 OSKextLog(this,
7645 kOSKextLogErrorLevel |
7646 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7647 "Can't unload kext %s; classes have instances:",
7648 getIdentifierCString());
7649 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7650 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7651 result = kOSKextReturnInUse;
7652 goto finish;
7653 }
7654
7655 /* Note that the kext is unloading before running any code that
7656 * might be in the kext (request callbacks, module stop function).
7657 * We will deny certain requests made against a kext in the process
7658 * of unloading.
7659 */
7660 flags.unloading = 1;
7661
7662 /* Update the string describing the last kext to unload in case we panic.
7663 */
7664 savePanicString(/* isLoading */ false);
7665
7666 if (isStarted()) {
7667 result = stop();
7668 if (result != KERN_SUCCESS) {
7669 OSKextLog(this,
7670 kOSKextLogErrorLevel |
7671 kOSKextLogLoadFlag,
7672 "Kext %s can't unload - module stop returned 0x%x.",
7673 getIdentifierCString(), (unsigned)result);
7674 result = kOSKextReturnStartStopError;
7675 goto finish;
7676 }
7677 }
7678
7679 OSKextLog(this,
7680 kOSKextLogProgressLevel |
7681 kOSKextLogLoadFlag,
7682 "Kext %s unloading.",
7683 getIdentifierCString());
7684
7685 {
7686 struct list_head *p;
7687 struct list_head *prev;
7688 struct list_head *next;
7689 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7690 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7691 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7692 prev = p->prev;
7693 next = p->next;
7694 prev->next = next;
7695 next->prev = prev;
7696 p->prev = p;
7697 p->next = p;
7698 IORecursiveLockWakeup(sKextLock, s, false);
7699 }
7700 }
7701
7702
7703 /* Even if we don't call the stop function, we want to be sure we
7704 * have no OSMetaClass references before unloading the kext executable
7705 * from memory. OSMetaClasses may have pointers into the kext executable
7706 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7707 */
7708 if (metaClasses) {
7709 metaClasses->flushCollection();
7710 }
7711 (void) OSRuntimeFinalizeCPP(this);
7712
7713 /* Remove the kext from the list of loaded kexts, patch the gap
7714 * in the kmod_info_t linked list, and reset "kmod" to point to the
7715 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7716 */
7717 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7718 if (index != (unsigned int)-1) {
7719 sLoadedKexts->removeObject(index);
7720
7721 OSKext * nextKext = OSDynamicCast(OSKext,
7722 sLoadedKexts->getObject(index));
7723
7724 if (nextKext) {
7725 if (index > 0) {
7726 OSKext * gapKext = OSDynamicCast(OSKext,
7727 sLoadedKexts->getObject(index - 1));
7728
7729 nextKext->kmod_info->next = gapKext->kmod_info;
7730 } else { /* index == 0 */
7731 nextKext->kmod_info->next = NULL;
7732 }
7733 }
7734
7735 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7736 if (lastKext && !lastKext->isKernel()) {
7737 kmod = lastKext->kmod_info;
7738 } else {
7739 kmod = NULL; // clear the global kmod variable
7740 }
7741 }
7742
7743 /* Clear out the kmod references that we're keeping for compatibility
7744 * with current panic backtrace code & kgmacros.
7745 * xxx - will want to update those bits sometime and remove this.
7746 */
7747 num_kmod_refs = getNumDependencies();
7748 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7749 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7750 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7751 ref->info->reference_count--;
7752 }
7753 kfree(kmod_info->reference_list,
7754 num_kmod_refs * sizeof(kmod_reference_t));
7755 }
7756
7757 #if CONFIG_DTRACE
7758 unregisterWithDTrace();
7759 #endif /* CONFIG_DTRACE */
7760
7761 notifyKextUnloadObservers(this);
7762
7763 freeAccount = NULL;
7764 IOSimpleLockLock(sKextAccountsLock);
7765 account->kext = NULL;
7766 if (account->site.tag) {
7767 account->site.flags |= VM_TAG_UNLOAD;
7768 } else {
7769 freeAccount = account;
7770 }
7771 IOSimpleLockUnlock(sKextAccountsLock);
7772 if (freeAccount) {
7773 IODelete(freeAccount, OSKextAccount, 1);
7774 }
7775
7776 /* Unwire and free the linked executable.
7777 */
7778 if (linkedExecutable) {
7779 #if KASAN
7780 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
7781 #endif
7782
7783 #if VM_MAPPED_KEXTS
7784 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
7785 kernel_segment_command_t *seg = NULL;
7786 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7787
7788 if (!kext_map) {
7789 OSKextLog(this,
7790 kOSKextLogErrorLevel |
7791 kOSKextLogLoadFlag,
7792 "Failed to free kext %s; couldn't find the kext map.",
7793 getIdentifierCString());
7794 result = kOSKextReturnInternalError;
7795 goto finish;
7796 }
7797
7798 OSKextLog(this,
7799 kOSKextLogProgressLevel |
7800 kOSKextLogLoadFlag,
7801 "Kext %s unwiring and unmapping linked executable.",
7802 getIdentifierCString());
7803
7804 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7805 while (seg) {
7806 if (segmentShouldBeWired(seg)) {
7807 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7808 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7809
7810 result = vm_map_unwire(kext_map, start_wire,
7811 end_wire, FALSE);
7812 if (result != KERN_SUCCESS) {
7813 OSKextLog(this,
7814 kOSKextLogErrorLevel |
7815 kOSKextLogLoadFlag,
7816 "Failed to unwire kext %s.",
7817 getIdentifierCString());
7818 result = kOSKextReturnInternalError;
7819 goto finish;
7820 }
7821 }
7822
7823 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7824 }
7825 #if defined(__x86_64__) || defined(__i386__)
7826 if (in_fileset && flags.resetSegmentsFromVnode) {
7827 IORecursiveLockLock(sKextLock);
7828 resetKCFileSetSegments();
7829 IORecursiveLockUnlock(sKextLock);
7830 }
7831 #endif // (__x86_64__) || defined(__i386__)
7832 }
7833 #endif /* VM_MAPPED_KEXTS */
7834 if (flags.resetSegmentsFromImmutableCopy) {
7835 result = resetMutableSegments();
7836 if (result != kOSReturnSuccess) {
7837 OSKextLog(this,
7838 kOSKextLogErrorLevel |
7839 kOSKextLogLoadFlag,
7840 "Failed to reset kext %s.",
7841 getIdentifierCString());
7842 result = kOSKextReturnInternalError;
7843 goto finish;
7844 }
7845 }
7846 if (kc_type == KCKindUnknown) {
7847 linkedExecutable.reset();
7848 }
7849 }
7850
7851 /* An interface kext has a fake kmod_info that was allocated,
7852 * so we have to free it.
7853 */
7854 if (isInterface()) {
7855 kfree(kmod_info, sizeof(kmod_info_t));
7856 kmod_info = NULL;
7857 }
7858
7859 if (!in_fileset) {
7860 kmod_info = NULL;
7861 }
7862
7863 flags.loaded = false;
7864 flushDependencies();
7865
7866 /* save a copy of the bundle ID for us to check when deciding to
7867 * rebuild the kernel cache file. If a kext was already in the kernel
7868 * cache and unloaded then later loaded we do not need to rebuild the
7869 * kernel cache. 9055303
7870 */
7871 if (isPrelinked()) {
7872 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
7873 IORecursiveLockLock(sKextLock);
7874 if (sUnloadedPrelinkedKexts) {
7875 sUnloadedPrelinkedKexts->setObject(bundleID.get());
7876 }
7877 IORecursiveLockUnlock(sKextLock);
7878 }
7879 }
7880
7881 OSKextLog(this,
7882 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
7883 "Kext %s unloaded.", getIdentifierCString());
7884
7885 queueKextNotification(kKextRequestPredicateUnloadNotification,
7886 OSDynamicCast(OSString, bundleID.get()));
7887
7888 finish:
7889 OSKext::saveLoadedKextPanicList();
7890 OSKext::updateLoadedKextSummaries();
7891
7892 flags.unloading = 0;
7893 return result;
7894 }
7895
7896 /*********************************************************************
7897 * Assumes sKextLock is held.
7898 *********************************************************************/
7899 /* static */
7900 OSReturn
7901 OSKext::queueKextNotification(
7902 const char * notificationName,
7903 OSString * kextIdentifier)
7904 {
7905 OSReturn result = kOSReturnError;
7906 OSSharedPtr<OSDictionary> loadRequest;
7907
7908 if (!kextIdentifier) {
7909 result = kOSKextReturnInvalidArgument;
7910 goto finish;
7911 }
7912
7913 /* Create a new request unless one is already sitting
7914 * in sKernelRequests for this bundle identifier
7915 */
7916 result = _OSKextCreateRequest(notificationName, loadRequest);
7917 if (result != kOSReturnSuccess) {
7918 goto finish;
7919 }
7920 if (!_OSKextSetRequestArgument(loadRequest.get(),
7921 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
7922 result = kOSKextReturnNoMemory;
7923 goto finish;
7924 }
7925 if (!sKernelRequests->setObject(loadRequest.get())) {
7926 result = kOSKextReturnNoMemory;
7927 goto finish;
7928 }
7929
7930 /* We might want to only queue the notification if the IOKit daemon is active,
7931 * but that wouldn't work for embedded. Note that we don't care if
7932 * the ping immediately succeeds here so don't do anything with the
7933 * result of this call.
7934 */
7935 OSKext::pingIOKitDaemon();
7936
7937 result = kOSReturnSuccess;
7938
7939 finish:
7940 return result;
7941 }
7942
7943
7944 #if CONFIG_KXLD
7945 /*********************************************************************
7946 *********************************************************************/
7947 static void
7948 _OSKextConsiderDestroyingLinkContext(
7949 __unused thread_call_param_t p0,
7950 __unused thread_call_param_t p1)
7951 {
7952 /* Take multiple locks in the correct order.
7953 */
7954 IORecursiveLockLock(sKextLock);
7955 IORecursiveLockLock(sKextInnerLock);
7956
7957 /* The first time we destroy the kxldContext is in the first
7958 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
7959 * before calling this function. Thereafter any call to this function
7960 * will actually destroy the context.
7961 */
7962 if (sConsiderUnloadsCalled && sKxldContext) {
7963 kxld_destroy_context(sKxldContext);
7964 sKxldContext = NULL;
7965 }
7966
7967 /* Free the thread_call that was allocated to execute this function.
7968 */
7969 if (sDestroyLinkContextThread) {
7970 if (!thread_call_free(sDestroyLinkContextThread)) {
7971 OSKextLog(/* kext */ NULL,
7972 kOSKextLogErrorLevel |
7973 kOSKextLogGeneralFlag,
7974 "thread_call_free() failed for kext link context.");
7975 }
7976 sDestroyLinkContextThread = NULL;
7977 }
7978
7979 IORecursiveLockUnlock(sKextInnerLock);
7980 IORecursiveLockUnlock(sKextLock);
7981
7982 return;
7983 }
7984
7985 /*********************************************************************
7986 * Destroying the kxldContext requires checking variables under both
7987 * sKextInnerLock and sKextLock, so we do it on a separate thread
7988 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
7989 * call relationship.
7990 *
7991 * This function must be invoked with sKextInnerLock held.
7992 * Do not call any function that takes sKextLock here!
7993 *********************************************************************/
7994 /* static */
7995 void
7996 OSKext::considerDestroyingLinkContext(void)
7997 {
7998 IORecursiveLockLock(sKextInnerLock);
7999
8000 /* If we have already queued a thread to destroy the link context,
8001 * don't bother resetting; that thread will take care of it.
8002 */
8003 if (sDestroyLinkContextThread) {
8004 goto finish;
8005 }
8006
8007 /* The function to be invoked in the thread will deallocate
8008 * this thread_call, so don't share it around.
8009 */
8010 sDestroyLinkContextThread = thread_call_allocate(
8011 &_OSKextConsiderDestroyingLinkContext, NULL);
8012 if (!sDestroyLinkContextThread) {
8013 OSKextLog(/* kext */ NULL,
8014 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8015 "Can't create thread to destroy kext link context.");
8016 goto finish;
8017 }
8018
8019 thread_call_enter(sDestroyLinkContextThread);
8020
8021 finish:
8022 IORecursiveLockUnlock(sKextInnerLock);
8023 return;
8024 }
8025
8026 #else // !CONFIG_KXLD
8027
8028 /* static */
8029 void
8030 OSKext::considerDestroyingLinkContext(void)
8031 {
8032 return;
8033 }
8034
8035 #endif // CONFIG_KXLD
8036
8037 #if PRAGMA_MARK
8038 #pragma mark Autounload
8039 #endif
8040 /*********************************************************************
8041 * This is a static method because the kext will be deallocated if it
8042 * does unload!
8043 *********************************************************************/
8044 /* static */
8045 OSReturn
8046 OSKext::autounloadKext(OSKext * aKext)
8047 {
8048 OSReturn result = kOSKextReturnInUse;
8049
8050 #if NO_KEXTD
8051 /*
8052 * Do not unload prelinked kexts on platforms that do not have an
8053 * IOKit daemon as there is no way to reload the kext or restart
8054 * matching.
8055 */
8056 if (aKext->isPrelinked()) {
8057 goto finish;
8058 }
8059 #endif /* defined(__x86_64__) */
8060
8061 /* Check for external references to this kext (usu. dependents),
8062 * instances of defined classes (or classes derived from them),
8063 * outstanding requests.
8064 */
8065 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8066 !aKext->flags.autounloadEnabled ||
8067 aKext->isKernelComponent()) {
8068 goto finish;
8069 }
8070
8071 /* Skip a delay-autounload kext, once.
8072 */
8073 if (aKext->flags.delayAutounload) {
8074 OSKextLog(aKext,
8075 kOSKextLogProgressLevel |
8076 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8077 "Kext %s has delayed autounload set; skipping and clearing flag.",
8078 aKext->getIdentifierCString());
8079 aKext->flags.delayAutounload = 0;
8080 goto finish;
8081 }
8082
8083 if (aKext->hasOSMetaClassInstances() ||
8084 aKext->countRequestCallbacks()) {
8085 goto finish;
8086 }
8087
8088 result = OSKext::removeKext(aKext);
8089
8090 finish:
8091 return result;
8092 }
8093
8094 /*********************************************************************
8095 *********************************************************************/
8096 void
8097 _OSKextConsiderUnloads(
8098 __unused thread_call_param_t p0,
8099 __unused thread_call_param_t p1)
8100 {
8101 bool didUnload = false;
8102 unsigned int count, i;
8103
8104 /* Take multiple locks in the correct order
8105 * (note also sKextSummaries lock further down).
8106 */
8107 IORecursiveLockLock(sKextLock);
8108 IORecursiveLockLock(sKextInnerLock);
8109
8110 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8111
8112 /* If the system is powering down, don't try to unload anything.
8113 */
8114 if (sSystemSleep) {
8115 goto finish;
8116 }
8117
8118 OSKextLog(/* kext */ NULL,
8119 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8120 "Checking for unused kexts to autounload.");
8121
8122 /*****
8123 * Remove any request callbacks marked as stale,
8124 * and mark as stale any currently in flight.
8125 */
8126 count = sRequestCallbackRecords->getCount();
8127 if (count) {
8128 i = count - 1;
8129 do {
8130 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8131 sRequestCallbackRecords->getObject(i));
8132 OSBoolean * stale = OSDynamicCast(OSBoolean,
8133 callbackRecord->getObject(kKextRequestStaleKey));
8134
8135 if (stale == kOSBooleanTrue) {
8136 OSKext::invokeRequestCallback(callbackRecord,
8137 kOSKextReturnTimeout);
8138 } else {
8139 callbackRecord->setObject(kKextRequestStaleKey,
8140 kOSBooleanTrue);
8141 }
8142 } while (i--);
8143 }
8144
8145 /*****
8146 * Make multiple passes through the array of loaded kexts until
8147 * we don't unload any. This handles unwinding of dependency
8148 * chains. We have to go *backwards* through the array because
8149 * kexts are removed from it when unloaded, and we cannot make
8150 * a copy or we'll mess up the retain counts we rely on to
8151 * check whether a kext will unload. If only we could have
8152 * nonretaining collections like CF has....
8153 */
8154 do {
8155 didUnload = false;
8156
8157 count = sLoadedKexts->getCount();
8158 if (count) {
8159 i = count - 1;
8160 do {
8161 OSKext * thisKext = OSDynamicCast(OSKext,
8162 sLoadedKexts->getObject(i));
8163 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8164 } while (i--);
8165 }
8166 } while (didUnload);
8167
8168 finish:
8169 sConsiderUnloadsPending = false;
8170 sConsiderUnloadsExecuted = true;
8171
8172 (void) OSKext::considerRebuildOfPrelinkedKernel();
8173
8174 IORecursiveLockUnlock(sKextInnerLock);
8175 IORecursiveLockUnlock(sKextLock);
8176
8177 return;
8178 }
8179
8180 /*********************************************************************
8181 * Do not call any function that takes sKextLock here!
8182 *********************************************************************/
8183 void
8184 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8185 {
8186 AbsoluteTime when;
8187
8188 IORecursiveLockLock(sKextInnerLock);
8189
8190 if (!sUnloadCallout) {
8191 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8192 }
8193
8194 /* we only reset delay value for unloading if we already have something
8195 * pending. rescheduleOnlyFlag should not start the count down.
8196 */
8197 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8198 goto finish;
8199 }
8200
8201 thread_call_cancel(sUnloadCallout);
8202 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8203 #if !NO_KEXTD
8204 && sIOKitDaemonActive
8205 #endif
8206 ) {
8207 clock_interval_to_deadline(sConsiderUnloadDelay,
8208 1000 * 1000 * 1000, &when);
8209
8210 OSKextLog(/* kext */ NULL,
8211 kOSKextLogProgressLevel |
8212 kOSKextLogLoadFlag,
8213 "%scheduling %sscan for unused kexts in %lu seconds.",
8214 sConsiderUnloadsPending ? "Res" : "S",
8215 sConsiderUnloadsCalled ? "" : "initial ",
8216 (unsigned long)sConsiderUnloadDelay);
8217
8218 sConsiderUnloadsPending = true;
8219 thread_call_enter_delayed(sUnloadCallout, when);
8220 }
8221
8222 finish:
8223 /* The kxld context should be reused throughout boot. We mark the end of
8224 * period as the first time considerUnloads() is called, and we destroy
8225 * the first kxld context in that function. Afterwards, it will be
8226 * destroyed in flushNonloadedKexts.
8227 */
8228 if (!sConsiderUnloadsCalled) {
8229 sConsiderUnloadsCalled = true;
8230 OSKext::considerDestroyingLinkContext();
8231 }
8232
8233 IORecursiveLockUnlock(sKextInnerLock);
8234 return;
8235 }
8236
8237 /*********************************************************************
8238 * Do not call any function that takes sKextLock here!
8239 *********************************************************************/
8240 extern "C" {
8241 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
8242 IOReturn
8243 OSKextSystemSleepOrWake(UInt32 messageType)
8244 {
8245 IORecursiveLockLock(sKextInnerLock);
8246
8247 /* If the system is going to sleep, cancel the reaper thread timer,
8248 * and note that we're in a sleep state in case it just fired but hasn't
8249 * taken the lock yet. If we are coming back from sleep, just
8250 * clear the sleep flag; IOService's normal operation will cause
8251 * unloads to be considered soon enough.
8252 */
8253 if (messageType == kIOMessageSystemWillSleep) {
8254 if (sUnloadCallout) {
8255 thread_call_cancel(sUnloadCallout);
8256 }
8257 sSystemSleep = true;
8258 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8259 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8260 sSystemSleep = false;
8261 clock_get_uptime(&sLastWakeTime);
8262 }
8263 IORecursiveLockUnlock(sKextInnerLock);
8264
8265 return kIOReturnSuccess;
8266 }
8267 };
8268
8269
8270 #if PRAGMA_MARK
8271 #pragma mark Prelinked Kernel
8272 #endif
8273
8274 #ifdef CONFIG_KXLD
8275 /*********************************************************************
8276 * Do not access sConsiderUnloads... variables other than
8277 * sConsiderUnloadsExecuted in this function. They are guarded by a
8278 * different lock.
8279 *********************************************************************/
8280 /* static */
8281 void
8282 OSKext::considerRebuildOfPrelinkedKernel(void)
8283 {
8284 static bool requestedPrelink = false;
8285 OSReturn checkResult = kOSReturnError;
8286 OSSharedPtr<OSDictionary> prelinkRequest;
8287 OSSharedPtr<OSCollectionIterator> kextIterator;
8288 const OSSymbol * thisID = NULL; // do not release
8289 bool doRebuild = false;
8290 AbsoluteTime my_abstime;
8291 UInt64 my_ns;
8292 SInt32 delta_secs;
8293
8294 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8295 if (requestedPrelink || !sPrelinkBoot) {
8296 return;
8297 }
8298
8299 /* no direct return from this point */
8300 IORecursiveLockLock(sKextLock);
8301
8302 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8303 * and any new startup kexts loaded.
8304 */
8305 if (!sConsiderUnloadsExecuted ||
8306 !sDeferredLoadSucceeded) {
8307 goto finish;
8308 }
8309
8310 /* we really only care about boot / system start up related kexts so bail
8311 * if we're here after REBUILD_MAX_TIME.
8312 */
8313 if (!_OSKextInPrelinkRebuildWindow()) {
8314 OSKextLog(/* kext */ NULL,
8315 kOSKextLogArchiveFlag,
8316 "%s prebuild rebuild has expired",
8317 __FUNCTION__);
8318 requestedPrelink = true;
8319 goto finish;
8320 }
8321
8322 /* we do not want to trigger a rebuild if we get here too close to waking
8323 * up. (see radar 10233768)
8324 */
8325 IORecursiveLockLock(sKextInnerLock);
8326
8327 clock_get_uptime(&my_abstime);
8328 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8329 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8330 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8331 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8332 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8333 }
8334 IORecursiveLockUnlock(sKextInnerLock);
8335
8336 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8337 /* too close to time of last wake from sleep */
8338 goto finish;
8339 }
8340 requestedPrelink = true;
8341
8342 /* Now it's time to see if we have a reason to rebuild. We may have done
8343 * some loads and unloads but the kernel cache didn't actually change.
8344 * We will rebuild if any kext is not marked prelinked AND is not in our
8345 * list of prelinked kexts that got unloaded. (see radar 9055303)
8346 */
8347 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
8348 if (!kextIterator) {
8349 goto finish;
8350 }
8351
8352 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
8353 OSKext * thisKext; // do not release
8354
8355 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8356 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8357 continue;
8358 }
8359
8360 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
8361 continue;
8362 }
8363 /* kext is loaded and was not in current kernel cache so let's rebuild
8364 */
8365 doRebuild = true;
8366 OSKextLog(/* kext */ NULL,
8367 kOSKextLogArchiveFlag,
8368 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8369 thisKext->bundleID->getCStringNoCopy());
8370 break;
8371 }
8372 sUnloadedPrelinkedKexts->flushCollection();
8373
8374 if (!doRebuild) {
8375 goto finish;
8376 }
8377
8378 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
8379 prelinkRequest);
8380 if (checkResult != kOSReturnSuccess) {
8381 goto finish;
8382 }
8383
8384 if (!sKernelRequests->setObject(prelinkRequest.get())) {
8385 goto finish;
8386 }
8387
8388 OSKext::pingIOKitDaemon();
8389
8390 finish:
8391 IORecursiveLockUnlock(sKextLock);
8392
8393 return;
8394 }
8395
8396 #else /* !CONFIG_KXLD */
8397
8398 void
8399 OSKext::considerRebuildOfPrelinkedKernel(void)
8400 {
8401 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8402 return;
8403 }
8404
8405 #endif /* CONFIG_KXLD */
8406
8407 #if PRAGMA_MARK
8408 #pragma mark Dependencies
8409 #endif
8410 /*********************************************************************
8411 *********************************************************************/
8412 bool
8413 OSKext::resolveDependencies(
8414 OSArray * loopStack)
8415 {
8416 bool result = false;
8417 OSSharedPtr<OSArray> localLoopStack;
8418 bool addedToLoopStack = false;
8419 OSDictionary * libraries = NULL; // do not release
8420 OSSharedPtr<OSCollectionIterator> libraryIterator;
8421 OSString * libraryID = NULL; // do not release
8422 OSKext * libraryKext = NULL; // do not release
8423 bool hasRawKernelDependency = false;
8424 bool hasKernelDependency = false;
8425 bool hasKPIDependency = false;
8426 bool hasPrivateKPIDependency = false;
8427 unsigned int count;
8428
8429 #if CONFIG_KXLD
8430 OSString * infoString = NULL; // do not release
8431 OSString * readableString = NULL; // do not release
8432 #endif // CONFIG_KXLD
8433
8434 /* A kernel component will automatically have this flag set,
8435 * and a loaded kext should also have it set (as should all its
8436 * loaded dependencies).
8437 */
8438 if (flags.hasAllDependencies) {
8439 result = true;
8440 goto finish;
8441 }
8442
8443 /* Check for loops in the dependency graph.
8444 */
8445 if (loopStack) {
8446 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8447 OSKextLog(this,
8448 kOSKextLogErrorLevel |
8449 kOSKextLogDependenciesFlag,
8450 "Kext %s has a dependency loop; can't resolve dependencies.",
8451 getIdentifierCString());
8452 goto finish;
8453 }
8454 } else {
8455 OSKextLog(this,
8456 kOSKextLogStepLevel |
8457 kOSKextLogDependenciesFlag,
8458 "Kext %s resolving dependencies.",
8459 getIdentifierCString());
8460
8461 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8462 if (!localLoopStack) {
8463 OSKextLog(this,
8464 kOSKextLogErrorLevel |
8465 kOSKextLogDependenciesFlag,
8466 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8467 getIdentifierCString());
8468 goto finish;
8469 }
8470 loopStack = localLoopStack.get();
8471 }
8472 if (!loopStack->setObject(this)) {
8473 OSKextLog(this,
8474 kOSKextLogErrorLevel |
8475 kOSKextLogDependenciesFlag,
8476 "Kext %s - internal error resolving dependencies.",
8477 getIdentifierCString());
8478 goto finish;
8479 }
8480 addedToLoopStack = true;
8481
8482 /* Purge any existing kexts in the dependency list and start over.
8483 */
8484 flushDependencies();
8485 if (dependencies) {
8486 OSKextLog(this,
8487 kOSKextLogErrorLevel |
8488 kOSKextLogDependenciesFlag,
8489 "Kext %s - internal error resolving dependencies.",
8490 getIdentifierCString());
8491 }
8492
8493 libraries = OSDynamicCast(OSDictionary,
8494 getPropertyForHostArch(kOSBundleLibrariesKey));
8495 if (libraries == NULL || libraries->getCount() == 0) {
8496 OSKextLog(this,
8497 kOSKextLogErrorLevel |
8498 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8499 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8500 getIdentifierCString(), kOSBundleLibrariesKey);
8501 goto finish;
8502 }
8503
8504 /* Make a new array to hold the dependencies (flush freed the old one).
8505 */
8506 dependencies = OSArray::withCapacity(libraries->getCount());
8507 if (!dependencies) {
8508 OSKextLog(this,
8509 kOSKextLogErrorLevel |
8510 kOSKextLogDependenciesFlag,
8511 "Kext %s - can't allocate dependencies array.",
8512 getIdentifierCString());
8513 goto finish;
8514 }
8515
8516 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8517 // xxx - compat: if none were declared.
8518
8519 libraryIterator = OSCollectionIterator::withCollection(libraries);
8520 if (!libraryIterator) {
8521 OSKextLog(this,
8522 kOSKextLogErrorLevel |
8523 kOSKextLogDependenciesFlag,
8524 "Kext %s - can't allocate dependencies iterator.",
8525 getIdentifierCString());
8526 goto finish;
8527 }
8528
8529 while ((libraryID = OSDynamicCast(OSString,
8530 libraryIterator->getNextObject()))) {
8531 const char * library_id = libraryID->getCStringNoCopy();
8532
8533 OSString * libraryVersion = OSDynamicCast(OSString,
8534 libraries->getObject(libraryID));
8535 if (libraryVersion == NULL) {
8536 OSKextLog(this,
8537 kOSKextLogErrorLevel |
8538 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8539 "Kext %s - illegal type in OSBundleLibraries.",
8540 getIdentifierCString());
8541 goto finish;
8542 }
8543
8544 OSKextVersion libraryVers =
8545 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8546 if (libraryVers == -1) {
8547 OSKextLog(this,
8548 kOSKextLogErrorLevel |
8549 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8550 "Kext %s - invalid library version %s.",
8551 getIdentifierCString(),
8552 libraryVersion->getCStringNoCopy());
8553 goto finish;
8554 }
8555
8556 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8557 if (libraryKext == NULL) {
8558 OSKextLog(this,
8559 kOSKextLogErrorLevel |
8560 kOSKextLogDependenciesFlag,
8561 "Kext %s - library kext %s not found.",
8562 getIdentifierCString(), library_id);
8563 goto finish;
8564 }
8565
8566 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8567 OSKextLog(this,
8568 kOSKextLogErrorLevel |
8569 kOSKextLogDependenciesFlag,
8570 "Kext %s - library kext %s not compatible "
8571 "with requested version %s.",
8572 getIdentifierCString(), library_id,
8573 libraryVersion->getCStringNoCopy());
8574 goto finish;
8575 }
8576
8577 /* If a nonprelinked library somehow got into the mix for a
8578 * prelinked kext, at any point in the chain, we must fail
8579 * because the prelinked relocs for the library will be all wrong.
8580 */
8581 if (this->isPrelinked() &&
8582 libraryKext->declaresExecutable() &&
8583 !libraryKext->isPrelinked()) {
8584 OSKextLog(this,
8585 kOSKextLogErrorLevel |
8586 kOSKextLogDependenciesFlag,
8587 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8588 getIdentifierCString(), library_id,
8589 libraryVersion->getCStringNoCopy());
8590 goto finish;
8591 }
8592
8593 if (!libraryKext->resolveDependencies(loopStack)) {
8594 goto finish;
8595 }
8596
8597 /* Add the library directly only if it has an executable to link.
8598 * Otherwise it's just used to collect other dependencies, so put
8599 * *its* dependencies on the list for this kext.
8600 */
8601 // xxx - We are losing info here; would like to make fake entries or
8602 // xxx - keep these in the dependency graph for loaded kexts.
8603 // xxx - I really want to make kernel components not a special case!
8604 if (libraryKext->declaresExecutable() ||
8605 libraryKext->isInterface()) {
8606 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8607 dependencies->setObject(libraryKext);
8608
8609 OSKextLog(this,
8610 kOSKextLogDetailLevel |
8611 kOSKextLogDependenciesFlag,
8612 "Kext %s added dependency %s.",
8613 getIdentifierCString(),
8614 libraryKext->getIdentifierCString());
8615 }
8616 } else {
8617 int numLibDependencies = libraryKext->getNumDependencies();
8618 OSArray * libraryDependencies = libraryKext->getDependencies();
8619 int index;
8620
8621 if (numLibDependencies) {
8622 // xxx - this msg level should be 1 lower than the per-kext one
8623 OSKextLog(this,
8624 kOSKextLogDetailLevel |
8625 kOSKextLogDependenciesFlag,
8626 "Kext %s pulling %d dependencies from codeless library %s.",
8627 getIdentifierCString(),
8628 numLibDependencies,
8629 libraryKext->getIdentifierCString());
8630 }
8631 for (index = 0; index < numLibDependencies; index++) {
8632 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8633 libraryDependencies->getObject(index));
8634 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8635 dependencies->setObject(thisLibDependency);
8636 OSKextLog(this,
8637 kOSKextLogDetailLevel |
8638 kOSKextLogDependenciesFlag,
8639 "Kext %s added dependency %s from codeless library %s.",
8640 getIdentifierCString(),
8641 thisLibDependency->getIdentifierCString(),
8642 libraryKext->getIdentifierCString());
8643 }
8644 }
8645 }
8646
8647 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8648 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8649 hasRawKernelDependency = true;
8650 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8651 hasKernelDependency = true;
8652 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8653 hasKPIDependency = true;
8654 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8655 hasPrivateKPIDependency = true;
8656 }
8657 }
8658 }
8659
8660 if (hasRawKernelDependency) {
8661 OSKextLog(this,
8662 kOSKextLogErrorLevel |
8663 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8664 "Error - kext %s declares a dependency on %s, which is not permitted.",
8665 getIdentifierCString(), KERNEL_LIB);
8666 goto finish;
8667 }
8668 #if __LP64__
8669 if (hasKernelDependency) {
8670 OSKextLog(this,
8671 kOSKextLogErrorLevel |
8672 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8673 "Error - kext %s declares %s dependencies. "
8674 "Only %s* dependencies are supported for 64-bit kexts.",
8675 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8676 goto finish;
8677 }
8678 if (!hasKPIDependency) {
8679 OSKextLog(this,
8680 kOSKextLogWarningLevel |
8681 kOSKextLogDependenciesFlag,
8682 "Warning - kext %s declares no %s* dependencies. "
8683 "If it uses any KPIs, the link may fail with undefined symbols.",
8684 getIdentifierCString(), KPI_LIB_PREFIX);
8685 }
8686 #else /* __LP64__ */
8687 // xxx - will change to flatly disallow "kernel" dependencies at some point
8688 // xxx - is it invalid to do both "com.apple.kernel" and any
8689 // xxx - "com.apple.kernel.*"?
8690
8691 if (hasKernelDependency && hasKPIDependency) {
8692 OSKextLog(this,
8693 kOSKextLogWarningLevel |
8694 kOSKextLogDependenciesFlag,
8695 "Warning - kext %s has immediate dependencies on both "
8696 "%s* and %s* components; use only one style.",
8697 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8698 }
8699
8700 if (!hasKernelDependency && !hasKPIDependency) {
8701 // xxx - do we want to use validation flag for these too?
8702 OSKextLog(this,
8703 kOSKextLogWarningLevel |
8704 kOSKextLogDependenciesFlag,
8705 "Warning - %s declares no kernel dependencies; using %s.",
8706 getIdentifierCString(), KERNEL6_LIB);
8707 OSKext * kernelKext = OSDynamicCast(OSKext,
8708 sKextsByID->getObject(KERNEL6_LIB));
8709 if (kernelKext) {
8710 dependencies->setObject(kernelKext);
8711 } else {
8712 OSKextLog(this,
8713 kOSKextLogErrorLevel |
8714 kOSKextLogDependenciesFlag,
8715 "Error - Library %s not found for %s.",
8716 KERNEL6_LIB, getIdentifierCString());
8717 }
8718 }
8719
8720 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8721 * its indirect dependencies to simulate old-style linking. XXX - Should
8722 * check for duplicates.
8723 */
8724 if (!hasKPIDependency) {
8725 unsigned int i;
8726
8727 flags.hasBleedthrough = true;
8728
8729 count = getNumDependencies();
8730
8731 /* We add to the dependencies array in this loop, but do not iterate
8732 * past its original count.
8733 */
8734 for (i = 0; i < count; i++) {
8735 OSKext * dependencyKext = OSDynamicCast(OSKext,
8736 dependencies->getObject(i));
8737 dependencyKext->addBleedthroughDependencies(dependencies.get());
8738 }
8739 }
8740 #endif /* __LP64__ */
8741
8742 #if CONFIG_KXLD
8743 /*
8744 * If we're not dynamically linking kexts, then we don't need to check
8745 * copyright strings. The linker in user space has already done this.
8746 */
8747 if (hasPrivateKPIDependency) {
8748 bool hasApplePrefix = false;
8749 bool infoCopyrightIsValid = false;
8750 bool readableCopyrightIsValid = false;
8751
8752 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8753 APPLE_KEXT_PREFIX);
8754
8755 infoString = OSDynamicCast(OSString,
8756 getPropertyForHostArch("CFBundleGetInfoString"));
8757 if (infoString) {
8758 infoCopyrightIsValid =
8759 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8760 }
8761
8762 readableString = OSDynamicCast(OSString,
8763 getPropertyForHostArch("NSHumanReadableCopyright"));
8764 if (readableString) {
8765 readableCopyrightIsValid =
8766 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8767 }
8768
8769 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8770 OSKextLog(this,
8771 kOSKextLogErrorLevel |
8772 kOSKextLogDependenciesFlag,
8773 "Error - kext %s declares a dependency on %s. "
8774 "Only Apple kexts may declare a dependency on %s.",
8775 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8776 goto finish;
8777 }
8778 }
8779 #endif // CONFIG_KXLD
8780
8781 result = true;
8782 flags.hasAllDependencies = 1;
8783
8784 finish:
8785
8786 if (addedToLoopStack) {
8787 count = loopStack->getCount();
8788 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8789 loopStack->removeObject(count - 1);
8790 } else {
8791 OSKextLog(this,
8792 kOSKextLogErrorLevel |
8793 kOSKextLogDependenciesFlag,
8794 "Kext %s - internal error resolving dependencies.",
8795 getIdentifierCString());
8796 }
8797 }
8798
8799 if (result && localLoopStack) {
8800 OSKextLog(this,
8801 kOSKextLogStepLevel |
8802 kOSKextLogDependenciesFlag,
8803 "Kext %s successfully resolved dependencies.",
8804 getIdentifierCString());
8805 }
8806
8807 return result;
8808 }
8809
8810 /*********************************************************************
8811 *********************************************************************/
8812 bool
8813 OSKext::addBleedthroughDependencies(OSArray * anArray)
8814 {
8815 bool result = false;
8816 unsigned int dependencyIndex, dependencyCount;
8817
8818 dependencyCount = getNumDependencies();
8819
8820 for (dependencyIndex = 0;
8821 dependencyIndex < dependencyCount;
8822 dependencyIndex++) {
8823 OSKext * dependency = OSDynamicCast(OSKext,
8824 dependencies->getObject(dependencyIndex));
8825 if (!dependency) {
8826 OSKextLog(this,
8827 kOSKextLogErrorLevel |
8828 kOSKextLogDependenciesFlag,
8829 "Kext %s - internal error propagating compatibility dependencies.",
8830 getIdentifierCString());
8831 goto finish;
8832 }
8833 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8834 anArray->setObject(dependency);
8835 }
8836 dependency->addBleedthroughDependencies(anArray);
8837 }
8838
8839 result = true;
8840
8841 finish:
8842 return result;
8843 }
8844
8845 /*********************************************************************
8846 *********************************************************************/
8847 bool
8848 OSKext::flushDependencies(bool forceFlag)
8849 {
8850 bool result = false;
8851
8852 /* Only clear the dependencies if the kext isn't loaded;
8853 * we need the info for loaded kexts to track references.
8854 */
8855 if (!isLoaded() || forceFlag) {
8856 if (dependencies) {
8857 // xxx - check level
8858 OSKextLog(this,
8859 kOSKextLogProgressLevel |
8860 kOSKextLogDependenciesFlag,
8861 "Kext %s flushing dependencies.",
8862 getIdentifierCString());
8863 dependencies.reset();
8864 }
8865 if (!isKernelComponent()) {
8866 flags.hasAllDependencies = 0;
8867 }
8868 result = true;
8869 }
8870
8871 return result;
8872 }
8873
8874 /*********************************************************************
8875 *********************************************************************/
8876 uint32_t
8877 OSKext::getNumDependencies(void)
8878 {
8879 if (!dependencies) {
8880 return 0;
8881 }
8882 return dependencies->getCount();
8883 }
8884
8885 /*********************************************************************
8886 *********************************************************************/
8887 OSArray *
8888 OSKext::getDependencies(void)
8889 {
8890 return dependencies.get();
8891 }
8892
8893 bool
8894 OSKext::hasDependency(const OSSymbol * depID)
8895 {
8896 bool result __block;
8897
8898 if (depID == getIdentifier()) {
8899 return true;
8900 }
8901 if (!dependencies) {
8902 return false;
8903 }
8904 result = false;
8905 dependencies->iterateObjects(^bool (OSObject * obj) {
8906 OSKext * kext;
8907 kext = OSDynamicCast(OSKext, obj);
8908 if (!kext) {
8909 return false;
8910 }
8911 result = (depID == kext->getIdentifier());
8912 return result;
8913 });
8914 return result;
8915 }
8916
8917 #if PRAGMA_MARK
8918 #pragma mark OSMetaClass Support
8919 #endif
8920 /*********************************************************************
8921 *********************************************************************/
8922 OSReturn
8923 OSKext::addClass(
8924 OSMetaClass * aClass,
8925 uint32_t numClasses)
8926 {
8927 OSReturn result = kOSMetaClassNoInsKModSet;
8928
8929 if (!metaClasses) {
8930 metaClasses = OSSet::withCapacity(numClasses);
8931 if (!metaClasses) {
8932 goto finish;
8933 }
8934 }
8935
8936 if (metaClasses->containsObject(aClass)) {
8937 OSKextLog(this,
8938 kOSKextLogWarningLevel |
8939 kOSKextLogLoadFlag,
8940 "Notice - kext %s has already registered class %s.",
8941 getIdentifierCString(),
8942 aClass->getClassName());
8943 result = kOSReturnSuccess;
8944 goto finish;
8945 }
8946
8947 if (!metaClasses->setObject(aClass)) {
8948 goto finish;
8949 } else {
8950 OSKextLog(this,
8951 kOSKextLogDetailLevel |
8952 kOSKextLogLoadFlag,
8953 "Kext %s registered class %s.",
8954 getIdentifierCString(),
8955 aClass->getClassName());
8956 }
8957
8958 if (!flags.autounloadEnabled) {
8959 const OSMetaClass * metaScan = NULL; // do not release
8960
8961 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
8962 if (metaScan == OSTypeID(IOService)) {
8963 OSKextLog(this,
8964 kOSKextLogProgressLevel |
8965 kOSKextLogLoadFlag,
8966 "Kext %s has IOService subclass %s; enabling autounload.",
8967 getIdentifierCString(),
8968 aClass->getClassName());
8969
8970 flags.autounloadEnabled = 1;
8971 break;
8972 }
8973 }
8974 }
8975
8976 notifyAddClassObservers(this, aClass, flags);
8977
8978 result = kOSReturnSuccess;
8979
8980 finish:
8981 if (result != kOSReturnSuccess) {
8982 OSKextLog(this,
8983 kOSKextLogErrorLevel |
8984 kOSKextLogLoadFlag,
8985 "Kext %s failed to register class %s.",
8986 getIdentifierCString(),
8987 aClass->getClassName());
8988 }
8989
8990 return result;
8991 }
8992
8993 /*********************************************************************
8994 *********************************************************************/
8995 OSReturn
8996 OSKext::removeClass(
8997 OSMetaClass * aClass)
8998 {
8999 OSReturn result = kOSMetaClassNoKModSet;
9000
9001 if (!metaClasses) {
9002 goto finish;
9003 }
9004
9005 if (!metaClasses->containsObject(aClass)) {
9006 OSKextLog(this,
9007 kOSKextLogWarningLevel |
9008 kOSKextLogLoadFlag,
9009 "Notice - kext %s asked to unregister unknown class %s.",
9010 getIdentifierCString(),
9011 aClass->getClassName());
9012 result = kOSReturnSuccess;
9013 goto finish;
9014 }
9015
9016 OSKextLog(this,
9017 kOSKextLogDetailLevel |
9018 kOSKextLogLoadFlag,
9019 "Kext %s unregistering class %s.",
9020 getIdentifierCString(),
9021 aClass->getClassName());
9022
9023 metaClasses->removeObject(aClass);
9024
9025 notifyRemoveClassObservers(this, aClass, flags);
9026
9027 result = kOSReturnSuccess;
9028
9029 finish:
9030 if (result != kOSReturnSuccess) {
9031 OSKextLog(this,
9032 kOSKextLogErrorLevel |
9033 kOSKextLogLoadFlag,
9034 "Failed to unregister kext %s class %s.",
9035 getIdentifierCString(),
9036 aClass->getClassName());
9037 }
9038 return result;
9039 }
9040
9041 /*********************************************************************
9042 *********************************************************************/
9043 OSSet *
9044 OSKext::getMetaClasses(void)
9045 {
9046 return metaClasses.get();
9047 }
9048
9049 /*********************************************************************
9050 *********************************************************************/
9051 bool
9052 OSKext::hasOSMetaClassInstances(void)
9053 {
9054 bool result = false;
9055 OSSharedPtr<OSCollectionIterator> classIterator;
9056 OSMetaClass * checkClass = NULL; // do not release
9057
9058 if (!metaClasses) {
9059 goto finish;
9060 }
9061
9062 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9063 if (!classIterator) {
9064 // xxx - log alloc failure?
9065 goto finish;
9066 }
9067 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9068 if (checkClass->getInstanceCount()) {
9069 result = true;
9070 goto finish;
9071 }
9072 }
9073
9074 finish:
9075 return result;
9076 }
9077
9078 /*********************************************************************
9079 *********************************************************************/
9080 /* static */
9081 void
9082 OSKext::reportOSMetaClassInstances(
9083 const char * kextIdentifier,
9084 OSKextLogSpec msgLogSpec)
9085 {
9086 OSSharedPtr<OSKext> theKext;
9087
9088 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9089 if (!theKext) {
9090 goto finish;
9091 }
9092
9093 theKext->reportOSMetaClassInstances(msgLogSpec);
9094 finish:
9095 return;
9096 }
9097
9098 /*********************************************************************
9099 *********************************************************************/
9100 void
9101 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9102 {
9103 OSSharedPtr<OSCollectionIterator> classIterator;
9104 OSMetaClass * checkClass = NULL; // do not release
9105
9106 if (!metaClasses) {
9107 goto finish;
9108 }
9109
9110 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9111 if (!classIterator) {
9112 goto finish;
9113 }
9114 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9115 if (checkClass->getInstanceCount()) {
9116 OSKextLog(this,
9117 msgLogSpec,
9118 " Kext %s class %s has %d instance%s.",
9119 getIdentifierCString(),
9120 checkClass->getClassName(),
9121 checkClass->getInstanceCount(),
9122 checkClass->getInstanceCount() == 1 ? "" : "s");
9123 }
9124 }
9125
9126 finish:
9127 return;
9128 }
9129
9130 #if PRAGMA_MARK
9131 #pragma mark User-Space Requests
9132 #endif
9133
9134 static kern_return_t
9135 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9136 {
9137 OSReturn result = kOSReturnSuccess;
9138 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9139 OSDictionary * request = NULL; //do not release
9140 IOUserServerCheckInToken * token = NULL; //do not release
9141 OSString * requestPredicate = NULL; //do not release
9142 OSSharedPtr<OSNumber> portNameNumber;
9143 mach_port_name_t portName = 0;
9144 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9145 if (!request) {
9146 OSKextLog(/* kext */ NULL,
9147 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9148 "Elements of request should be of type OSDictionary");
9149 result = kOSKextReturnInternalError;
9150 goto finish;
9151 }
9152 requestPredicate = _OSKextGetRequestPredicate(request);
9153 if (!requestPredicate) {
9154 OSKextLog(/* kext */ NULL,
9155 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9156 "Failed to get request predicate");
9157 result = kOSKextReturnInternalError;
9158 goto finish;
9159 }
9160 // is this a dext launch?
9161 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9162 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9163 if (!token) {
9164 OSKextLog(/* kext */ NULL,
9165 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9166 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9167 result = kOSKextReturnInternalError;
9168 goto finish;
9169 }
9170 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9171 if (portName == 0 || portName == MACH_PORT_DEAD) {
9172 OSKextLog(/* kext */ NULL,
9173 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9174 "Could not create send right for object.");
9175 result = kOSKextReturnInternalError;
9176 goto finish;
9177 }
9178 // Store the mach port name as a OSNumber
9179 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9180 if (!portNameNumber) {
9181 OSKextLog(/* kext */ NULL,
9182 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9183 "Could not create OSNumber object.");
9184 result = kOSKextReturnNoMemory;
9185 goto finish;
9186 }
9187 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9188 OSKextLog(/* kext */ NULL,
9189 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9190 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9191 result = kOSKextReturnNoMemory;
9192 goto finish;
9193 }
9194 }
9195 finish:
9196 if (result != kOSReturnSuccess) {
9197 break;
9198 }
9199 }
9200 return result;
9201 }
9202
9203 /*********************************************************************
9204 * XXX - this function is a big ugly mess
9205 *********************************************************************/
9206 /* static */
9207 OSReturn
9208 OSKext::handleRequest(
9209 host_priv_t hostPriv,
9210 OSKextLogSpec clientLogFilter,
9211 char * requestBuffer,
9212 uint32_t requestLength,
9213 char ** responseOut,
9214 uint32_t * responseLengthOut,
9215 char ** logInfoOut,
9216 uint32_t * logInfoLengthOut)
9217 {
9218 OSReturn result = kOSReturnError;
9219 kern_return_t kmem_result = KERN_FAILURE;
9220
9221 char * response = NULL; // returned by reference
9222 uint32_t responseLength = 0;
9223
9224 bool taskCanManageAllKCs = false;
9225 bool taskOnlyManagesBootKC = false;
9226
9227 OSSharedPtr<OSObject> parsedXML;
9228 OSDictionary * requestDict = NULL; // do not release
9229 OSSharedPtr<OSString> errorString;
9230
9231 OSSharedPtr<OSObject> responseObject;
9232
9233 OSSharedPtr<OSSerialize> serializer;
9234
9235 OSSharedPtr<OSArray> logInfoArray;
9236
9237 OSString * predicate = NULL; // do not release
9238 OSString * kextIdentifier = NULL; // do not release
9239 OSArray * kextIdentifiers = NULL; // do not release
9240 OSKext * theKext = NULL; // do not release
9241 OSBoolean * boolArg = NULL; // do not release
9242
9243 IORecursiveLockLock(sKextLock);
9244
9245 if (responseOut) {
9246 *responseOut = NULL;
9247 *responseLengthOut = 0;
9248 }
9249 if (logInfoOut) {
9250 *logInfoOut = NULL;
9251 *logInfoLengthOut = 0;
9252 }
9253
9254 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9255
9256 /* XML must be nul-terminated.
9257 */
9258 if (requestBuffer[requestLength - 1] != '\0') {
9259 OSKextLog(/* kext */ NULL,
9260 kOSKextLogErrorLevel |
9261 kOSKextLogIPCFlag,
9262 "Invalid request from user space (not nul-terminated).");
9263 result = kOSKextReturnBadData;
9264 goto finish;
9265 }
9266 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
9267 if (parsedXML) {
9268 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
9269 }
9270 if (!requestDict) {
9271 const char * errorCString = "(unknown error)";
9272
9273 if (errorString && errorString->getCStringNoCopy()) {
9274 errorCString = errorString->getCStringNoCopy();
9275 } else if (parsedXML) {
9276 errorCString = "not a dictionary";
9277 }
9278 OSKextLog(/* kext */ NULL,
9279 kOSKextLogErrorLevel |
9280 kOSKextLogIPCFlag,
9281 "Error unserializing request from user space: %s.",
9282 errorCString);
9283 result = kOSKextReturnSerialization;
9284 goto finish;
9285 }
9286
9287 predicate = _OSKextGetRequestPredicate(requestDict);
9288 if (!predicate) {
9289 OSKextLog(/* kext */ NULL,
9290 kOSKextLogErrorLevel |
9291 kOSKextLogIPCFlag,
9292 "Recieved kext request from user space with no predicate.");
9293 result = kOSKextReturnInvalidArgument;
9294 goto finish;
9295 }
9296
9297 OSKextLog(/* kext */ NULL,
9298 kOSKextLogDebugLevel |
9299 kOSKextLogIPCFlag,
9300 "Received '%s' request from user space.",
9301 predicate->getCStringNoCopy());
9302
9303 /*
9304 * All management of file sets requires an entitlement
9305 */
9306 result = kOSKextReturnNotPrivileged;
9307 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9308 predicate->isEqualTo(kKextRequestPredicateStart) ||
9309 predicate->isEqualTo(kKextRequestPredicateStop) ||
9310 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9311 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9312 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9313 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9314 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9315 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9316 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9317 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9318 if (hostPriv == HOST_PRIV_NULL) {
9319 OSKextLog(/* kext */ NULL,
9320 kOSKextLogErrorLevel |
9321 kOSKextLogIPCFlag,
9322 "Access Failure - must be root user.");
9323 goto finish;
9324 }
9325 taskCanManageAllKCs = IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement) == TRUE;
9326 taskOnlyManagesBootKC = IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9327
9328 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9329 OSKextLog(/* kext */ NULL,
9330 kOSKextLogErrorLevel |
9331 kOSKextLogIPCFlag,
9332 "Access Failure - client not entitled to manage file sets.");
9333 goto finish;
9334 }
9335
9336 /*
9337 * The OnlyBootKC entitlement restricts the
9338 * collection-management entitlement to only managing kexts in
9339 * the BootKC. All other predicates that alter global state or
9340 * add new KCs are disallowed.
9341 */
9342 if (taskOnlyManagesBootKC &&
9343 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9344 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9345 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9346 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9347 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9348 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9349 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9350 OSKextLog(/* kext */ NULL,
9351 kOSKextLogErrorLevel |
9352 kOSKextLogIPCFlag,
9353 "Access Failure - client not entitled to manage non-primary KCs");
9354 goto finish;
9355 }
9356
9357 /*
9358 * If we get here, then the process either has the full KC
9359 * management entitlement, or it has the BootKC-only
9360 * entitlement and the request is about the BootKC.
9361 */
9362 }
9363
9364 /* Get common args in anticipation of use.
9365 */
9366 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9367 requestDict, kKextRequestArgumentBundleIdentifierKey));
9368 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9369 requestDict, kKextRequestArgumentBundleIdentifierKey));
9370 if (kextIdentifier) {
9371 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9372 }
9373 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9374 requestDict, kKextRequestArgumentValueKey));
9375
9376 if (taskOnlyManagesBootKC &&
9377 theKext &&
9378 theKext->isInFileset() &&
9379 theKext->kc_type != KCKindPrimary) {
9380 OSKextLog(/* kext */ NULL,
9381 kOSKextLogErrorLevel |
9382 kOSKextLogIPCFlag,
9383 "Access Failure - client not entitled to manage kext in non-primary KC");
9384 result = kOSKextReturnNotPrivileged;
9385 goto finish;
9386 }
9387
9388 result = kOSKextReturnInvalidArgument;
9389
9390 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9391 if (!kextIdentifier) {
9392 OSKextLog(/* kext */ NULL,
9393 kOSKextLogErrorLevel |
9394 kOSKextLogIPCFlag,
9395 "Invalid arguments to kext start request.");
9396 } else if (!theKext) {
9397 OSKextLog(/* kext */ NULL,
9398 kOSKextLogErrorLevel |
9399 kOSKextLogIPCFlag,
9400 "Kext %s not found for start request.",
9401 kextIdentifier->getCStringNoCopy());
9402 result = kOSKextReturnNotFound;
9403 } else {
9404 result = theKext->start();
9405 }
9406 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9407 if (!kextIdentifier) {
9408 OSKextLog(/* kext */ NULL,
9409 kOSKextLogErrorLevel |
9410 kOSKextLogIPCFlag,
9411 "Invalid arguments to kext stop request.");
9412 } else if (!theKext) {
9413 OSKextLog(/* kext */ NULL,
9414 kOSKextLogErrorLevel |
9415 kOSKextLogIPCFlag,
9416 "Kext %s not found for stop request.",
9417 kextIdentifier->getCStringNoCopy());
9418 result = kOSKextReturnNotFound;
9419 } else {
9420 result = theKext->stop();
9421 }
9422 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9423 result = OSKext::setMissingAuxKCBundles(requestDict);
9424 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9425 if (!kextIdentifier) {
9426 OSKextLog(/* kext */ NULL,
9427 kOSKextLogErrorLevel |
9428 kOSKextLogIPCFlag,
9429 "Invalid arguments to AuxKC Bundle Available request.");
9430 } else {
9431 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9432 }
9433 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9434 if (!kextIdentifier) {
9435 OSKextLog(/* kext */ NULL,
9436 kOSKextLogErrorLevel |
9437 kOSKextLogIPCFlag,
9438 "Invalid arguments to kext load from KC request.");
9439 } else if (!theKext) {
9440 OSKextLog(/* kext */ NULL,
9441 kOSKextLogErrorLevel |
9442 kOSKextLogIPCFlag,
9443 "Kext %s not found for load from KC request.",
9444 kextIdentifier->getCStringNoCopy());
9445 result = kOSKextReturnNotFound;
9446 } else if (!theKext->isInFileset()) {
9447 OSKextLog(/* kext */ NULL,
9448 kOSKextLogErrorLevel |
9449 kOSKextLogIPCFlag,
9450 "Kext %s does not exist in a KC: refusing to load.",
9451 kextIdentifier->getCStringNoCopy());
9452 result = kOSKextReturnNotLoadable;
9453 } else {
9454 result = OSKext::loadKextFromKC(theKext, requestDict);
9455 }
9456 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9457 if (!kextIdentifier) {
9458 OSKextLog(/* kext */ NULL,
9459 kOSKextLogErrorLevel |
9460 kOSKextLogIPCFlag,
9461 "Invalid arguments to codeless kext load interface (missing identifier).");
9462 } else {
9463 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9464 }
9465 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9466 if (!kextIdentifier) {
9467 OSKextLog(/* kext */ NULL,
9468 kOSKextLogErrorLevel |
9469 kOSKextLogIPCFlag,
9470 "Invalid arguments to kext unload request.");
9471 } else if (!theKext) {
9472 OSKextLog(/* kext */ NULL,
9473 kOSKextLogErrorLevel |
9474 kOSKextLogIPCFlag,
9475 "Kext %s not found for unload request.",
9476 kextIdentifier->getCStringNoCopy());
9477 result = kOSKextReturnNotFound;
9478 } else {
9479 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9480 _OSKextGetRequestArgument(requestDict,
9481 kKextRequestArgumentTerminateIOServicesKey));
9482 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9483 }
9484 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9485 result = OSKext::dispatchResource(requestDict);
9486 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9487 OSNumber *lookupNum = NULL;
9488 lookupNum = OSDynamicCast(OSNumber,
9489 _OSKextGetRequestArgument(requestDict,
9490 kKextRequestArgumentLookupAddressKey));
9491
9492 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9493 if (responseObject) {
9494 result = kOSReturnSuccess;
9495 } else {
9496 goto finish;
9497 }
9498 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
9499 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9500 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9501 OSBoolean * delayAutounloadBool = NULL;
9502 OSObject * infoKeysRaw = NULL;
9503 OSArray * infoKeys = NULL;
9504 uint32_t infoKeysCount = 0;
9505
9506 delayAutounloadBool = OSDynamicCast(OSBoolean,
9507 _OSKextGetRequestArgument(requestDict,
9508 kKextRequestArgumentDelayAutounloadKey));
9509
9510 /* If asked to delay autounload, reset the timer if it's currently set.
9511 * (That is, don't schedule an unload if one isn't already pending.
9512 */
9513 if (delayAutounloadBool == kOSBooleanTrue) {
9514 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9515 }
9516
9517 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9518 kKextRequestArgumentInfoKeysKey);
9519 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9520 if (infoKeysRaw && !infoKeys) {
9521 OSKextLog(/* kext */ NULL,
9522 kOSKextLogErrorLevel |
9523 kOSKextLogIPCFlag,
9524 "Invalid arguments to kext info request.");
9525 goto finish;
9526 }
9527
9528 if (infoKeys) {
9529 infoKeysCount = infoKeys->getCount();
9530 for (uint32_t i = 0; i < infoKeysCount; i++) {
9531 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9532 OSKextLog(/* kext */ NULL,
9533 kOSKextLogErrorLevel |
9534 kOSKextLogIPCFlag,
9535 "Invalid arguments to kext info request.");
9536 goto finish;
9537 }
9538 }
9539 }
9540
9541 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9542 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9543 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9544 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
9545 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9546 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
9547 }
9548
9549 if (!responseObject) {
9550 result = kOSKextReturnInternalError;
9551 } else {
9552 OSKextLog(/* kext */ NULL,
9553 kOSKextLogDebugLevel |
9554 kOSKextLogIPCFlag,
9555 "Returning loaded kext info.");
9556 result = kOSReturnSuccess;
9557 }
9558 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9559 /* Hand the current sKernelRequests array to the caller
9560 * (who must release it), and make a new one.
9561 */
9562 responseObject = os::move(sKernelRequests);
9563 sKernelRequests = OSArray::withCapacity(0);
9564 sPostedKextLoadIdentifiers->flushCollection();
9565 OSKextLog(/* kext */ NULL,
9566 kOSKextLogDebugLevel |
9567 kOSKextLogIPCFlag,
9568 "Returning kernel requests.");
9569 result = kOSReturnSuccess;
9570 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9571 /* Return the set of all requested bundle identifiers */
9572 responseObject = sAllKextLoadIdentifiers;
9573 OSKextLog(/* kext */ NULL,
9574 kOSKextLogDebugLevel |
9575 kOSKextLogIPCFlag,
9576 "Returning load requests.");
9577 result = kOSReturnSuccess;
9578 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9579 printf("KextLog: Loading FileSet KC(s)\n");
9580 result = OSKext::loadFileSetKexts(requestDict);
9581 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9582 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9583 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
9584 } else {
9585 OSKextLog(/* kext */ NULL,
9586 kOSKextLogDebugLevel |
9587 kOSKextLogIPCFlag,
9588 "Received '%s' invalid request from user space.",
9589 predicate->getCStringNoCopy());
9590 goto finish;
9591 }
9592
9593 /**********
9594 * Now we have handle the request, or not. Gather up the response & logging
9595 * info to ship to user space.
9596 *********/
9597
9598 /* Note: Nothing in OSKext is supposed to retain requestDict,
9599 * but you never know....
9600 */
9601 if (requestDict->getRetainCount() > 1) {
9602 OSKextLog(/* kext */ NULL,
9603 kOSKextLogWarningLevel |
9604 kOSKextLogIPCFlag,
9605 "Request from user space still retained by a kext; "
9606 "probable memory leak.");
9607 }
9608
9609 if (responseOut && responseObject) {
9610 serializer = OSSerialize::withCapacity(0);
9611 if (!serializer) {
9612 result = kOSKextReturnNoMemory;
9613 goto finish;
9614 }
9615 /*
9616 * Before serializing the kernel requests, patch the dext launch requests so
9617 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9618 * IOUserServerCheckInToken kernel object.
9619 */
9620 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9621 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9622 task_t calling_task = current_task();
9623 if (!requests) {
9624 OSKextLog(/* kext */ NULL,
9625 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9626 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9627 result = kOSKextReturnInternalError;
9628 goto finish;
9629 }
9630 result = patchDextLaunchRequests(calling_task, requests);
9631 if (result != kOSReturnSuccess) {
9632 OSKextLog(/* kext */ NULL,
9633 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9634 "Failed to patch dext launch requests.");
9635 goto finish;
9636 }
9637 }
9638
9639 if (!responseObject->serialize(serializer.get())) {
9640 OSKextLog(/* kext */ NULL,
9641 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9642 "Failed to serialize response to request from user space.");
9643 result = kOSKextReturnSerialization;
9644 goto finish;
9645 }
9646
9647 response = (char *)serializer->text();
9648 responseLength = serializer->getLength();
9649 }
9650
9651 if (responseOut && response) {
9652 char * buffer;
9653
9654 /* This kmem_alloc sets the return value of the function.
9655 */
9656 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9657 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
9658 if (kmem_result != KERN_SUCCESS) {
9659 OSKextLog(/* kext */ NULL,
9660 kOSKextLogErrorLevel |
9661 kOSKextLogIPCFlag,
9662 "Failed to copy response to request from user space.");
9663 result = kmem_result;
9664 goto finish;
9665 } else {
9666 /* 11981737 - clear uninitialized data in last page */
9667 bzero((void *)(buffer + responseLength),
9668 (round_page(responseLength) - responseLength));
9669 memcpy(buffer, response, responseLength);
9670 *responseOut = buffer;
9671 *responseLengthOut = responseLength;
9672 }
9673 }
9674
9675 finish:
9676
9677 /* Gather up the collected log messages for user space. Any messages
9678 * messages past this call will not make it up as log messages but
9679 * will be in the system log. Note that we ignore the return of the
9680 * serialize; it has no bearing on the operation at hand even if we
9681 * fail to get the log messages.
9682 */
9683 logInfoArray = OSKext::clearUserSpaceLogFilter();
9684
9685 if (logInfoArray && logInfoOut && logInfoLengthOut) {
9686 (void)OSKext::serializeLogInfo(logInfoArray.get(),
9687 logInfoOut, logInfoLengthOut);
9688 }
9689
9690 IORecursiveLockUnlock(sKextLock);
9691
9692 return result;
9693 }
9694
9695 #if PRAGMA_MARK
9696 #pragma mark Linked Kext Collection Support
9697 #endif
9698
9699 static int
9700 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9701 {
9702 for (int i = 0; i < segCount; i++) {
9703 vm_offset_t segStart = segAddrs[i];
9704 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9705
9706 if (theAddr >= segStart && theAddr < segEnd) {
9707 return i;
9708 }
9709 }
9710 return -1;
9711 }
9712
9713 static void
9714 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
9715 kernel_segment_command_t *kextTextSeg,
9716 OSData *kaslrOffsets)
9717 {
9718 static const char *plk_segNames[] = {
9719 "__TEXT",
9720 "__TEXT_EXEC",
9721 "__DATA",
9722 "__DATA_CONST",
9723 "__LINKEDIT",
9724 "__PRELINK_TEXT",
9725 "__PLK_TEXT_EXEC",
9726 "__PRELINK_DATA",
9727 "__PLK_DATA_CONST",
9728 "__PLK_LLVM_COV",
9729 "__PLK_LINKEDIT",
9730 "__PRELINK_INFO"
9731 };
9732 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9733
9734 unsigned long plk_segSizes[num_plk_seg];
9735 vm_offset_t plk_segAddrs[num_plk_seg];
9736
9737 for (size_t i = 0; i < num_plk_seg; i++) {
9738 plk_segSizes[i] = 0;
9739 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9740 }
9741
9742 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9743
9744 int slidKextAddrCount = 0;
9745 int badSlideAddr = 0;
9746 int badSlideTarget = 0;
9747
9748 struct kaslrPackedOffsets {
9749 uint32_t count; /* number of offsets */
9750 uint32_t offsetsArray[]; /* offsets to slide */
9751 };
9752 const struct kaslrPackedOffsets *myOffsets = NULL;
9753 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9754
9755 for (uint32_t j = 0; j < myOffsets->count; j++) {
9756 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9757 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9758 int slideAddrSegIndex = -1;
9759 int addrToSlideSegIndex = -1;
9760
9761 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9762 if (slideAddrSegIndex >= 0) {
9763 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9764 if (addrToSlideSegIndex < 0) {
9765 badSlideTarget++;
9766 continue;
9767 }
9768 } else {
9769 badSlideAddr++;
9770 continue;
9771 }
9772
9773 slidKextAddrCount++;
9774 *slideAddr = ml_static_slide(*slideAddr);
9775 } // for ...
9776 }
9777
9778
9779
9780 /********************************************************************
9781 * addKextsFromKextCollection
9782 *
9783 * Input: MachO header of kext collection. The MachO is assumed to
9784 * have a section named 'info_seg_name,info_sect_name' that
9785 * contains a serialized XML info dictionary. This dictionary
9786 * contains a UUID, possibly a set of relocations (for older
9787 * kxld-built binaries), and an array of kext personalities.
9788 *
9789 ********************************************************************/
9790 bool
9791 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9792 OSDictionary *infoDict, const char *text_seg_name,
9793 OSData **kcUUID, kc_kind_t type)
9794 {
9795 bool result = false;
9796
9797 OSArray *kextArray = NULL; // do not release
9798 OSData *infoDictKCUUID = NULL; // do not release
9799 OSData *kaslrOffsets = NULL; // do not release
9800
9801 IORegistryEntry *registryRoot = NULL; // do not release
9802 OSSharedPtr<OSNumber> kcKextCount;
9803
9804 /* extract the KC UUID from the dictionary */
9805 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9806 if (infoDictKCUUID) {
9807 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9808 panic("kcUUID length is %d, expected %lu",
9809 infoDictKCUUID->getLength(), sizeof(uuid_t));
9810 }
9811 }
9812
9813 /* locate the array of kext dictionaries */
9814 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9815 if (!kextArray) {
9816 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9817 "The given KC has no kext info dictionaries");
9818 goto finish;
9819 }
9820
9821 /*
9822 * old-style KASLR offsets may be present in the info dictionary. If
9823 * we find them, use them and eventually slide them.
9824 */
9825 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9826
9827 /*
9828 * Before processing any kexts, locate the special kext bundle which
9829 * contains a list of kexts that we are to prevent from loading.
9830 */
9831 createExcludeListFromPrelinkInfo(kextArray);
9832
9833 /*
9834 * Create OSKext objects for each kext we find in the array of kext
9835 * info plist dictionaries.
9836 */
9837 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9838 OSDictionary *kextDict = NULL;
9839 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9840 if (!kextDict) {
9841 OSKextLog(/* kext */ NULL,
9842 kOSKextLogErrorLevel |
9843 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9844 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9845 continue;
9846 }
9847
9848 /*
9849 * Create the kext for the entry, then release it, because the
9850 * kext system keeps a reference around until the kext is
9851 * explicitly removed. Any creation/registration failures are
9852 * already logged for us.
9853 */
9854 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9855 }
9856
9857 /*
9858 * slide old-style kxld relocations
9859 * NOTE: this is still used on embedded KCs built with kcgen
9860 * TODO: Remove this once we use the new kext linker everywhere!
9861 */
9862 if (kaslrOffsets && vm_kernel_slide > 0) {
9863 kernel_segment_command_t *text_segment = NULL;
9864 text_segment = getsegbynamefromheader(mh, text_seg_name);
9865 if (!text_segment) {
9866 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9867 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9868 goto finish;
9869 }
9870
9871 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9872 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9873 setAllVMAttributes();
9874 }
9875
9876 /* Store the number of prelinked kexts in the registry so we can tell
9877 * when the system has been started from a prelinked kernel.
9878 */
9879 registryRoot = IORegistryEntry::getRegistryRoot();
9880 assert(registryRoot);
9881
9882 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
9883 assert(kcKextCount);
9884 if (kcKextCount) {
9885 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
9886 OSNumber *num;
9887 num = OSDynamicCast(OSNumber, prop.get());
9888 if (num) {
9889 kcKextCount->addValue(num->unsigned64BitValue());
9890 }
9891 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
9892 }
9893
9894 OSKextLog(/* kext */ NULL,
9895 kOSKextLogProgressLevel |
9896 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
9897 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9898 "%u prelinked kexts", infoDict->getCount());
9899
9900
9901 if (kcUUID && infoDictKCUUID) {
9902 *kcUUID = OSData::withData(infoDictKCUUID).detach();
9903 }
9904
9905 result = true;
9906
9907 finish:
9908 return result;
9909 }
9910
9911 bool
9912 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9913 OSDictionary *infoDict, const char *text_seg_name,
9914 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
9915 {
9916 OSData *result = NULL;
9917 bool success = addKextsFromKextCollection(mh,
9918 infoDict,
9919 text_seg_name,
9920 &result,
9921 type);
9922 if (success) {
9923 kcUUID.reset(result, OSNoRetain);
9924 }
9925 return success;
9926 }
9927
9928 static OSSharedPtr<OSObject> deferredAuxKCXML;
9929 bool
9930 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
9931 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
9932 {
9933 if (type != KCKindAuxiliary) {
9934 return false;
9935 }
9936
9937 kernel_mach_header_t *_mh;
9938 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
9939 if (!_mh || _mh != mh) {
9940 return false;
9941 }
9942
9943 if (deferredAuxKCXML) {
9944 /* only allow this to be called once */
9945 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9946 "An Aux KC has already been registered for deferred processing.");
9947 return false;
9948 }
9949
9950 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
9951 if (!infoDict) {
9952 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9953 "The Aux KC has info dictionary");
9954 return false;
9955 }
9956
9957 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9958 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
9959 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9960 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
9961 return false;
9962 }
9963
9964 /*
9965 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
9966 * sysctl can return the UUID to user space which will check this
9967 * value for errors.
9968 */
9969 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
9970 kcUUID->getLength());
9971 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
9972 auxkc_uuid_valid = TRUE;
9973
9974 deferredAuxKCXML = parsedXML;
9975
9976 return true;
9977 }
9978
9979 OSSharedPtr<OSObject>
9980 OSKext::consumeDeferredKextCollection(kc_kind_t type)
9981 {
9982 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
9983 return NULL;
9984 }
9985
9986 return os::move(deferredAuxKCXML);
9987 }
9988
9989 #if PRAGMA_MARK
9990 #pragma mark Profile-Guided-Optimization Support
9991 #endif
9992
9993 // #include <InstrProfiling.h>
9994 extern "C" {
9995 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
9996 const char *DataEnd,
9997 const char *CountersBegin,
9998 const char *CountersEnd,
9999 const char *NamesBegin,
10000 const char *NamesEnd);
10001 int __llvm_profile_write_buffer_internal(char *Buffer,
10002 const char *DataBegin,
10003 const char *DataEnd,
10004 const char *CountersBegin,
10005 const char *CountersEnd,
10006 const char *NamesBegin,
10007 const char *NamesEnd);
10008 }
10009
10010
10011 static
10012 void
10013 OSKextPgoMetadataPut(char *pBuffer,
10014 size_t *position,
10015 size_t bufferSize,
10016 uint32_t *num_pairs,
10017 const char *key,
10018 const char *value)
10019 {
10020 size_t strlen_key = strlen(key);
10021 size_t strlen_value = strlen(value);
10022 size_t len = strlen(key) + 1 + strlen(value) + 1;
10023 char *pos = pBuffer + *position;
10024 *position += len;
10025 if (pBuffer && bufferSize && *position <= bufferSize) {
10026 memcpy(pos, key, strlen_key); pos += strlen_key;
10027 *(pos++) = '=';
10028 memcpy(pos, value, strlen_value); pos += strlen_value;
10029 *(pos++) = 0;
10030 if (num_pairs) {
10031 (*num_pairs)++;
10032 }
10033 }
10034 }
10035
10036
10037 static
10038 void
10039 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10040 {
10041 *position += strlen(key) + 1 + value_max + 1;
10042 }
10043
10044
10045 static
10046 void
10047 OSKextPgoMetadataPutAll(OSKext *kext,
10048 uuid_t instance_uuid,
10049 char *pBuffer,
10050 size_t *position,
10051 size_t bufferSize,
10052 uint32_t *num_pairs)
10053 {
10054 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10055 //log_10 2^16 ≈ 4.82
10056 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10057 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10058
10059 if (!pBuffer) {
10060 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10061 OSKextPgoMetadataPutMax(position, "UUID", 36);
10062 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10063 } else {
10064 uuid_string_t instance_uuid_string;
10065 uuid_unparse(instance_uuid, instance_uuid_string);
10066 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10067 "INSTANCE", instance_uuid_string);
10068
10069 OSSharedPtr<OSData> uuid_data;
10070 uuid_t uuid;
10071 uuid_string_t uuid_string;
10072 uuid_data = kext->copyUUID();
10073 if (uuid_data) {
10074 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10075 uuid_unparse(uuid, uuid_string);
10076 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10077 "UUID", uuid_string);
10078 }
10079
10080 clock_sec_t secs;
10081 clock_usec_t usecs;
10082 clock_get_calendar_microtime(&secs, &usecs);
10083 assert(usecs < 1000000);
10084 char timestamp[max_timestamp_string_size + 1];
10085 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10086 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10087 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10088 "TIMESTAMP", timestamp);
10089 }
10090
10091 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10092 "NAME", kext->getIdentifierCString());
10093
10094 char versionCString[kOSKextVersionMaxLength];
10095 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10096 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10097 "VERSION", versionCString);
10098 }
10099
10100 static
10101 size_t
10102 OSKextPgoMetadataSize(OSKext *kext)
10103 {
10104 size_t position = 0;
10105 uuid_t fakeuuid = {};
10106 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10107 return position;
10108 }
10109
10110 int
10111 OSKextGrabPgoDataLocked(OSKext *kext,
10112 bool metadata,
10113 uuid_t instance_uuid,
10114 uint64_t *pSize,
10115 char *pBuffer,
10116 uint64_t bufferSize)
10117 {
10118 int err = 0;
10119
10120 kernel_section_t *sect_prf_data = NULL;
10121 kernel_section_t *sect_prf_name = NULL;
10122 kernel_section_t *sect_prf_cnts = NULL;
10123 uint64_t size;
10124 size_t metadata_size = 0;
10125 size_t offset_to_pairs = 0;
10126
10127 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10128 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10129 if (!sect_prf_name) {
10130 // kextcache sometimes truncates the section name to 15 chars
10131 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10132 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10133 }
10134 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10135
10136 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10137 err = ENOTSUP;
10138 goto out;
10139 }
10140
10141 size = __llvm_profile_get_size_for_buffer_internal(
10142 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10143 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10144 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10145
10146 if (metadata) {
10147 metadata_size = OSKextPgoMetadataSize(kext);
10148 size += metadata_size;
10149 size += sizeof(pgo_metadata_footer);
10150 }
10151
10152
10153 if (pSize) {
10154 *pSize = size;
10155 }
10156
10157 if (pBuffer && bufferSize) {
10158 if (bufferSize < size) {
10159 err = ERANGE;
10160 goto out;
10161 }
10162
10163 err = __llvm_profile_write_buffer_internal(
10164 pBuffer,
10165 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10166 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10167 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10168
10169 if (err) {
10170 err = EIO;
10171 goto out;
10172 }
10173
10174 if (metadata) {
10175 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10176 if (offset_to_pairs > UINT32_MAX) {
10177 err = E2BIG;
10178 goto out;
10179 }
10180
10181 char *end_of_buffer = pBuffer + size;
10182 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10183 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10184
10185 size_t metadata_position = 0;
10186 uint32_t num_pairs = 0;
10187 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10188 while (metadata_position < metadata_size) {
10189 metadata_buffer[metadata_position++] = 0;
10190 }
10191
10192 struct pgo_metadata_footer footer;
10193 footer.magic = htonl(0x6d657461);
10194 footer.number_of_pairs = htonl( num_pairs );
10195 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
10196 memcpy(footerp, &footer, sizeof(footer));
10197 }
10198 }
10199
10200 out:
10201 return err;
10202 }
10203
10204
10205 int
10206 OSKextGrabPgoData(uuid_t uuid,
10207 uint64_t *pSize,
10208 char *pBuffer,
10209 uint64_t bufferSize,
10210 int wait_for_unload,
10211 int metadata)
10212 {
10213 int err = 0;
10214 OSSharedPtr<OSKext> kext;
10215
10216
10217 IORecursiveLockLock(sKextLock);
10218
10219 kext = OSKext::lookupKextWithUUID(uuid);
10220 if (!kext) {
10221 err = ENOENT;
10222 goto out;
10223 }
10224
10225 if (wait_for_unload) {
10226 OSKextGrabPgoStruct s;
10227
10228 s.metadata = metadata;
10229 s.pSize = pSize;
10230 s.pBuffer = pBuffer;
10231 s.bufferSize = bufferSize;
10232 s.err = EINTR;
10233
10234 struct list_head *prev = &kext->pendingPgoHead;
10235 struct list_head *next = kext->pendingPgoHead.next;
10236
10237 s.list_head.prev = prev;
10238 s.list_head.next = next;
10239
10240 prev->next = &s.list_head;
10241 next->prev = &s.list_head;
10242
10243 kext.reset();
10244
10245 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
10246
10247 prev = s.list_head.prev;
10248 next = s.list_head.next;
10249
10250 prev->next = next;
10251 next->prev = prev;
10252
10253 err = s.err;
10254 } else {
10255 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
10256 }
10257
10258 out:
10259
10260 IORecursiveLockUnlock(sKextLock);
10261
10262 return err;
10263 }
10264
10265 void
10266 OSKextResetPgoCountersLock()
10267 {
10268 IORecursiveLockLock(sKextLock);
10269 }
10270
10271 void
10272 OSKextResetPgoCountersUnlock()
10273 {
10274 IORecursiveLockUnlock(sKextLock);
10275 }
10276
10277
10278 extern unsigned int not_in_kdp;
10279
10280 void
10281 OSKextResetPgoCounters()
10282 {
10283 assert(!not_in_kdp);
10284 uint32_t count = sLoadedKexts->getCount();
10285 for (uint32_t i = 0; i < count; i++) {
10286 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10287 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10288 if (!sect_prf_cnts) {
10289 continue;
10290 }
10291 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10292 }
10293 }
10294
10295 OSSharedPtr<OSDictionary>
10296 OSKext::copyLoadedKextInfoByUUID(
10297 OSArray * kextIdentifiers,
10298 OSArray * infoKeys)
10299 {
10300 OSSharedPtr<OSDictionary> result;
10301 OSSharedPtr<OSDictionary> kextInfo;
10302 uint32_t max_count, i, j;
10303 uint32_t idCount = 0;
10304 uint32_t idIndex = 0;
10305 IORecursiveLockLock(sKextLock);
10306 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
10307 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
10308
10309 #if CONFIG_MACF
10310 /* Is the calling process allowed to query kext info? */
10311 if (current_task() != kernel_task) {
10312 int macCheckResult = 0;
10313 kauth_cred_t cred = NULL;
10314
10315 cred = kauth_cred_get_with_ref();
10316 macCheckResult = mac_kext_check_query(cred);
10317 kauth_cred_unref(&cred);
10318
10319 if (macCheckResult != 0) {
10320 OSKextLog(/* kext */ NULL,
10321 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10322 "Failed to query kext info (MAC policy error 0x%x).",
10323 macCheckResult);
10324 goto finish;
10325 }
10326 }
10327 #endif
10328
10329 /* Empty list of UUIDs is equivalent to no list (get all).
10330 */
10331 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10332 kextIdentifiers = NULL;
10333 } else if (kextIdentifiers) {
10334 idCount = kextIdentifiers->getCount();
10335 }
10336
10337 /* Same for keys.
10338 */
10339 if (infoKeys && !infoKeys->getCount()) {
10340 infoKeys = NULL;
10341 }
10342
10343 max_count = count[0] + count[1];
10344 result = OSDictionary::withCapacity(max_count);
10345 if (!result) {
10346 goto finish;
10347 }
10348
10349 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10350 for (i = 0; i < count[j]; i++) {
10351 OSKext *thisKext = NULL; // do not release
10352 Boolean includeThis = true;
10353 uuid_t thisKextUUID;
10354 uuid_t thisKextTextUUID;
10355 OSSharedPtr<OSData> uuid_data;
10356 uuid_string_t uuid_key;
10357
10358 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10359 if (!thisKext) {
10360 continue;
10361 }
10362
10363 uuid_data = thisKext->copyUUID();
10364 if (!uuid_data) {
10365 continue;
10366 }
10367
10368 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
10369
10370 uuid_unparse(thisKextUUID, uuid_key);
10371
10372 uuid_data = thisKext->copyTextUUID();
10373 if (!uuid_data) {
10374 continue;
10375 }
10376 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
10377
10378 /* Skip current kext if we have a list of UUIDs and
10379 * it isn't in the list.
10380 */
10381 if (kextIdentifiers) {
10382 includeThis = false;
10383
10384 for (idIndex = 0; idIndex < idCount; idIndex++) {
10385 const OSString* wantedUUID = OSDynamicCast(OSString,
10386 kextIdentifiers->getObject(idIndex));
10387
10388 uuid_t uuid;
10389 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10390
10391 if ((0 == uuid_compare(uuid, thisKextUUID))
10392 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10393 includeThis = true;
10394 /* Only need to find the first kext if multiple match,
10395 * ie. asking for the kernel uuid does not need to find
10396 * interface kexts or builtin static kexts.
10397 */
10398 kextIdentifiers->removeObject(idIndex);
10399 uuid_unparse(uuid, uuid_key);
10400 break;
10401 }
10402 }
10403 }
10404
10405 if (!includeThis) {
10406 continue;
10407 }
10408
10409 kextInfo = thisKext->copyInfo(infoKeys);
10410 if (kextInfo) {
10411 result->setObject(uuid_key, kextInfo.get());
10412 }
10413
10414 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10415 goto finish;
10416 }
10417 }
10418 }
10419
10420 finish:
10421 IORecursiveLockUnlock(sKextLock);
10422
10423 return result;
10424 }
10425
10426 /*********************************************************************
10427 *********************************************************************/
10428 /* static */
10429 OSSharedPtr<OSDictionary>
10430 OSKext::copyKextCollectionInfo(
10431 OSDictionary *requestDict,
10432 OSArray *infoKeys)
10433 {
10434 OSSharedPtr<OSDictionary> result;
10435 OSString *collectionType = NULL;
10436 OSObject *rawLoadedState = NULL;
10437 OSString *loadedState = NULL;
10438
10439 kc_kind_t kc_request_kind = KCKindUnknown;
10440 bool onlyLoaded = false;
10441 bool onlyUnloaded = false;
10442
10443 #if CONFIG_MACF
10444 /* Is the calling process allowed to query kext info? */
10445 if (current_task() != kernel_task) {
10446 int macCheckResult = 0;
10447 kauth_cred_t cred = NULL;
10448
10449 cred = kauth_cred_get_with_ref();
10450 macCheckResult = mac_kext_check_query(cred);
10451 kauth_cred_unref(&cred);
10452
10453 if (macCheckResult != 0) {
10454 OSKextLog(/* kext */ NULL,
10455 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10456 "Failed to query kext info (MAC policy error 0x%x).",
10457 macCheckResult);
10458 goto finish;
10459 }
10460 }
10461 #endif
10462
10463 if (infoKeys && !infoKeys->getCount()) {
10464 infoKeys = NULL;
10465 }
10466
10467 collectionType = OSDynamicCast(OSString,
10468 _OSKextGetRequestArgument(requestDict,
10469 kKextRequestArgumentCollectionTypeKey));
10470 if (!collectionType) {
10471 OSKextLog(/* kext */ NULL,
10472 kOSKextLogErrorLevel |
10473 kOSKextLogIPCFlag,
10474 "Invalid '%s' argument to kext collection info request.",
10475 kKextRequestArgumentCollectionTypeKey);
10476 goto finish;
10477 }
10478 if (collectionType->isEqualTo(kKCTypePrimary)) {
10479 kc_request_kind = KCKindPrimary;
10480 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10481 kc_request_kind = KCKindPageable;
10482 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10483 kc_request_kind = KCKindAuxiliary;
10484 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10485 kc_request_kind = KCKindNone;
10486 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10487 OSKextLog(/* kext */ NULL,
10488 kOSKextLogErrorLevel |
10489 kOSKextLogIPCFlag,
10490 "Invalid '%s' argument value '%s' to kext collection info request.",
10491 kKextRequestArgumentCollectionTypeKey,
10492 collectionType->getCStringNoCopy());
10493 goto finish;
10494 }
10495
10496 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10497 kKextRequestArgumentLoadedStateKey);
10498 if (rawLoadedState) {
10499 loadedState = OSDynamicCast(OSString, rawLoadedState);
10500 if (!loadedState) {
10501 OSKextLog(/* kext */ NULL,
10502 kOSKextLogErrorLevel |
10503 kOSKextLogIPCFlag,
10504 "Invalid '%s' argument to kext collection info request.",
10505 kKextRequestArgumentLoadedStateKey);
10506 goto finish;
10507 }
10508 }
10509 if (loadedState) {
10510 if (loadedState->isEqualTo("Loaded")) {
10511 onlyLoaded = true;
10512 } else if (loadedState->isEqualTo("Unloaded")) {
10513 onlyUnloaded = true;
10514 } else if (!loadedState->isEqualTo("Any")) {
10515 OSKextLog(/* kext */ NULL,
10516 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10517 "Invalid '%s' argument value '%s' for '%s' collection info",
10518 kKextRequestArgumentLoadedStateKey,
10519 loadedState->getCStringNoCopy(),
10520 collectionType->getCStringNoCopy());
10521 goto finish;
10522 }
10523 }
10524
10525 result = OSDictionary::withCapacity(sKextsByID->getCount());
10526 if (!result) {
10527 goto finish;
10528 }
10529
10530 IORecursiveLockLock(sKextLock);
10531 { // start block scope
10532 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10533 {
10534 OSKext *thisKext = NULL; // do not release
10535 OSSharedPtr<OSDictionary> kextInfo;
10536
10537 (void)thisKextID;
10538
10539 thisKext = OSDynamicCast(OSKext, obj);
10540 if (!thisKext) {
10541 return false;;
10542 }
10543
10544 /*
10545 * skip the kext if it came from the wrong collection type
10546 * (and the caller requested a specific type)
10547 */
10548 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10549 return false;
10550 }
10551
10552 /*
10553 * respect the caller's desire to find only loaded or
10554 * unloaded kexts
10555 */
10556 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10557 return false;
10558 }
10559 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10560 return false;
10561 }
10562
10563 kextInfo = thisKext->copyInfo(infoKeys);
10564 if (kextInfo) {
10565 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10566 }
10567 return false;
10568 });
10569 } // end block scope
10570 IORecursiveLockUnlock(sKextLock);
10571
10572 finish:
10573 return result;
10574 }
10575
10576 /*********************************************************************
10577 *********************************************************************/
10578 /* static */
10579 OSSharedPtr<OSDictionary>
10580 OSKext::copyLoadedKextInfo(
10581 OSArray * kextIdentifiers,
10582 OSArray * infoKeys)
10583 {
10584 OSSharedPtr<OSDictionary> result;
10585 uint32_t idCount = 0;
10586 bool onlyLoaded;
10587
10588 IORecursiveLockLock(sKextLock);
10589
10590 #if CONFIG_MACF
10591 /* Is the calling process allowed to query kext info? */
10592 if (current_task() != kernel_task) {
10593 int macCheckResult = 0;
10594 kauth_cred_t cred = NULL;
10595
10596 cred = kauth_cred_get_with_ref();
10597 macCheckResult = mac_kext_check_query(cred);
10598 kauth_cred_unref(&cred);
10599
10600 if (macCheckResult != 0) {
10601 OSKextLog(/* kext */ NULL,
10602 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10603 "Failed to query kext info (MAC policy error 0x%x).",
10604 macCheckResult);
10605 goto finish;
10606 }
10607 }
10608 #endif
10609
10610 /* Empty list of bundle ids is equivalent to no list (get all).
10611 */
10612 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10613 kextIdentifiers = NULL;
10614 } else if (kextIdentifiers) {
10615 idCount = kextIdentifiers->getCount();
10616 }
10617
10618 /* Same for keys.
10619 */
10620 if (infoKeys && !infoKeys->getCount()) {
10621 infoKeys = NULL;
10622 }
10623
10624 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10625
10626 result = OSDictionary::withCapacity(128);
10627 if (!result) {
10628 goto finish;
10629 }
10630
10631 #if 0
10632 OSKextLog(/* kext */ NULL,
10633 kOSKextLogErrorLevel |
10634 kOSKextLogGeneralFlag,
10635 "kaslr: vm_kernel_slide 0x%lx \n",
10636 vm_kernel_slide);
10637 OSKextLog(/* kext */ NULL,
10638 kOSKextLogErrorLevel |
10639 kOSKextLogGeneralFlag,
10640 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10641 vm_kernel_stext, vm_kernel_etext);
10642 OSKextLog(/* kext */ NULL,
10643 kOSKextLogErrorLevel |
10644 kOSKextLogGeneralFlag,
10645 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10646 vm_kernel_base, vm_kernel_top);
10647 OSKextLog(/* kext */ NULL,
10648 kOSKextLogErrorLevel |
10649 kOSKextLogGeneralFlag,
10650 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10651 vm_kext_base, vm_kext_top);
10652 OSKextLog(/* kext */ NULL,
10653 kOSKextLogErrorLevel |
10654 kOSKextLogGeneralFlag,
10655 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10656 vm_prelink_stext, vm_prelink_etext);
10657 OSKextLog(/* kext */ NULL,
10658 kOSKextLogErrorLevel |
10659 kOSKextLogGeneralFlag,
10660 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10661 vm_prelink_sinfo, vm_prelink_einfo);
10662 OSKextLog(/* kext */ NULL,
10663 kOSKextLogErrorLevel |
10664 kOSKextLogGeneralFlag,
10665 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10666 vm_slinkedit, vm_elinkedit);
10667 #endif
10668 { // start block scope
10669 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10670 {
10671 OSKext * thisKext = NULL; // do not release
10672 Boolean includeThis = true;
10673 OSSharedPtr<OSDictionary> kextInfo;
10674
10675 thisKext = OSDynamicCast(OSKext, obj);
10676 if (!thisKext) {
10677 return false;;
10678 }
10679
10680 /* Skip current kext if not yet started and caller didn't request all.
10681 */
10682 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10683 return false;;
10684 }
10685
10686 /* Skip current kext if we have a list of bundle IDs and
10687 * it isn't in the list.
10688 */
10689 if (kextIdentifiers) {
10690 includeThis = false;
10691
10692 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10693 const OSString * thisRequestID = OSDynamicCast(OSString,
10694 kextIdentifiers->getObject(idIndex));
10695 if (thisKextID->isEqualTo(thisRequestID)) {
10696 includeThis = true;
10697 break;
10698 }
10699 }
10700 }
10701
10702 if (!includeThis) {
10703 return false;
10704 }
10705
10706 kextInfo = thisKext->copyInfo(infoKeys);
10707 if (kextInfo) {
10708 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10709 }
10710 return false;
10711 });
10712 } // end block scope
10713
10714 finish:
10715 IORecursiveLockUnlock(sKextLock);
10716
10717 return result;
10718 }
10719
10720 /*********************************************************************
10721 * Any info that needs to do allocations must goto finish on alloc
10722 * failure. Info that is just a lookup should just not set the object
10723 * if the info does not exist.
10724 *********************************************************************/
10725 #define _OSKextLoadInfoDictCapacity (12)
10726
10727 OSSharedPtr<OSDictionary>
10728 OSKext::copyInfo(OSArray * infoKeys)
10729 {
10730 OSSharedPtr<OSDictionary> result;
10731 bool success = false;
10732 OSSharedPtr<OSData> headerData;
10733 OSSharedPtr<OSData> logData;
10734 OSSharedPtr<OSNumber> cpuTypeNumber;
10735 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10736 OSString * versionString = NULL; // do not release
10737 OSString * bundleType = NULL; // do not release
10738 uint32_t executablePathCStringSize = 0;
10739 char * executablePathCString = NULL; // must kfree
10740 OSSharedPtr<OSString> executablePathString;
10741 OSSharedPtr<OSData> uuid;
10742 OSSharedPtr<OSArray> dependencyLoadTags;
10743 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10744 OSSharedPtr<OSArray> metaClassInfo;
10745 OSSharedPtr<OSDictionary> metaClassDict;
10746 OSMetaClass * thisMetaClass = NULL; // do not release
10747 OSSharedPtr<OSString> metaClassName;
10748 OSSharedPtr<OSString> superclassName;
10749 kc_format_t kcformat;
10750 uint32_t count, i;
10751
10752 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10753 if (!result) {
10754 goto finish;
10755 }
10756
10757
10758 /* Empty keys means no keys, but NULL is quicker to check.
10759 */
10760 if (infoKeys && !infoKeys->getCount()) {
10761 infoKeys = NULL;
10762 }
10763
10764 if (!PE_get_primary_kc_format(&kcformat)) {
10765 goto finish;
10766 }
10767
10768 /* Headers, CPU type, and CPU subtype.
10769 */
10770 if (!infoKeys ||
10771 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10772 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10773 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10774 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10775 if (linkedExecutable && !isInterface()) {
10776 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10777 linkedExecutable->getBytesNoCopy();
10778
10779 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10780 // do not return macho header info on shipping embedded - 19095897
10781 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10782 kernel_mach_header_t * temp_kext_mach_hdr;
10783 struct load_command * lcp;
10784
10785 headerData = OSData::withBytes(kext_mach_hdr,
10786 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10787 if (!headerData) {
10788 goto finish;
10789 }
10790
10791 // unslide any vmaddrs we return to userspace - 10726716
10792 temp_kext_mach_hdr = (kernel_mach_header_t *)
10793 headerData->getBytesNoCopy();
10794 if (temp_kext_mach_hdr == NULL) {
10795 goto finish;
10796 }
10797
10798 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10799 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10800 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10801 kernel_segment_command_t * segp;
10802 kernel_section_t * secp;
10803
10804 segp = (kernel_segment_command_t *) lcp;
10805 // 10543468 - if we jettisoned __LINKEDIT clear size info
10806 if (flags.jettisonLinkeditSeg) {
10807 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10808 segp->vmsize = 0;
10809 segp->fileoff = 0;
10810 segp->filesize = 0;
10811 }
10812 }
10813
10814 #if __arm__ || __arm64__
10815 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10816 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10817 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10818 segp->vmaddr = gVirtBase;
10819 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10820 secp->size = 0; // paranoia :)
10821 secp->addr = gVirtBase;
10822 }
10823 }
10824 #endif
10825
10826 #if 0
10827 OSKextLog(/* kext */ NULL,
10828 kOSKextLogErrorLevel |
10829 kOSKextLogGeneralFlag,
10830 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10831 __FUNCTION__, segp->segname, segp->vmaddr,
10832 VM_KERNEL_UNSLIDE(segp->vmaddr),
10833 segp->vmsize, segp->nsects);
10834 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10835 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10836 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10837 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10838 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10839 OSKextLog(/* kext */ NULL,
10840 kOSKextLogErrorLevel |
10841 kOSKextLogGeneralFlag,
10842 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10843 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10844 }
10845 #endif
10846 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10847
10848 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10849 secp->addr = ml_static_unslide(secp->addr);
10850 }
10851 }
10852 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10853 }
10854 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
10855 }
10856 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10857
10858 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10859 osLogDataHeaderRef *header;
10860 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10861
10862 void *os_log_data = NULL;
10863 void *cstring_data = NULL;
10864 unsigned long os_log_size = 0;
10865 unsigned long cstring_size = 0;
10866 uint32_t os_log_offset = 0;
10867 uint32_t cstring_offset = 0;
10868 bool res;
10869
10870 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
10871 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
10872 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
10873 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
10874
10875 header = (osLogDataHeaderRef *) headerBytes;
10876 header->version = OS_LOG_HDR_VERSION;
10877 header->sect_count = NUM_OS_LOG_SECTIONS;
10878 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
10879 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
10880 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
10881 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
10882
10883
10884 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10885 if (!logData) {
10886 goto finish;
10887 }
10888 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10889 if (!res) {
10890 goto finish;
10891 }
10892 if (os_log_data) {
10893 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
10894 if (!res) {
10895 goto finish;
10896 }
10897 }
10898 if (cstring_data) {
10899 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
10900 if (!res) {
10901 goto finish;
10902 }
10903 }
10904 result->setObject(kOSBundleLogStringsKey, logData.get());
10905 }
10906
10907 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
10908 cpuTypeNumber = OSNumber::withNumber(
10909 (uint64_t) kext_mach_hdr->cputype,
10910 8 * sizeof(kext_mach_hdr->cputype));
10911 if (!cpuTypeNumber) {
10912 goto finish;
10913 }
10914 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
10915 }
10916
10917 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10918 cpuSubtypeNumber = OSNumber::withNumber(
10919 (uint64_t) kext_mach_hdr->cpusubtype,
10920 8 * sizeof(kext_mach_hdr->cpusubtype));
10921 if (!cpuSubtypeNumber) {
10922 goto finish;
10923 }
10924 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
10925 }
10926 } else {
10927 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10928 osLogDataHeaderRef *header;
10929 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10930 bool res;
10931
10932 header = (osLogDataHeaderRef *) headerBytes;
10933 header->version = OS_LOG_HDR_VERSION;
10934 header->sect_count = NUM_OS_LOG_SECTIONS;
10935 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
10936 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
10937 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
10938 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
10939
10940 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10941 if (!logData) {
10942 goto finish;
10943 }
10944 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10945 if (!res) {
10946 goto finish;
10947 }
10948 result->setObject(kOSBundleLogStringsKey, logData.get());
10949 }
10950 }
10951 }
10952
10953 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10954 */
10955 result->setObject(kCFBundleIdentifierKey, bundleID.get());
10956
10957 /* CFBundlePackageType
10958 */
10959 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
10960 if (bundleType) {
10961 result->setObject(kCFBundlePackageTypeKey, bundleType);
10962 }
10963
10964 /* CFBundleVersion.
10965 */
10966 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
10967 versionString = OSDynamicCast(OSString,
10968 getPropertyForHostArch(kCFBundleVersionKey));
10969 if (versionString) {
10970 result->setObject(kCFBundleVersionKey, versionString);
10971 }
10972 }
10973
10974 /* OSBundleCompatibleVersion.
10975 */
10976 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
10977 versionString = OSDynamicCast(OSString,
10978 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
10979 if (versionString) {
10980 result->setObject(kOSBundleCompatibleVersionKey, versionString);
10981 }
10982 }
10983
10984 /* Path.
10985 */
10986 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
10987 if (path) {
10988 result->setObject(kOSBundlePathKey, path.get());
10989 }
10990 }
10991
10992
10993 /* OSBundleExecutablePath.
10994 */
10995 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
10996 if (path && executableRelPath) {
10997 uint32_t pathLength = path->getLength(); // gets incremented below
10998
10999 // +1 for slash, +1 for \0
11000 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11001
11002 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11003 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
11004 if (!executablePathCString) {
11005 goto finish;
11006 }
11007 strlcpy(executablePathCString, path->getCStringNoCopy(),
11008 executablePathCStringSize);
11009 executablePathCString[pathLength++] = '/';
11010 executablePathCString[pathLength++] = '\0';
11011 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11012 executablePathCStringSize);
11013
11014 executablePathString = OSString::withCString(executablePathCString);
11015
11016 if (!executablePathString) {
11017 goto finish;
11018 }
11019
11020 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11021 } else if (flags.builtin) {
11022 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
11023 } else if (isDriverKit()) {
11024 if (path) {
11025 // +1 for slash, +1 for \0
11026 uint32_t pathLength = path->getLength();
11027 executablePathCStringSize = pathLength + 2;
11028
11029 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11030 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
11031 if (!executablePathCString) {
11032 goto finish;
11033 }
11034 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11035 executablePathCString[pathLength++] = '/';
11036 executablePathCString[pathLength++] = '\0';
11037
11038 executablePathString = OSString::withCString(executablePathCString);
11039
11040 if (!executablePathString) {
11041 goto finish;
11042 }
11043
11044 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11045 }
11046 }
11047 }
11048
11049 /* UUID, if the kext has one.
11050 */
11051 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11052 uuid = copyUUID();
11053 if (uuid) {
11054 result->setObject(kOSBundleUUIDKey, uuid.get());
11055 }
11056 }
11057 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11058 uuid = copyTextUUID();
11059 if (uuid) {
11060 result->setObject(kOSBundleTextUUIDKey, uuid.get());
11061 }
11062 }
11063
11064 /*
11065 * Info.plist digest
11066 */
11067 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11068 OSData *digest;
11069 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11070 if (digest) {
11071 result->setObject(kOSKextInfoPlistDigestKey, digest);
11072 }
11073 }
11074
11075 /*
11076 * Collection type
11077 */
11078 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11079 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
11080 }
11081
11082 /*
11083 * Collection availability
11084 */
11085 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11086 result->setObject(kOSKextAuxKCAvailabilityKey,
11087 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11088 }
11089
11090 /*
11091 * Allows user load
11092 */
11093 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11094 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11095 if (allowUserLoad) {
11096 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11097 }
11098 }
11099
11100 /*
11101 * Bundle Dependencies (OSBundleLibraries)
11102 */
11103 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11104 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11105 if (libraries) {
11106 result->setObject(kOSBundleLibrariesKey, libraries);
11107 }
11108 }
11109
11110 /*****
11111 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11112 */
11113 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11114 result->setObject(kOSKernelResourceKey,
11115 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11116 }
11117
11118 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11119 result->setObject(kOSBundleIsInterfaceKey,
11120 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11121 }
11122
11123 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11124 result->setObject(kOSBundlePrelinkedKey,
11125 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
11126 }
11127
11128 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11129 result->setObject(kOSBundleStartedKey,
11130 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11131 }
11132
11133 /* LoadTag (Index).
11134 */
11135 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
11136 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
11137 /* numBits */ 8 * sizeof(loadTag));
11138 if (!scratchNumber) {
11139 goto finish;
11140 }
11141 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
11142 }
11143
11144 /* LoadAddress, LoadSize.
11145 */
11146 if (!infoKeys ||
11147 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11148 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11149 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11150 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11151 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11152 bool is_dext = isDriverKit();
11153 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
11154 /* These go to userspace via serialization, so we don't want any doubts
11155 * about their size.
11156 */
11157 uint64_t loadAddress = 0;
11158 uint32_t loadSize = 0;
11159 uint32_t wiredSize = 0;
11160 uint64_t execLoadAddress = 0;
11161 uint32_t execLoadSize = 0;
11162
11163 /* Interfaces always report 0 load address & size.
11164 * Just the way they roll.
11165 *
11166 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11167 * xxx - shouldn't have one!
11168 */
11169
11170 if (flags.builtin || linkedExecutable) {
11171 kernel_mach_header_t *mh = NULL;
11172 kernel_segment_command_t *seg = NULL;
11173
11174 if (flags.builtin) {
11175 loadAddress = kmod_info->address;
11176 loadSize = (uint32_t)kmod_info->size;
11177 } else {
11178 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11179 loadSize = linkedExecutable->getLength();
11180 }
11181 mh = (kernel_mach_header_t *)loadAddress;
11182 loadAddress = ml_static_unslide(loadAddress);
11183
11184 /* Walk through the kext, looking for the first executable
11185 * segment in case we were asked for its size/address.
11186 */
11187 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11188 if (seg->initprot & VM_PROT_EXECUTE) {
11189 execLoadAddress = ml_static_unslide(seg->vmaddr);
11190 execLoadSize = (uint32_t)seg->vmsize;
11191 break;
11192 }
11193 }
11194
11195 /* If we have a kmod_info struct, calculated the wired size
11196 * from that. Otherwise it's the full load size.
11197 */
11198 if (kmod_info) {
11199 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
11200 } else {
11201 wiredSize = loadSize;
11202 }
11203 } else if (is_dext) {
11204 /*
11205 * DriverKit userspace executables do not have a kernel linkedExecutable,
11206 * so we "fake" their address range with the LoadTag.
11207 */
11208 if (loadTag) {
11209 loadAddress = execLoadAddress = loadTag;
11210 loadSize = execLoadSize = 1;
11211 }
11212 }
11213
11214 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
11215 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11216 (unsigned long long)(loadAddress),
11217 /* numBits */ 8 * sizeof(loadAddress));
11218 if (!scratchNumber) {
11219 goto finish;
11220 }
11221 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
11222 }
11223 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11224 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11225 && loadAddress && loadSize) {
11226 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11227 if (!baseAddress) {
11228 goto finish;
11229 }
11230
11231 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11232 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11233 /* numBits */ 8 * sizeof(loadAddress));
11234 if (!scratchNumber) {
11235 goto finish;
11236 }
11237 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11238 }
11239 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11240 && (this == sKernelKext) && gBuiltinKmodsCount) {
11241 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
11242 }
11243 }
11244
11245 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
11246 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11247 (unsigned long long)(execLoadAddress),
11248 /* numBits */ 8 * sizeof(execLoadAddress));
11249 if (!scratchNumber) {
11250 goto finish;
11251 }
11252 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
11253 }
11254 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
11255 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11256 (unsigned long long)(loadSize),
11257 /* numBits */ 8 * sizeof(loadSize));
11258 if (!scratchNumber) {
11259 goto finish;
11260 }
11261 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
11262 }
11263 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
11264 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11265 (unsigned long long)(execLoadSize),
11266 /* numBits */ 8 * sizeof(execLoadSize));
11267 if (!scratchNumber) {
11268 goto finish;
11269 }
11270 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
11271 }
11272 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11273 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11274 (unsigned long long)(wiredSize),
11275 /* numBits */ 8 * sizeof(wiredSize));
11276 if (!scratchNumber) {
11277 goto finish;
11278 }
11279 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
11280 }
11281 }
11282 }
11283
11284 /* OSBundleDependencies. In descending order for
11285 * easy compatibility with kextstat(8).
11286 */
11287 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11288 if ((count = getNumDependencies())) {
11289 dependencyLoadTags = OSArray::withCapacity(count);
11290 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
11291
11292 i = count - 1;
11293 do {
11294 OSKext * dependency = OSDynamicCast(OSKext,
11295 dependencies->getObject(i));
11296
11297 if (!dependency) {
11298 continue;
11299 }
11300 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11301 (unsigned long long)dependency->getLoadTag(),
11302 /* numBits*/ 8 * sizeof(loadTag));
11303 if (!scratchNumber) {
11304 goto finish;
11305 }
11306 dependencyLoadTags->setObject(scratchNumber.get());
11307 } while (i--);
11308 }
11309 }
11310
11311 /* OSBundleMetaClasses.
11312 */
11313 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11314 if (metaClasses && metaClasses->getCount()) {
11315 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
11316 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11317 if (!metaClassIterator || !metaClassInfo) {
11318 goto finish;
11319 }
11320 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
11321
11322 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11323 metaClassIterator->getNextObject()))) {
11324 metaClassDict = OSDictionary::withCapacity(3);
11325 if (!metaClassDict) {
11326 goto finish;
11327 }
11328
11329 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11330 if (thisMetaClass->getSuperClass()) {
11331 superclassName = OSString::withCString(
11332 thisMetaClass->getSuperClass()->getClassName());
11333 }
11334 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
11335 8 * sizeof(unsigned int));
11336
11337 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11338 * of course.
11339 */
11340 if (!metaClassDict || !metaClassName || !scratchNumber) {
11341 goto finish;
11342 }
11343
11344 metaClassInfo->setObject(metaClassDict.get());
11345 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
11346 if (superclassName) {
11347 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
11348 }
11349 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
11350 }
11351 }
11352 }
11353
11354 /* OSBundleRetainCount.
11355 */
11356 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
11357 {
11358 int kextRetainCount = getRetainCount() - 1;
11359 if (isLoaded()) {
11360 kextRetainCount--;
11361 }
11362 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11363 (int)kextRetainCount,
11364 /* numBits*/ 8 * sizeof(int));
11365 if (scratchNumber) {
11366 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
11367 }
11368 }
11369 }
11370
11371 success = true;
11372
11373 finish:
11374 if (executablePathCString) {
11375 kheap_free(KHEAP_TEMP, executablePathCString, executablePathCStringSize);
11376 }
11377 if (!success) {
11378 result.reset();
11379 }
11380 return result;
11381 }
11382
11383 /*********************************************************************
11384 *********************************************************************/
11385 /* static */
11386 bool
11387 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11388 {
11389 bool ok;
11390 OSSharedPtr<OSKext> kext;
11391
11392 IORecursiveLockLock(sKextLock);
11393 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
11394 IORecursiveLockUnlock(sKextLock);
11395
11396 if (!kext || !kext->path || !kext->userExecutableRelPath) {
11397 return false;
11398 }
11399 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11400 kext->path->getCStringNoCopy(),
11401 kext->userExecutableRelPath->getCStringNoCopy());
11402 ok = true;
11403
11404 return ok;
11405 }
11406
11407 /*********************************************************************
11408 *********************************************************************/
11409 /* static */
11410 OSReturn
11411 OSKext::requestResource(
11412 const char * kextIdentifierCString,
11413 const char * resourceNameCString,
11414 OSKextRequestResourceCallback callback,
11415 void * context,
11416 OSKextRequestTag * requestTagOut)
11417 {
11418 OSReturn result = kOSReturnError;
11419 OSSharedPtr<OSKext> callbackKext; // looked up
11420
11421 OSKextRequestTag requestTag = -1;
11422 OSSharedPtr<OSNumber> requestTagNum;
11423 OSSharedPtr<OSDictionary> requestDict;
11424 OSSharedPtr<OSString> kextIdentifier;
11425 OSSharedPtr<OSString> resourceName;
11426
11427 OSSharedPtr<OSDictionary> callbackRecord;
11428 OSSharedPtr<OSData> callbackWrapper;
11429
11430 OSSharedPtr<OSData> contextWrapper;
11431
11432 IORecursiveLockLock(sKextLock);
11433
11434 if (requestTagOut) {
11435 *requestTagOut = kOSKextRequestTagInvalid;
11436 }
11437
11438 /* If requests to user space are disabled, don't go any further */
11439 if (!sKernelRequestsEnabled) {
11440 OSKextLog(/* kext */ NULL,
11441 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11442 "Can't request resource %s for %s - requests to user space are disabled.",
11443 resourceNameCString,
11444 kextIdentifierCString);
11445 result = kOSKextReturnDisabled;
11446 goto finish;
11447 }
11448
11449 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11450 result = kOSKextReturnInvalidArgument;
11451 goto finish;
11452 }
11453
11454 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11455 if (!callbackKext) {
11456 OSKextLog(/* kext */ NULL,
11457 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11458 "Resource request has bad callback address.");
11459 result = kOSKextReturnInvalidArgument;
11460 goto finish;
11461 }
11462 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11463 OSKextLog(/* kext */ NULL,
11464 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11465 "Resource request callback is in a kext that is not started.");
11466 result = kOSKextReturnInvalidArgument;
11467 goto finish;
11468 }
11469
11470 /* Do not allow any new requests to be made on a kext that is unloading.
11471 */
11472 if (callbackKext->flags.stopping) {
11473 result = kOSKextReturnStopping;
11474 goto finish;
11475 }
11476
11477 /* If we're wrapped the next available request tag around to the negative
11478 * numbers, we can't service any more requests.
11479 */
11480 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11481 OSKextLog(/* kext */ NULL,
11482 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11483 "No more request tags available; restart required.");
11484 result = kOSKextReturnNoResources;
11485 goto finish;
11486 }
11487 requestTag = sNextRequestTag++;
11488
11489 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
11490 requestDict);
11491 if (result != kOSReturnSuccess) {
11492 goto finish;
11493 }
11494
11495 kextIdentifier = OSString::withCString(kextIdentifierCString);
11496 resourceName = OSString::withCString(resourceNameCString);
11497 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11498 8 * sizeof(requestTag));
11499 if (!kextIdentifier ||
11500 !resourceName ||
11501 !requestTagNum ||
11502 !_OSKextSetRequestArgument(requestDict.get(),
11503 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11504 !_OSKextSetRequestArgument(requestDict.get(),
11505 kKextRequestArgumentNameKey, resourceName.get()) ||
11506 !_OSKextSetRequestArgument(requestDict.get(),
11507 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
11508 result = kOSKextReturnNoMemory;
11509 goto finish;
11510 }
11511
11512 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
11513 if (!callbackRecord) {
11514 result = kOSKextReturnNoMemory;
11515 goto finish;
11516 }
11517 // we validate callback address at call time
11518 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
11519 if (context) {
11520 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
11521 }
11522 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11523 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
11524 result = kOSKextReturnNoMemory;
11525 goto finish;
11526 }
11527
11528 if (context) {
11529 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11530 kKextRequestArgumentContextKey, contextWrapper.get())) {
11531 result = kOSKextReturnNoMemory;
11532 goto finish;
11533 }
11534 }
11535
11536 /* Only post the requests after all the other potential failure points
11537 * have been passed.
11538 */
11539 if (!sKernelRequests->setObject(requestDict.get()) ||
11540 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
11541 result = kOSKextReturnNoMemory;
11542 goto finish;
11543 }
11544
11545 OSKext::pingIOKitDaemon();
11546
11547 result = kOSReturnSuccess;
11548 if (requestTagOut) {
11549 *requestTagOut = requestTag;
11550 }
11551
11552 finish:
11553
11554 /* If we didn't succeed, yank the request & callback
11555 * from their holding arrays.
11556 */
11557 if (result != kOSReturnSuccess) {
11558 unsigned int index;
11559
11560 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
11561 if (index != (unsigned int)-1) {
11562 sKernelRequests->removeObject(index);
11563 }
11564 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
11565 if (index != (unsigned int)-1) {
11566 sRequestCallbackRecords->removeObject(index);
11567 }
11568 }
11569
11570 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11571
11572 IORecursiveLockUnlock(sKextLock);
11573
11574 return result;
11575 }
11576
11577 OSReturn
11578 OSKext::requestDaemonLaunch(
11579 OSString *kextIdentifier,
11580 OSString *serverName,
11581 OSNumber *serverTag,
11582 OSSharedPtr<IOUserServerCheckInToken> &checkInToken)
11583 {
11584 OSReturn result;
11585 IOUserServerCheckInToken * checkInTokenRaw = NULL;
11586
11587 result = requestDaemonLaunch(kextIdentifier, serverName,
11588 serverTag, &checkInTokenRaw);
11589
11590 if (kOSReturnSuccess == result) {
11591 checkInToken.reset(checkInTokenRaw, OSNoRetain);
11592 }
11593
11594 return result;
11595 }
11596
11597 OSReturn
11598 OSKext::requestDaemonLaunch(
11599 OSString *kextIdentifier,
11600 OSString *serverName,
11601 OSNumber *serverTag,
11602 IOUserServerCheckInToken ** checkInToken)
11603 {
11604 OSReturn result = kOSReturnError;
11605 OSSharedPtr<OSDictionary> requestDict;
11606 OSSharedPtr<IOUserServerCheckInToken> token;
11607
11608 if (!kextIdentifier || !serverName || !serverTag) {
11609 result = kOSKextReturnInvalidArgument;
11610 goto finish;
11611 }
11612
11613 IORecursiveLockLock(sKextLock);
11614
11615 OSKextLog(/* kext */ NULL,
11616 kOSKextLogDebugLevel |
11617 kOSKextLogGeneralFlag,
11618 "Requesting daemon launch for %s with serverName %s and tag %llu",
11619 kextIdentifier->getCStringNoCopy(),
11620 serverName->getCStringNoCopy(),
11621 serverTag->unsigned64BitValue()
11622 );
11623
11624 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
11625 if (result != kOSReturnSuccess) {
11626 goto finish;
11627 }
11628
11629 token.reset(IOUserServerCheckInToken::create(), OSNoRetain);
11630 if (!token) {
11631 result = kOSKextReturnNoMemory;
11632 goto finish;
11633 }
11634
11635 if (!_OSKextSetRequestArgument(requestDict.get(),
11636 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
11637 !_OSKextSetRequestArgument(requestDict.get(),
11638 kKextRequestArgumentDriverExtensionServerName, serverName) ||
11639 !_OSKextSetRequestArgument(requestDict.get(),
11640 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11641 !_OSKextSetRequestArgument(requestDict.get(),
11642 kKextRequestArgumentCheckInToken, token.get())) {
11643 result = kOSKextReturnNoMemory;
11644 goto finish;
11645 }
11646
11647 /* Only post the requests after all the other potential failure points
11648 * have been passed.
11649 */
11650 if (!sKernelRequests->setObject(requestDict.get())) {
11651 result = kOSKextReturnNoMemory;
11652 goto finish;
11653 }
11654 *checkInToken = token.detach();
11655 OSKext::pingIOKitDaemon();
11656
11657 result = kOSReturnSuccess;
11658 finish:
11659 IORecursiveLockUnlock(sKextLock);
11660 return result;
11661 }
11662
11663 /*********************************************************************
11664 * Assumes sKextLock is held.
11665 *********************************************************************/
11666 /* static */
11667 OSReturn
11668 OSKext::dequeueCallbackForRequestTag(
11669 OSKextRequestTag requestTag,
11670 OSSharedPtr<OSDictionary> &callbackRecordOut)
11671 {
11672 OSDictionary * callbackRecordOutRaw = NULL;
11673 OSReturn result;
11674
11675 result = dequeueCallbackForRequestTag(requestTag,
11676 &callbackRecordOutRaw);
11677
11678 if (kOSReturnSuccess == result) {
11679 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11680 }
11681
11682 return result;
11683 }
11684 OSReturn
11685 OSKext::dequeueCallbackForRequestTag(
11686 OSKextRequestTag requestTag,
11687 OSDictionary ** callbackRecordOut)
11688 {
11689 OSReturn result = kOSReturnError;
11690 OSSharedPtr<OSNumber> requestTagNum;
11691
11692 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11693 8 * sizeof(requestTag));
11694 if (!requestTagNum) {
11695 goto finish;
11696 }
11697
11698 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11699 callbackRecordOut);
11700
11701 finish:
11702 return result;
11703 }
11704
11705 /*********************************************************************
11706 * Assumes sKextLock is held.
11707 *********************************************************************/
11708 /* static */
11709 OSReturn
11710 OSKext::dequeueCallbackForRequestTag(
11711 OSNumber * requestTagNum,
11712 OSSharedPtr<OSDictionary> &callbackRecordOut)
11713 {
11714 OSDictionary * callbackRecordOutRaw = NULL;
11715 OSReturn result;
11716
11717 result = dequeueCallbackForRequestTag(requestTagNum,
11718 &callbackRecordOutRaw);
11719
11720 if (kOSReturnSuccess == result) {
11721 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11722 }
11723
11724 return result;
11725 }
11726 OSReturn
11727 OSKext::dequeueCallbackForRequestTag(
11728 OSNumber * requestTagNum,
11729 OSDictionary ** callbackRecordOut)
11730 {
11731 OSReturn result = kOSKextReturnInvalidArgument;
11732 OSDictionary * callbackRecord = NULL; // retain if matched!
11733 OSNumber * callbackTagNum = NULL; // do not release
11734 unsigned int count, i;
11735
11736 result = kOSReturnError;
11737 count = sRequestCallbackRecords->getCount();
11738 for (i = 0; i < count; i++) {
11739 callbackRecord = OSDynamicCast(OSDictionary,
11740 sRequestCallbackRecords->getObject(i));
11741 if (!callbackRecord) {
11742 goto finish;
11743 }
11744
11745 /* If we don't find a tag, we basically have a leak here. Maybe
11746 * we should just remove it.
11747 */
11748 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11749 callbackRecord, kKextRequestArgumentRequestTagKey));
11750 if (!callbackTagNum) {
11751 goto finish;
11752 }
11753
11754 /* We could be even more paranoid and check that all the incoming
11755 * args match what's in the callback record.
11756 */
11757 if (callbackTagNum->isEqualTo(requestTagNum)) {
11758 if (callbackRecordOut) {
11759 *callbackRecordOut = callbackRecord;
11760 callbackRecord->retain();
11761 }
11762 sRequestCallbackRecords->removeObject(i);
11763 result = kOSReturnSuccess;
11764 goto finish;
11765 }
11766 }
11767 result = kOSKextReturnNotFound;
11768
11769 finish:
11770 return result;
11771 }
11772
11773
11774 /*********************************************************************
11775 * Busy timeout triage
11776 *********************************************************************/
11777 /* static */
11778 bool
11779 OSKext::pendingIOKitDaemonRequests(void)
11780 {
11781 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11782 }
11783
11784 /*********************************************************************
11785 * Acquires and releases sKextLock
11786 *
11787 * This function is designed to be called exactly once on boot by
11788 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11789 * kext and dext personalities, and then attempts to map a System
11790 * (pageable) KC and an Auxiliary (aux) KC.
11791 *
11792 * Even if the pageable or aux KC fail to load - this function will
11793 * not allow a second call. This avoids security issues where
11794 * kernelmanagerd has been compromised or the pageable kc has been
11795 * tampered with and the attacker attempts to re-load a malicious
11796 * variant.
11797 *
11798 * Return: if a KC fails to load the return value will contain:
11799 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11800 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11801 * Similarly, if the aux kc load fails, the return value will
11802 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11803 * compose with each other and with kOSKextReturnKCLoadFailure.
11804 *********************************************************************/
11805 /* static */
11806 OSReturn
11807 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11808 {
11809 static bool daemon_ready = false;
11810
11811 OSReturn ret = kOSKextReturnInvalidArgument;
11812 OSReturn kcerr = 0;
11813 bool start_matching = false;
11814
11815 bool allow_fileset_load = !daemon_ready;
11816 #if !(defined(__x86_64__) || defined(__i386__))
11817 /* never allow KCs full of kexts on non-x86 machines */
11818 allow_fileset_load = false;
11819 #endif
11820
11821 /*
11822 * Get the args from the request. Right now we need the file
11823 * name for the pageable and the aux kext collection file sets.
11824 */
11825 OSDictionary * requestArgs = NULL; // do not release
11826 OSString * pageable_filepath = NULL; // do not release
11827 OSString * aux_filepath = NULL; // do not release
11828 OSArray * codeless_kexts = NULL; // do not release
11829
11830 kernel_mach_header_t *akc_mh = NULL;
11831
11832 requestArgs = OSDynamicCast(OSDictionary,
11833 requestDict->getObject(kKextRequestArgumentsKey));
11834
11835 if (requestArgs == NULL) {
11836 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11837 "KextLog: No arguments in plist for loading fileset kext\n");
11838 printf("KextLog: No arguments in plist for loading fileset kext\n");
11839 return ret;
11840 }
11841
11842 ret = kOSKextReturnDisabled;
11843
11844 IORecursiveLockLock(sKextLock);
11845
11846 pageable_filepath = OSDynamicCast(OSString,
11847 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11848
11849 if (allow_fileset_load && pageable_filepath != NULL) {
11850 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11851
11852 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11853 if (ret) {
11854 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11855 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11856
11857 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11858 ret = kOSKextReturnKCLoadFailure;
11859 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11860 goto try_auxkc;
11861 }
11862 /*
11863 * Even if the AuxKC fails to load, we still want to send
11864 * the System KC personalities to the catalog for matching
11865 */
11866 start_matching = true;
11867 } else if (pageable_filepath != NULL) {
11868 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11869 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
11870 ret = kOSKextReturnUnsupported;
11871 }
11872
11873 try_auxkc:
11874 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
11875 if (akc_mh) {
11876 /*
11877 * If we try to load a deferred AuxKC, then don't ever attempt
11878 * a filesystem map of a file
11879 */
11880 allow_fileset_load = false;
11881
11882 /*
11883 * This function is only called once per boot, so we haven't
11884 * yet loaded an AuxKC. If we have registered the AuxKC mach
11885 * header, that means that the kext collection has been placed
11886 * in memory for us by the booter, and is waiting for us to
11887 * process it. Grab the deferred XML plist of info
11888 * dictionaries and add all the kexts.
11889 */
11890 OSSharedPtr<OSObject> parsedXML;
11891 OSSharedPtr<OSData> loaded_kcUUID;
11892 OSDictionary *infoDict;
11893 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
11894 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11895 if (infoDict) {
11896 bool added;
11897 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11898 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
11899 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
11900 if (!loaded_kcUUID) {
11901 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11902 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11903 } else if (!added) {
11904 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11905 "KextLog: WARNING: Failed to load AuxKC from memory.");
11906 }
11907 /* only return success if the pageable load (above) was successful */
11908 if (ret != kOSKextReturnKCLoadFailure) {
11909 ret = kOSReturnSuccess;
11910 }
11911 /* the registration of the AuxKC parsed out the KC's UUID already */
11912 } else {
11913 if (daemon_ready) {
11914 /*
11915 * Complain, but don't return an error if this isn't the first time the
11916 * IOKit daemon is checking in. If the daemon ever restarts, we will
11917 * hit this case because we've already consumed the deferred personalities.
11918 * We return success here so that a call to this function from a restarted
11919 * daemon with no codeless kexts will succeed.
11920 */
11921 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11922 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
11923 if (ret != kOSKextReturnKCLoadFailure) {
11924 ret = kOSReturnSuccess;
11925 }
11926 } else {
11927 /* this is a real error case */
11928 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11929 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
11930 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
11931 ret = kOSKextReturnKCLoadFailure;
11932 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
11933 }
11934 }
11935 }
11936
11937 aux_filepath = OSDynamicCast(OSString,
11938 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
11939 if (allow_fileset_load && aux_filepath != NULL) {
11940 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
11941
11942 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
11943 if (ret) {
11944 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11945 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
11946
11947 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
11948 ret = kOSKextReturnKCLoadFailure;
11949 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
11950 goto try_codeless;
11951 }
11952 start_matching = true;
11953 } else if (aux_filepath != NULL) {
11954 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11955 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
11956 if (ret != kOSKextReturnKCLoadFailure) {
11957 ret = kOSKextReturnUnsupported;
11958 }
11959 }
11960
11961 try_codeless:
11962 /*
11963 * Load codeless kexts last so that there is no possibilty of a
11964 * codeless kext bundle ID preventing a kext in the system KC from
11965 * loading
11966 */
11967 codeless_kexts = OSDynamicCast(OSArray,
11968 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
11969 if (codeless_kexts != NULL) {
11970 uint32_t count = codeless_kexts->getCount();
11971 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11972 "KextLog: loading %d codeless kexts/dexts", count);
11973 for (uint32_t i = 0; i < count; i++) {
11974 OSDictionary *infoDict;
11975 infoDict = OSDynamicCast(OSDictionary,
11976 codeless_kexts->getObject(i));
11977 if (!infoDict) {
11978 continue;
11979 }
11980 // instantiate a new kext, and don't hold a reference
11981 // (the kext subsystem will hold one implicitly)
11982 OSKext::withCodelessInfo(infoDict);
11983 }
11984 /* ignore errors that are not KC load failures */
11985 if (ret != kOSKextReturnKCLoadFailure) {
11986 ret = kOSReturnSuccess;
11987 }
11988 start_matching = true;
11989 }
11990
11991 /* send personalities to the IOCatalog once */
11992 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
11993 OSKext::sendAllKextPersonalitiesToCatalog(true);
11994 /*
11995 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
11996 * things as active and start all the delayed matching: the
11997 * dext and codeless kext personalities should have all been
11998 * delivered via this one call.
11999 */
12000 if (!daemon_ready) {
12001 OSKext::setIOKitDaemonActive();
12002 OSKext::setDeferredLoadSucceeded(TRUE);
12003 IOService::iokitDaemonLaunched();
12004 }
12005 if (sOSKextWasResetAfterUserspaceReboot) {
12006 sOSKextWasResetAfterUserspaceReboot = false;
12007 OSKext::setIOKitDaemonActive();
12008 IOService::startDeferredMatches();
12009 }
12010 }
12011
12012 if (ret == kOSKextReturnKCLoadFailure) {
12013 ret |= kcerr;
12014 }
12015
12016 /*
12017 * Only allow this function to attempt to load the pageable and
12018 * aux KCs once per boot.
12019 */
12020 daemon_ready = true;
12021
12022 IORecursiveLockUnlock(sKextLock);
12023
12024 return ret;
12025 }
12026
12027 OSReturn
12028 OSKext::resetMutableSegments(void)
12029 {
12030 kernel_segment_command_t *seg = NULL;
12031 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12032 u_int index = 0;
12033 OSKextSavedMutableSegment *savedSegment = NULL;
12034 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12035 OSReturn err;
12036
12037 if (!savedMutableSegments) {
12038 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12039 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12040 err = kOSKextReturnInternalError;
12041 goto finish;
12042 }
12043
12044 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12045 if (!segmentIsMutable(seg)) {
12046 continue;
12047 }
12048 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12049 uint64_t vmsize = seg->vmsize;
12050 err = kOSKextReturnInternalError;
12051 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12052 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12053 assert(savedSegment);
12054 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12055 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12056 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12057 err = savedSegment->restoreContents(seg);
12058 if (err != kOSReturnSuccess) {
12059 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12060 }
12061 }
12062 }
12063 if (err != kOSReturnSuccess) {
12064 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12065 }
12066 }
12067 err = kOSReturnSuccess;
12068 finish:
12069 return err;
12070 }
12071
12072
12073 /*********************************************************************
12074 * Assumes sKextLock is held.
12075 *********************************************************************/
12076 /* static */
12077 OSReturn
12078 OSKext::loadKCFileSet(
12079 const char *filepath,
12080 kc_kind_t type)
12081 {
12082 #if VM_MAPPED_KEXTS
12083 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12084 OSReturn err;
12085 struct vnode *vp = NULL;
12086 void *fileset_control;
12087 off_t fsize;
12088 bool pageable = (type == KCKindPageable);
12089
12090 if ((pageable && pageableKCloaded) ||
12091 (!pageable && auxKCloaded)) {
12092 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12093 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12094
12095 return kOSKextReturnInvalidArgument;
12096 }
12097
12098 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12099 if (!pageable && !pageableKCloaded) {
12100 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12101 "Trying to load the Aux KC without loading the Pageable KC");
12102 return kOSKextReturnInvalidArgument;
12103 }
12104
12105 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12106
12107 if (fileset_control == NULL) {
12108 printf("Could not get memory control object for file %s", filepath);
12109
12110 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12111 "Could not get memory control object for file %s", filepath);
12112 return kOSKextReturnInvalidArgument;
12113 }
12114 if (vp == NULL) {
12115 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12116 "Could not find vnode for file %s", filepath);
12117 return kOSKextReturnInvalidArgument;
12118 }
12119
12120 kernel_mach_header_t *mh = NULL;
12121 uintptr_t slide = 0;
12122
12123 #if CONFIG_CSR
12124 /*
12125 * When SIP is enabled, the KC we map must be SIP-protected
12126 */
12127 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12128 struct vnode_attr va;
12129 int error;
12130 VATTR_INIT(&va);
12131 VATTR_WANTED(&va, va_flags);
12132 error = vnode_getattr(vp, &va, vfs_context_current());
12133 if (error) {
12134 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12135 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12136 err = kOSKextReturnInternalError;
12137 goto finish;
12138 }
12139 if (!(va.va_flags & SF_RESTRICTED)) {
12140 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12141 "Path to KC '%s' is not SIP-protected", filepath);
12142 err = kOSKextReturnInvalidArgument;
12143 goto finish;
12144 }
12145 }
12146 #endif
12147
12148 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12149 if (err) {
12150 printf("KextLog: mapKCFileSet returned %d\n", err);
12151
12152 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12153 "mapKCFileSet returned %d\n", err);
12154
12155 err = kOSKextReturnInvalidArgument;
12156 }
12157
12158 #if CONFIG_CSR
12159 finish:
12160 #endif
12161 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12162 assert(vp != NULL);
12163 if (err == kOSReturnSuccess) {
12164 PE_set_kc_vp(type, vp);
12165 if (pageable) {
12166 pageableKCloaded = true;
12167 } else {
12168 auxKCloaded = true;
12169 }
12170 } else {
12171 vnode_put(vp);
12172 }
12173
12174 return err;
12175 #else
12176 (void)filepath;
12177 (void)type;
12178 return kOSKextReturnUnsupported;
12179 #endif // VM_MAPPED_KEXTS
12180 }
12181
12182 #if defined(__x86_64__) || defined(__i386__)
12183 /*********************************************************************
12184 * Assumes sKextLock is held.
12185 *********************************************************************/
12186 /* static */
12187 OSReturn
12188 OSKext::mapKCFileSet(
12189 void *control,
12190 vm_size_t fsize,
12191 kernel_mach_header_t **mhp,
12192 off_t file_offset,
12193 uintptr_t *slidep,
12194 bool pageable,
12195 void *map_entry_list)
12196 {
12197 bool fileset_load = false;
12198 kern_return_t ret;
12199 OSReturn err;
12200 kernel_section_t *infoPlistSection = NULL;
12201 OSDictionary *infoDict = NULL;
12202
12203 OSSharedPtr<OSObject> parsedXML;
12204 OSSharedPtr<OSString> errorString;
12205 OSSharedPtr<OSData> loaded_kcUUID;
12206
12207 /* Check if initial load for file set */
12208 if (*mhp == NULL) {
12209 fileset_load = true;
12210
12211 /* Get a page aligned address from kext map to map the file */
12212 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12213 if (pagealigned_addr == 0) {
12214 return kOSKextReturnNoMemory;
12215 }
12216
12217 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12218
12219 /* Allocate memory for bailout mechanism */
12220 map_entry_list = allocate_kcfileset_map_entry_list();
12221 if (map_entry_list == NULL) {
12222 return kOSKextReturnNoMemory;
12223 }
12224 }
12225
12226 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12227 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12228 /* mhp and slideptr are updated by mapKCTextSegment */
12229 if (err) {
12230 if (fileset_load) {
12231 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12232 }
12233 return err;
12234 }
12235
12236 /* Initialize the kc header globals */
12237 if (fileset_load) {
12238 if (pageable) {
12239 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12240 } else {
12241 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12242 }
12243 }
12244
12245 /* Iterate through all the segments and map necessary segments */
12246 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12247 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12248 vm_map_offset_t start;
12249 kernel_mach_header_t *k_mh = NULL;
12250 kernel_segment_command_t * seg = NULL;
12251 struct fileset_entry_command *fse = NULL;
12252
12253 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12254 seg = (kernel_segment_command_t *)lcp;
12255 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12256 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12257 fse = (struct fileset_entry_command *)lcp;
12258 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12259
12260 /* Map the segments of the mach-o binary */
12261 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12262 if (err) {
12263 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12264 return kOSKextReturnInvalidArgument;
12265 }
12266 continue;
12267 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12268 /* Check if the Aux KC is built pageable style */
12269 if (!pageable && !fileset_load && !auxKCloaded) {
12270 resetAuxKCSegmentOnUnload = true;
12271 }
12272 continue;
12273 } else {
12274 continue;
12275 }
12276
12277 if (fileset_load) {
12278 if (seg->vmsize == 0) {
12279 continue;
12280 }
12281
12282 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12283 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12284 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12285 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12286 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12287 continue;
12288 }
12289 } else {
12290 if (seg->vmsize == 0) {
12291 continue;
12292 }
12293
12294 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12295 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12296 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12297 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12298 continue;
12299 }
12300 }
12301
12302 ret = vm_map_kcfileset_segment(
12303 &start, seg->vmsize,
12304 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12305
12306 if (ret != KERN_SUCCESS) {
12307 if (fileset_load) {
12308 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12309 }
12310 return kOSKextReturnInvalidArgument;
12311 }
12312 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12313 }
12314
12315 /* Return if regular mach-o */
12316 if (!fileset_load) {
12317 return 0;
12318 }
12319
12320 /*
12321 * Fixup for the Pageable KC and the Aux KC is done by
12322 * i386_slide_kext_collection_mh_addrs, but it differs in
12323 * following ways:
12324 *
12325 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12326 * The fixup of kext segments and kext load commands are done at kext
12327 * load time by calling i386_slide_individual_kext.
12328 *
12329 * AuxKC old style: Fixup all the segments and all the load commands.
12330 *
12331 * AuxKC pageable style: Same as the Pageable KC.
12332 */
12333 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12334 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12335 if (ret != KERN_SUCCESS) {
12336 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12337 return kOSKextReturnInvalidArgument;
12338 }
12339
12340 /* Get the prelink info dictionary */
12341 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12342 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12343 if (parsedXML) {
12344 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12345 }
12346
12347 if (!infoDict) {
12348 const char *errorCString = "(unknown error)";
12349
12350 if (errorString && errorString->getCStringNoCopy()) {
12351 errorCString = errorString->getCStringNoCopy();
12352 } else if (parsedXML) {
12353 errorCString = "not a dictionary";
12354 }
12355 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12356 "Error unserializing kext info plist section: %s.", errorCString);
12357 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12358 return kOSKextReturnInvalidArgument;
12359 }
12360
12361 /* Validate that the Kext Collection is prelinked to the loaded KC */
12362 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12363 if (err) {
12364 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12365 return kOSKextReturnInvalidArgument;
12366 }
12367
12368 /* Set Protection of Segments */
12369 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12370
12371 OSKext::addKextsFromKextCollection(*mhp,
12372 infoDict, kPrelinkTextSegment,
12373 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12374
12375 /* Copy in the KC UUID */
12376 if (!loaded_kcUUID) {
12377 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12378 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12379 } else if (pageable) {
12380 pageablekc_uuid_valid = TRUE;
12381 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12382 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12383 } else {
12384 auxkc_uuid_valid = TRUE;
12385 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12386 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12387 }
12388
12389 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12390
12391 return 0;
12392 }
12393
12394 /*********************************************************************
12395 * Assumes sKextLock is held.
12396 *********************************************************************/
12397 /* static */
12398 OSReturn
12399 OSKext::mapKCTextSegment(
12400 void *control,
12401 kernel_mach_header_t **mhp,
12402 off_t file_offset,
12403 uintptr_t *slidep,
12404 void *map_entry_list)
12405 {
12406 kern_return_t ret;
12407 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12408 PAGE_MASK);
12409 vm_map_offset_t load_command_map_size = 0;
12410 kernel_mach_header_t *base_mh = *mhp;
12411
12412 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12413 ret = vm_map_kcfileset_segment(
12414 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12415 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12416
12417 if (ret != KERN_SUCCESS) {
12418 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12419
12420 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12421 "Failed to map mach header of kc fileset with error %d", ret);
12422 return kOSKextReturnInvalidArgument;
12423 }
12424
12425 if (slidep) {
12426 /* Verify that it's an MH_FILESET */
12427 if (base_mh->filetype != MH_FILESET) {
12428 printf("Kext Log: mapKCTextSegment mach header filetype"
12429 " is not an MH_FILESET, it is %x", base_mh->filetype);
12430
12431 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12432 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12433
12434 /* Unmap the mach header */
12435 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12436 return kOSKextReturnInvalidArgument;
12437 }
12438 }
12439
12440 /* Map the remaining pages of load commands */
12441 if (base_mh->sizeofcmds > mach_header_map_size) {
12442 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12443 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12444
12445 /* Map the load commands */
12446 ret = vm_map_kcfileset_segment(
12447 &load_command_addr, load_command_map_size,
12448 (memory_object_control_t)control, file_offset + mach_header_map_size,
12449 (VM_PROT_READ | VM_PROT_WRITE));
12450
12451 if (ret != KERN_SUCCESS) {
12452 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12453 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12454 "Failed to map load commands of kc fileset with error %d", ret);
12455
12456 /* Unmap the mach header */
12457 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12458 return kOSKextReturnInvalidArgument;
12459 }
12460 }
12461
12462 kernel_segment_command_t *text_seg;
12463 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12464
12465 /* Calculate the slide and vm addr of mach header */
12466 if (slidep) {
12467 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12468 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12469 }
12470
12471 /* Cache the text segment size and file offset before unmapping */
12472 vm_map_offset_t text_segment_size = text_seg->vmsize;
12473 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12474 vm_prot_t text_maxprot = text_seg->maxprot;
12475
12476 /* Unmap the first page and loadcommands and map the text segment */
12477 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12478 assert(ret == KERN_SUCCESS);
12479
12480 if (load_command_map_size) {
12481 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12482 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12483 assert(ret == KERN_SUCCESS);
12484 }
12485
12486 /* Map the text segment at actual vm addr specified in fileset */
12487 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12488 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12489 if (ret != KERN_SUCCESS) {
12490 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12491 "Failed to map Text segment of kc fileset with error %d", ret);
12492 return kOSKextReturnInvalidArgument;
12493 }
12494
12495 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12496 return 0;
12497 }
12498
12499 /*********************************************************************
12500 * Assumes sKextLock is held.
12501 *********************************************************************/
12502 /* static */
12503 OSReturn
12504 OSKext::protectKCFileSet(
12505 kernel_mach_header_t *mh,
12506 kc_kind_t type)
12507 {
12508 vm_map_t kext_map = g_kext_map;
12509 kernel_segment_command_t * seg = NULL;
12510 vm_map_offset_t start = 0;
12511 vm_map_offset_t end = 0;
12512 OSReturn ret = 0;
12513
12514 /* Set VM permissions */
12515 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12516 while (seg) {
12517 start = round_page(seg->vmaddr);
12518 end = trunc_page(seg->vmaddr + seg->vmsize);
12519
12520 /*
12521 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12522 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12523 * for the Aux KC as well.
12524 */
12525 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12526 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12527 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12528 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12529 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12530 ret = OSKext_protect((kernel_mach_header_t *)mh,
12531 kext_map, start, end, seg->maxprot, TRUE, type);
12532 if (ret != KERN_SUCCESS) {
12533 printf("OSKext protect failed with error %d", ret);
12534 return kOSKextReturnInvalidArgument;
12535 }
12536
12537 ret = OSKext_protect((kernel_mach_header_t *)mh,
12538 kext_map, start, end, seg->initprot, FALSE, type);
12539 if (ret != KERN_SUCCESS) {
12540 printf("OSKext protect failed with error %d", ret);
12541 return kOSKextReturnInvalidArgument;
12542 }
12543
12544 ret = OSKext_wire((kernel_mach_header_t *)mh,
12545 kext_map, start, end, seg->initprot, FALSE, type);
12546 if (ret != KERN_SUCCESS) {
12547 printf("OSKext wire failed with error %d", ret);
12548 return kOSKextReturnInvalidArgument;
12549 }
12550 }
12551
12552 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12553 }
12554
12555 return 0;
12556 }
12557
12558 /*********************************************************************
12559 * Assumes sKextLock is held.
12560 *********************************************************************/
12561 /* static */
12562 void
12563 OSKext::freeKCFileSetcontrol(void)
12564 {
12565 PE_reset_all_kc_vp();
12566 }
12567
12568 /*********************************************************************
12569 * Assumes sKextLock is held.
12570 *
12571 * resetKCFileSetSegments: Kext start function expects data segment to
12572 * be pristine on every load, unmap the dirty segments on unload and
12573 * remap them from FileSet on disk. Remap all segments of kext since
12574 * fixups are done per kext and not per segment.
12575 *********************************************************************/
12576 OSReturn
12577 OSKext::resetKCFileSetSegments(void)
12578 {
12579 kernel_segment_command_t *seg = NULL;
12580 kernel_segment_command_t *text_seg;
12581 uint32_t text_fileoff;
12582 kernel_mach_header_t *k_mh = NULL;
12583 uintptr_t slide;
12584 struct vnode *vp = NULL;
12585 void *fileset_control = NULL;
12586 bool pageable = (kc_type == KCKindPageable);
12587 OSReturn err;
12588 kern_return_t kr;
12589
12590 /* Check the vnode reference is still available */
12591 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12592 if (vp == NULL) {
12593 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12594 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12595 return kOSKextReturnInternalError;
12596 }
12597
12598 fileset_control = ubc_getobject(vp, 0);
12599 assert(fileset_control != NULL);
12600
12601 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12602 "Kext %s resetting all segments", getIdentifierCString());
12603
12604 k_mh = (kernel_mach_header_t *)kmod_info->address;
12605 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12606 text_fileoff = text_seg->fileoff;
12607 slide = PE_get_kc_slide(kc_type);
12608
12609 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12610 while (seg) {
12611 if (seg->vmsize == 0) {
12612 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12613 continue;
12614 }
12615
12616 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12617 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12618 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12619 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12620 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12621 continue;
12622 }
12623
12624 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12625 assert(kr == KERN_SUCCESS);
12626 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12627 }
12628
12629 /* Unmap the text segment */
12630 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12631 assert(kr == KERN_SUCCESS);
12632
12633 /* Map all the segments of the kext */
12634 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12635 if (err) {
12636 panic("Could not reset segments of a mapped kext, error %x", err);
12637 }
12638
12639 /* Update address in kmod_info, since it has been reset */
12640 if (kmod_info->address) {
12641 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12642 }
12643
12644 return 0;
12645 }
12646
12647 /*********************************************************************
12648 * Mechanism to track all segment mapping while mapping KC fileset.
12649 *********************************************************************/
12650
12651 struct kcfileset_map_entry {
12652 vm_map_offset_t me_start;
12653 vm_map_offset_t me_size;
12654 };
12655
12656 struct kcfileset_map_entry_list {
12657 int kme_list_count;
12658 int kme_list_index;
12659 struct kcfileset_map_entry kme_list[];
12660 };
12661
12662 #define KCFILESET_MAP_ENTRY_MAX (16380)
12663
12664 static void *
12665 allocate_kcfileset_map_entry_list(void)
12666 {
12667 struct kcfileset_map_entry_list *entry_list;
12668
12669 entry_list = (struct kcfileset_map_entry_list *)kalloc(sizeof(struct kcfileset_map_entry_list) +
12670 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12671
12672 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12673 entry_list->kme_list_index = 0;
12674 return entry_list;
12675 }
12676
12677 static void
12678 add_kcfileset_map_entry(
12679 void *map_entry_list,
12680 vm_map_offset_t start,
12681 vm_map_offset_t size)
12682 {
12683 if (map_entry_list == NULL) {
12684 return;
12685 }
12686
12687 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12688
12689 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12690 panic("Ran out of map kc fileset list\n");
12691 }
12692
12693 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12694 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12695
12696 entry_list->kme_list_index++;
12697 }
12698
12699 static void
12700 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12701 void *map_entry_list,
12702 boolean_t unmap_entries,
12703 bool pageable)
12704 {
12705 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12706
12707 if (unmap_entries) {
12708 for (int i = 0; i < entry_list->kme_list_index; i++) {
12709 kern_return_t ret;
12710 ret = vm_unmap_kcfileset_segment(
12711 &(entry_list->kme_list[i].me_start),
12712 entry_list->kme_list[i].me_size);
12713 assert(ret == KERN_SUCCESS);
12714 }
12715
12716 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
12717 }
12718
12719 kfree(entry_list, sizeof(struct kcfileset_map_entry_list) +
12720 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12721 }
12722
12723 /*********************************************************************
12724 * Mechanism to map kext segment.
12725 *********************************************************************/
12726
12727 kern_return_t
12728 vm_map_kcfileset_segment(
12729 vm_map_offset_t *start,
12730 vm_map_offset_t size,
12731 void *control,
12732 vm_object_offset_t fileoffset,
12733 vm_prot_t max_prot)
12734 {
12735 vm_map_kernel_flags_t vmk_flags;
12736 vmk_flags.vmkf_no_copy_on_read = 1;
12737 vmk_flags.vmkf_cs_enforcement = 0;
12738 vmk_flags.vmkf_cs_enforcement_override = 1;
12739 kern_return_t ret;
12740
12741 /* Add Write to max prot to allow fixups */
12742 max_prot = max_prot | VM_PROT_WRITE;
12743
12744 /*
12745 * Map the segments from file as COPY mappings to
12746 * make sure changes on disk to the file does not affect
12747 * mapped segments.
12748 */
12749 ret = vm_map_enter_mem_object_control(
12750 g_kext_map,
12751 start,
12752 size,
12753 (mach_vm_offset_t)0,
12754 VM_FLAGS_FIXED,
12755 vmk_flags,
12756 VM_KERN_MEMORY_OSKEXT,
12757 (memory_object_control_t)control,
12758 fileoffset,
12759 TRUE, /* copy */
12760 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12761 VM_INHERIT_NONE);
12762
12763 return ret;
12764 }
12765
12766 kern_return_t
12767 vm_unmap_kcfileset_segment(
12768 vm_map_offset_t *start,
12769 vm_map_offset_t size)
12770 {
12771 return mach_vm_deallocate(g_kext_map, *start, size);
12772 }
12773
12774 #endif //(__x86_64__) || defined(__i386__)
12775
12776 /*********************************************************************
12777 * Assumes sKextLock is held.
12778 *********************************************************************/
12779 /* static */
12780 OSReturn
12781 OSKext::validateKCFileSetUUID(
12782 OSDictionary *infoDict,
12783 kc_kind_t type)
12784 {
12785 OSReturn ret = kOSReturnSuccess;
12786
12787 if (!kernelcache_uuid_valid) {
12788 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12789 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12790 ret = kOSKextReturnInvalidArgument;
12791 goto finish;
12792 }
12793 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12794 if (ret != 0) {
12795 goto finish;
12796 }
12797
12798 #if defined(__x86_64__) || defined(__i386__)
12799 /* Check if the Aux KC is prelinked to correct Pageable KC */
12800 if (type == KCKindAuxiliary) {
12801 if (!pageablekc_uuid_valid) {
12802 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12803 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12804 ret = kOSKextReturnInvalidArgument;
12805 goto finish;
12806 }
12807 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12808 if (ret != 0) {
12809 goto finish;
12810 }
12811 }
12812 #endif //(__x86_64__) || defined(__i386__)
12813
12814 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12815 finish:
12816 return ret;
12817 }
12818
12819 /*********************************************************************
12820 * Assumes sKextLock is held.
12821 *********************************************************************/
12822 /* static */
12823 OSReturn
12824 OSKext::validateKCUUIDfromPrelinkInfo(
12825 uuid_t *loaded_kcuuid,
12826 kc_kind_t type,
12827 OSDictionary *infoDict,
12828 const char *uuid_key)
12829 {
12830 /* extract the UUID from the dictionary */
12831 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12832 if (!prelinkinfoKCUUID) {
12833 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12834 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12835 return kOSKextReturnInvalidArgument;
12836 }
12837
12838 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12839 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12840 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12841 return kOSKextReturnInvalidArgument;
12842 }
12843
12844 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
12845 prelinkinfoKCUUID->getLength())) {
12846 OSData *info_dict_uuid;
12847 uuid_string_t info_dict_uuid_str = {};
12848 uuid_string_t expected_uuid_str = {};
12849 uuid_string_t given_uuid_str = {};
12850 uuid_t given_uuid;
12851
12852 /* extract the KC UUID from the dictionary */
12853 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
12854 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
12855 uuid_t tmp_uuid;
12856 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
12857 uuid_unparse(tmp_uuid, info_dict_uuid_str);
12858 }
12859
12860 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
12861 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
12862 uuid_unparse(given_uuid, given_uuid_str);
12863
12864 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12865 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12866 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12867 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12868 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12869 if (type == KCKindPageable && sPanicOnKCMismatch) {
12870 panic("System KC UUID %s linked against %s, but %s is loaded",
12871 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
12872 }
12873 return kOSKextReturnInvalidArgument;
12874 }
12875
12876 return 0;
12877 }
12878
12879 /*********************************************************************
12880 * Assumes sKextLock is held.
12881 *********************************************************************/
12882 /* static */
12883 OSReturn
12884 OSKext::dispatchResource(OSDictionary * requestDict)
12885 {
12886 OSReturn result = kOSReturnError;
12887 OSSharedPtr<OSDictionary> callbackRecord;
12888 OSNumber * requestTag = NULL; // do not release
12889 OSNumber * requestResult = NULL; // do not release
12890 OSData * dataObj = NULL; // do not release
12891 uint32_t dataLength = 0;
12892 const void * dataPtr = NULL; // do not free
12893 OSData * callbackWrapper = NULL; // do not release
12894 OSKextRequestResourceCallback callback = NULL;
12895 OSData * contextWrapper = NULL; // do not release
12896 void * context = NULL; // do not free
12897 OSSharedPtr<OSKext> callbackKext;
12898
12899 /* Get the args from the request. Right now we need the tag
12900 * to look up the callback record, and the result for invoking the callback.
12901 */
12902 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12903 kKextRequestArgumentRequestTagKey));
12904 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12905 kKextRequestArgumentResultKey));
12906 if (!requestTag || !requestResult) {
12907 result = kOSKextReturnInvalidArgument;
12908 goto finish;
12909 }
12910
12911 /* Look for a callback record matching this request's tag.
12912 */
12913 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
12914 if (result != kOSReturnSuccess) {
12915 goto finish;
12916 }
12917
12918 /*****
12919 * Get the context pointer of the callback record (if there is one).
12920 */
12921 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord.get(),
12922 kKextRequestArgumentContextKey));
12923 context = _OSKextExtractPointer(contextWrapper);
12924 if (contextWrapper && !context) {
12925 goto finish;
12926 }
12927
12928 callbackWrapper = OSDynamicCast(OSData,
12929 _OSKextGetRequestArgument(callbackRecord.get(),
12930 kKextRequestArgumentCallbackKey));
12931 callback = _OSKextExtractCallbackPointer(callbackWrapper);
12932 if (!callback) {
12933 goto finish;
12934 }
12935
12936 /* Check for a data obj. We might not have one and that's ok, that means
12937 * we didn't find the requested resource, and we still have to tell the
12938 * caller that via the callback.
12939 */
12940 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
12941 kKextRequestArgumentValueKey));
12942 if (dataObj) {
12943 dataPtr = dataObj->getBytesNoCopy();
12944 dataLength = dataObj->getLength();
12945 }
12946
12947 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12948 if (!callbackKext) {
12949 OSKextLog(/* kext */ NULL,
12950 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12951 "Can't invoke callback for resource request; ");
12952 goto finish;
12953 }
12954 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12955 OSKextLog(/* kext */ NULL,
12956 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12957 "Can't invoke kext resource callback; ");
12958 goto finish;
12959 }
12960
12961 (void)callback(requestTag->unsigned32BitValue(),
12962 (OSReturn)requestResult->unsigned32BitValue(),
12963 dataPtr, dataLength, context);
12964
12965 result = kOSReturnSuccess;
12966
12967 finish:
12968 return result;
12969 }
12970
12971 /*********************************************************************
12972 * Assumes sKextLock is held.
12973 *********************************************************************/
12974 /* static */
12975 OSReturn
12976 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
12977 {
12978 OSSharedPtr<OSDictionary> missingIDs;
12979 OSArray *bundleIDList = NULL; // do not release
12980
12981 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
12982 requestDict, kKextRequestArgumentMissingBundleIDs));
12983 if (!bundleIDList) {
12984 return kOSKextReturnInvalidArgument;
12985 }
12986
12987 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
12988 if (!missingIDs) {
12989 return kOSKextReturnNoMemory;
12990 }
12991
12992 uint32_t count, i;
12993 count = bundleIDList->getCount();
12994 for (i = 0; i < count; i++) {
12995 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
12996 if (thisID) {
12997 missingIDs->setObject(thisID, kOSBooleanFalse);
12998 }
12999 }
13000
13001 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13002
13003 return kOSReturnSuccess;
13004 }
13005
13006 /*********************************************************************
13007 * Assumes sKextLock is held.
13008 *********************************************************************/
13009 /* static */
13010 OSReturn
13011 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13012 {
13013 bool loadable = true;
13014 if (!kextIdentifier) {
13015 return kOSKextReturnInvalidArgument;
13016 }
13017
13018 if (requestDict) {
13019 OSBoolean *loadableArg;
13020 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13021 requestDict, kKextRequestArgumentBundleAvailability));
13022 /* If we find the "Bundle Available" arg, and it's false, then
13023 * mark the bundle ID as _not_ loadable
13024 */
13025 if (loadableArg && !loadableArg->getValue()) {
13026 loadable = false;
13027 }
13028 }
13029
13030 if (!sNonLoadableKextsByID) {
13031 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13032 }
13033
13034 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13035
13036 OSKextLog(/* kext */ NULL,
13037 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13038 "KextLog: AuxKC bundle %s marked as %s",
13039 kextIdentifier->getCStringNoCopy(),
13040 (loadable ? "loadable" : "NOT loadable"));
13041
13042 return kOSReturnSuccess;
13043 }
13044
13045 /*********************************************************************
13046 *********************************************************************/
13047 /* static */
13048 void
13049 OSKext::invokeRequestCallback(
13050 OSDictionary * callbackRecord,
13051 OSReturn callbackResult)
13052 {
13053 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
13054 OSSharedPtr<OSNumber> resultNum;
13055
13056 if (!predicate) {
13057 goto finish;
13058 }
13059
13060 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13061 8 * sizeof(callbackResult));
13062 if (!resultNum) {
13063 goto finish;
13064 }
13065
13066 /* Insert the result into the callback record and dispatch it as if it
13067 * were the reply coming down from user space.
13068 */
13069 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
13070 resultNum.get());
13071
13072 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13073 /* This removes the pending callback record.
13074 */
13075 OSKext::dispatchResource(callbackRecord);
13076 }
13077
13078 finish:
13079 return;
13080 }
13081
13082 /*********************************************************************
13083 * Assumes sKextLock is held.
13084 *********************************************************************/
13085 /* static */
13086 OSReturn
13087 OSKext::cancelRequest(
13088 OSKextRequestTag requestTag,
13089 void ** contextOut)
13090 {
13091 OSReturn result = kOSKextReturnNoMemory;
13092 OSSharedPtr<OSDictionary> callbackRecord;
13093 OSData * contextWrapper = NULL; // do not release
13094
13095 IORecursiveLockLock(sKextLock);
13096 result = OSKext::dequeueCallbackForRequestTag(requestTag,
13097 callbackRecord);
13098 IORecursiveLockUnlock(sKextLock);
13099
13100 if (result == kOSReturnSuccess && contextOut) {
13101 contextWrapper = OSDynamicCast(OSData,
13102 _OSKextGetRequestArgument(callbackRecord.get(),
13103 kKextRequestArgumentContextKey));
13104 *contextOut = _OSKextExtractPointer(contextWrapper);
13105 }
13106
13107 return result;
13108 }
13109
13110 /*********************************************************************
13111 * Assumes sKextLock is held.
13112 *********************************************************************/
13113 void
13114 OSKext::invokeOrCancelRequestCallbacks(
13115 OSReturn callbackResult,
13116 bool invokeFlag)
13117 {
13118 unsigned int count, i;
13119
13120 count = sRequestCallbackRecords->getCount();
13121 if (!count) {
13122 goto finish;
13123 }
13124
13125 i = count - 1;
13126 do {
13127 OSDictionary * request = OSDynamicCast(OSDictionary,
13128 sRequestCallbackRecords->getObject(i));
13129
13130 if (!request) {
13131 continue;
13132 }
13133 OSData * callbackWrapper = OSDynamicCast(OSData,
13134 _OSKextGetRequestArgument(request,
13135 kKextRequestArgumentCallbackKey));
13136
13137 if (!callbackWrapper) {
13138 sRequestCallbackRecords->removeObject(i);
13139 continue;
13140 }
13141
13142 vm_address_t callbackAddress = (vm_address_t)
13143 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13144
13145 if ((kmod_info->address <= callbackAddress) &&
13146 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13147 if (invokeFlag) {
13148 /* This removes the callback record.
13149 */
13150 invokeRequestCallback(request, callbackResult);
13151 } else {
13152 sRequestCallbackRecords->removeObject(i);
13153 }
13154 }
13155 } while (i--);
13156
13157 finish:
13158 return;
13159 }
13160
13161 /*********************************************************************
13162 * Assumes sKextLock is held.
13163 *********************************************************************/
13164 uint32_t
13165 OSKext::countRequestCallbacks(void)
13166 {
13167 uint32_t result = 0;
13168 unsigned int count, i;
13169
13170 count = sRequestCallbackRecords->getCount();
13171 if (!count) {
13172 goto finish;
13173 }
13174
13175 i = count - 1;
13176 do {
13177 OSDictionary * request = OSDynamicCast(OSDictionary,
13178 sRequestCallbackRecords->getObject(i));
13179
13180 if (!request) {
13181 continue;
13182 }
13183 OSData * callbackWrapper = OSDynamicCast(OSData,
13184 _OSKextGetRequestArgument(request,
13185 kKextRequestArgumentCallbackKey));
13186
13187 if (!callbackWrapper) {
13188 continue;
13189 }
13190
13191 vm_address_t callbackAddress = (vm_address_t)
13192 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13193
13194 if ((kmod_info->address <= callbackAddress) &&
13195 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13196 result++;
13197 }
13198 } while (i--);
13199
13200 finish:
13201 return result;
13202 }
13203
13204 /*********************************************************************
13205 *********************************************************************/
13206 static OSReturn
13207 _OSKextCreateRequest(
13208 const char * predicate,
13209 OSSharedPtr<OSDictionary> & requestR)
13210 {
13211 OSReturn result = kOSKextReturnNoMemory;
13212 OSSharedPtr<OSDictionary> request;
13213
13214 request = OSDictionary::withCapacity(2);
13215 if (!request) {
13216 goto finish;
13217 }
13218 result = _OSDictionarySetCStringValue(request.get(),
13219 kKextRequestPredicateKey, predicate);
13220 if (result != kOSReturnSuccess) {
13221 goto finish;
13222 }
13223 result = kOSReturnSuccess;
13224
13225 finish:
13226 if (result == kOSReturnSuccess) {
13227 requestR = os::move(request);
13228 }
13229
13230 return result;
13231 }
13232
13233 /*********************************************************************
13234 *********************************************************************/
13235 static OSString *
13236 _OSKextGetRequestPredicate(OSDictionary * requestDict)
13237 {
13238 return OSDynamicCast(OSString,
13239 requestDict->getObject(kKextRequestPredicateKey));
13240 }
13241
13242 /*********************************************************************
13243 *********************************************************************/
13244 static OSObject *
13245 _OSKextGetRequestArgument(
13246 OSDictionary * requestDict,
13247 const char * argName)
13248 {
13249 OSDictionary * args = OSDynamicCast(OSDictionary,
13250 requestDict->getObject(kKextRequestArgumentsKey));
13251 if (args) {
13252 return args->getObject(argName);
13253 }
13254 return NULL;
13255 }
13256
13257 /*********************************************************************
13258 *********************************************************************/
13259 static bool
13260 _OSKextSetRequestArgument(
13261 OSDictionary * requestDict,
13262 const char * argName,
13263 OSObject * value)
13264 {
13265 OSDictionary * args = OSDynamicCast(OSDictionary,
13266 requestDict->getObject(kKextRequestArgumentsKey));
13267 OSSharedPtr<OSDictionary> newArgs;
13268 if (!args) {
13269 newArgs = OSDictionary::withCapacity(2);
13270 args = newArgs.get();
13271 if (!args) {
13272 goto finish;
13273 }
13274 requestDict->setObject(kKextRequestArgumentsKey, args);
13275 }
13276 if (args) {
13277 return args->setObject(argName, value);
13278 }
13279 finish:
13280 return false;
13281 }
13282
13283 /*********************************************************************
13284 *********************************************************************/
13285 static void *
13286 _OSKextExtractPointer(OSData * wrapper)
13287 {
13288 void * result = NULL;
13289 const void * resultPtr = NULL;
13290
13291 if (!wrapper) {
13292 goto finish;
13293 }
13294 resultPtr = wrapper->getBytesNoCopy();
13295 result = *(void **)resultPtr;
13296 finish:
13297 return result;
13298 }
13299
13300 /*********************************************************************
13301 *********************************************************************/
13302 static OSKextRequestResourceCallback
13303 _OSKextExtractCallbackPointer(OSData * wrapper)
13304 {
13305 OSKextRequestResourceCallback result = NULL;
13306 const void * resultPtr = NULL;
13307
13308 if (!wrapper) {
13309 goto finish;
13310 }
13311 resultPtr = wrapper->getBytesNoCopy();
13312 result = *(OSKextRequestResourceCallback *)resultPtr;
13313 finish:
13314 return result;
13315 }
13316
13317
13318 /*********************************************************************
13319 *********************************************************************/
13320 static OSReturn
13321 _OSDictionarySetCStringValue(
13322 OSDictionary * dict,
13323 const char * cKey,
13324 const char * cValue)
13325 {
13326 OSReturn result = kOSKextReturnNoMemory;
13327 OSSharedPtr<const OSSymbol> key;
13328 OSSharedPtr<OSString> value;
13329
13330 key = OSSymbol::withCString(cKey);
13331 value = OSString::withCString(cValue);
13332 if (!key || !value) {
13333 goto finish;
13334 }
13335 if (dict->setObject(key.get(), value.get())) {
13336 result = kOSReturnSuccess;
13337 }
13338
13339 finish:
13340 return result;
13341 }
13342
13343 /*********************************************************************
13344 *********************************************************************/
13345 static bool
13346 _OSArrayContainsCString(
13347 OSArray * array,
13348 const char * cString)
13349 {
13350 bool result = false;
13351 OSSharedPtr<const OSSymbol> symbol;
13352 uint32_t count, i;
13353
13354 if (!array || !cString) {
13355 goto finish;
13356 }
13357
13358 symbol = OSSymbol::withCStringNoCopy(cString);
13359 if (!symbol) {
13360 goto finish;
13361 }
13362
13363 count = array->getCount();
13364 for (i = 0; i < count; i++) {
13365 OSObject * thisObject = array->getObject(i);
13366 if (symbol->isEqualTo(thisObject)) {
13367 result = true;
13368 goto finish;
13369 }
13370 }
13371
13372 finish:
13373 return result;
13374 }
13375
13376 #if CONFIG_KXLD
13377 /*********************************************************************
13378 * We really only care about boot / system start up related kexts.
13379 * We return true if we're less than REBUILD_MAX_TIME since start up,
13380 * otherwise return false.
13381 *********************************************************************/
13382 bool
13383 _OSKextInPrelinkRebuildWindow(void)
13384 {
13385 static bool outside_the_window = false;
13386 AbsoluteTime my_abstime;
13387 UInt64 my_ns;
13388 SInt32 my_secs;
13389
13390 if (outside_the_window) {
13391 return false;
13392 }
13393 clock_get_uptime(&my_abstime);
13394 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13395 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13396 if (my_secs > REBUILD_MAX_TIME) {
13397 outside_the_window = true;
13398 return false;
13399 }
13400 return true;
13401 }
13402 #endif /* CONFIG_KXLD */
13403
13404 /*********************************************************************
13405 *********************************************************************/
13406 bool
13407 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13408 {
13409 int unLoadedCount, i;
13410 bool result = false;
13411
13412 IORecursiveLockLock(sKextLock);
13413
13414 if (sUnloadedPrelinkedKexts == NULL) {
13415 goto finish;
13416 }
13417 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13418 if (unLoadedCount == 0) {
13419 goto finish;
13420 }
13421
13422 for (i = 0; i < unLoadedCount; i++) {
13423 const OSSymbol * myBundleID; // do not release
13424
13425 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13426 if (!myBundleID) {
13427 continue;
13428 }
13429 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13430 result = true;
13431 break;
13432 }
13433 }
13434 finish:
13435 IORecursiveLockUnlock(sKextLock);
13436 return result;
13437 }
13438
13439 #if PRAGMA_MARK
13440 #pragma mark Personalities (IOKit Drivers)
13441 #endif
13442 /*********************************************************************
13443 *********************************************************************/
13444 /* static */
13445 OSSharedPtr<OSArray>
13446 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13447 {
13448 OSSharedPtr<OSArray> result;
13449 OSSharedPtr<OSCollectionIterator> kextIterator;
13450 OSSharedPtr<OSArray> personalities;
13451
13452 OSString * kextID = NULL; // do not release
13453 OSKext * theKext = NULL; // do not release
13454
13455 IORecursiveLockLock(sKextLock);
13456
13457 /* Let's conservatively guess that any given kext has around 3
13458 * personalities for now.
13459 */
13460 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13461 if (!result) {
13462 goto finish;
13463 }
13464
13465 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
13466 if (!kextIterator) {
13467 goto finish;
13468 }
13469
13470 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
13471 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
13472 if (theKext->flags.requireExplicitLoad) {
13473 OSKextLog(theKext,
13474 kOSKextLogDebugLevel |
13475 kOSKextLogLoadFlag,
13476 "Kext %s requires an explicit kextload; "
13477 "omitting its personalities.",
13478 theKext->getIdentifierCString());
13479 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
13480 personalities = theKext->copyPersonalitiesArray();
13481 if (!personalities) {
13482 continue;
13483 }
13484 result->merge(personalities.get());
13485 } else {
13486 // xxx - check for better place to put this log msg
13487 OSKextLog(theKext,
13488 kOSKextLogWarningLevel |
13489 kOSKextLogLoadFlag,
13490 "Kext %s is not loadable during safe boot; "
13491 "omitting its personalities.",
13492 theKext->getIdentifierCString());
13493 }
13494 }
13495
13496 finish:
13497 IORecursiveLockUnlock(sKextLock);
13498
13499 return result;
13500 }
13501
13502 /*********************************************************************
13503 *********************************************************************/
13504 /* static */
13505 void
13506 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13507 {
13508 int numPersonalities = 0;
13509
13510 OSKextLog(/* kext */ NULL,
13511 kOSKextLogStepLevel |
13512 kOSKextLogLoadFlag,
13513 "Sending all eligible registered kexts' personalities "
13514 "to the IOCatalogue %s.",
13515 startMatching ? "and starting matching" : "but not starting matching");
13516
13517 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
13518 /* filterSafeBootFlag */ true);
13519
13520 if (personalities) {
13521 gIOCatalogue->addDrivers(personalities.get(), startMatching);
13522 numPersonalities = personalities->getCount();
13523 }
13524
13525 OSKextLog(/* kext */ NULL,
13526 kOSKextLogStepLevel |
13527 kOSKextLogLoadFlag,
13528 "%d kext personalit%s sent to the IOCatalogue; %s.",
13529 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13530 startMatching ? "matching started" : "matching not started");
13531 return;
13532 }
13533
13534 /*********************************************************************
13535 * Do not make a deep copy, just convert the IOKitPersonalities dict
13536 * to an array for sending to the IOCatalogue.
13537 *********************************************************************/
13538 OSSharedPtr<OSArray>
13539 OSKext::copyPersonalitiesArray(void)
13540 {
13541 OSSharedPtr<OSArray> result;
13542 OSDictionary * personalities = NULL; // do not release
13543 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
13544
13545 OSString * personalityName = NULL; // do not release
13546 OSString * personalityBundleIdentifier = NULL; // do not release
13547
13548 personalities = OSDynamicCast(OSDictionary,
13549 getPropertyForHostArch(kIOKitPersonalitiesKey));
13550 if (!personalities) {
13551 goto finish;
13552 }
13553
13554 result = OSArray::withCapacity(personalities->getCount());
13555 if (!result) {
13556 goto finish;
13557 }
13558
13559 personalitiesIterator =
13560 OSCollectionIterator::withCollection(personalities);
13561 if (!personalitiesIterator) {
13562 goto finish;
13563 }
13564 while ((personalityName = OSDynamicCast(OSString,
13565 personalitiesIterator->getNextObject()))) {
13566 OSDictionary * personality = OSDynamicCast(OSDictionary,
13567 personalities->getObject(personalityName));
13568
13569 /******
13570 * If the personality doesn't have a CFBundleIdentifier, or if it
13571 * differs from the kext's, insert the kext's ID so we can find it.
13572 * The publisher ID is used to remove personalities from bundles
13573 * correctly.
13574 */
13575 personalityBundleIdentifier = OSDynamicCast(OSString,
13576 personality->getObject(kCFBundleIdentifierKey));
13577
13578 if (!personalityBundleIdentifier) {
13579 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13580 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13581 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
13582 }
13583
13584 result->setObject(personality);
13585 }
13586
13587 finish:
13588 return result;
13589 }
13590
13591 /*********************************************************************
13592 * Might want to change this to a bool return?
13593 *********************************************************************/
13594 OSReturn
13595 OSKext::sendPersonalitiesToCatalog(
13596 bool startMatching,
13597 OSArray * personalityNames)
13598 {
13599 OSReturn result = kOSReturnSuccess;
13600 OSSharedPtr<OSArray> personalitiesToSend;
13601 OSDictionary * kextPersonalities = NULL; // do not release
13602 int count, i;
13603
13604 if (!sLoadEnabled) {
13605 OSKextLog(this,
13606 kOSKextLogErrorLevel |
13607 kOSKextLogLoadFlag,
13608 "Kext loading is disabled (attempt to start matching for kext %s).",
13609 getIdentifierCString());
13610 result = kOSKextReturnDisabled;
13611 goto finish;
13612 }
13613
13614 if (sSafeBoot && !isLoadableInSafeBoot()) {
13615 OSKextLog(this,
13616 kOSKextLogErrorLevel |
13617 kOSKextLogLoadFlag,
13618 "Kext %s is not loadable during safe boot; "
13619 "not sending personalities to the IOCatalogue.",
13620 getIdentifierCString());
13621 result = kOSKextReturnNotLoadable;
13622 goto finish;
13623 }
13624
13625 if (!personalityNames || !personalityNames->getCount()) {
13626 personalitiesToSend = copyPersonalitiesArray();
13627 } else {
13628 kextPersonalities = OSDynamicCast(OSDictionary,
13629 getPropertyForHostArch(kIOKitPersonalitiesKey));
13630 if (!kextPersonalities || !kextPersonalities->getCount()) {
13631 // not an error
13632 goto finish;
13633 }
13634 personalitiesToSend = OSArray::withCapacity(0);
13635 if (!personalitiesToSend) {
13636 result = kOSKextReturnNoMemory;
13637 goto finish;
13638 }
13639 count = personalityNames->getCount();
13640 for (i = 0; i < count; i++) {
13641 OSString * name = OSDynamicCast(OSString,
13642 personalityNames->getObject(i));
13643 if (!name) {
13644 continue;
13645 }
13646 OSDictionary * personality = OSDynamicCast(OSDictionary,
13647 kextPersonalities->getObject(name));
13648 if (personality) {
13649 personalitiesToSend->setObject(personality);
13650 }
13651 }
13652 }
13653 if (personalitiesToSend) {
13654 unsigned numPersonalities = personalitiesToSend->getCount();
13655 OSKextLog(this,
13656 kOSKextLogStepLevel |
13657 kOSKextLogLoadFlag,
13658 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13659 getIdentifierCString(),
13660 numPersonalities,
13661 numPersonalities > 1 ? "ies" : "y",
13662 startMatching ? " and starting matching" : " but not starting matching");
13663 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
13664 }
13665 finish:
13666 return result;
13667 }
13668
13669 /*********************************************************************
13670 * xxx - We should allow removing the kext's declared personalities,
13671 * xxx - even with other bundle identifiers.
13672 *********************************************************************/
13673 void
13674 OSKext::removePersonalitiesFromCatalog(void)
13675 {
13676 OSSharedPtr<OSDictionary> personality;
13677
13678 personality = OSDictionary::withCapacity(1);
13679 if (!personality) {
13680 goto finish;
13681 }
13682 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
13683
13684 OSKextLog(this,
13685 kOSKextLogStepLevel |
13686 kOSKextLogLoadFlag,
13687 "Kext %s removing all personalities naming it from the IOCatalogue.",
13688 getIdentifierCString());
13689
13690 /* Have the IOCatalog remove all personalities matching this kext's
13691 * bundle ID and trigger matching anew.
13692 */
13693 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
13694
13695 finish:
13696 return;
13697 }
13698
13699
13700 #if PRAGMA_MARK
13701 #pragma mark Logging
13702 #endif
13703 /*********************************************************************
13704 * Do not call any function that takes sKextLock here!
13705 *********************************************************************/
13706 /* static */
13707 OSKextLogSpec
13708 OSKext::setUserSpaceLogFilter(
13709 OSKextLogSpec newUserLogFilter,
13710 bool captureFlag)
13711 {
13712 OSKextLogSpec result;
13713 bool allocError = false;
13714
13715 /* Do not call any function that takes sKextLoggingLock during
13716 * this critical block. That means do logging after.
13717 */
13718 IOLockLock(sKextLoggingLock);
13719
13720 result = sUserSpaceKextLogFilter;
13721 sUserSpaceKextLogFilter = newUserLogFilter;
13722
13723 if (newUserLogFilter && captureFlag &&
13724 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13725 // xxx - do some measurements for a good initial capacity?
13726 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13727 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13728
13729 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
13730 allocError = true;
13731 }
13732 }
13733
13734 IOLockUnlock(sKextLoggingLock);
13735
13736 /* If the config flag itself is changing, log the state change
13737 * going both ways, before setting up the user-space log arrays,
13738 * so that this is only logged in the kernel.
13739 */
13740 if (result != newUserLogFilter) {
13741 OSKextLog(/* kext */ NULL,
13742 kOSKextLogDebugLevel |
13743 kOSKextLogGeneralFlag,
13744 "User-space log flags changed from 0x%x to 0x%x.",
13745 result, newUserLogFilter);
13746 }
13747 if (allocError) {
13748 OSKextLog(/* kext */ NULL,
13749 kOSKextLogErrorLevel |
13750 kOSKextLogGeneralFlag,
13751 "Failed to allocate user-space log message arrays.");
13752 }
13753
13754 return result;
13755 }
13756
13757 /*********************************************************************
13758 * Do not call any function that takes sKextLock here!
13759 *********************************************************************/
13760 /* static */
13761 OSSharedPtr<OSArray>
13762 OSKext::clearUserSpaceLogFilter(void)
13763 {
13764 OSSharedPtr<OSArray> result;
13765 OSKextLogSpec oldLogFilter;
13766 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
13767
13768 /* Do not call any function that takes sKextLoggingLock during
13769 * this critical block. That means do logging after.
13770 */
13771 IOLockLock(sKextLoggingLock);
13772
13773 result = OSArray::withCapacity(2);
13774 if (result) {
13775 result->setObject(sUserSpaceLogSpecArray.get());
13776 result->setObject(sUserSpaceLogMessageArray.get());
13777 }
13778 sUserSpaceLogSpecArray.reset();
13779 sUserSpaceLogMessageArray.reset();
13780
13781 oldLogFilter = sUserSpaceKextLogFilter;
13782 sUserSpaceKextLogFilter = newLogFilter;
13783
13784 IOLockUnlock(sKextLoggingLock);
13785
13786 /* If the config flag itself is changing, log the state change
13787 * going both ways, after tearing down the user-space log
13788 * arrays, so this is only logged within the kernel.
13789 */
13790 if (oldLogFilter != newLogFilter) {
13791 OSKextLog(/* kext */ NULL,
13792 kOSKextLogDebugLevel |
13793 kOSKextLogGeneralFlag,
13794 "User-space log flags changed from 0x%x to 0x%x.",
13795 oldLogFilter, newLogFilter);
13796 }
13797
13798 return result;
13799 }
13800
13801
13802 /*********************************************************************
13803 * Do not call any function that takes sKextLock here!
13804 *********************************************************************/
13805 /* static */
13806 OSKextLogSpec
13807 OSKext::getUserSpaceLogFilter(void)
13808 {
13809 OSKextLogSpec result;
13810
13811 IOLockLock(sKextLoggingLock);
13812 result = sUserSpaceKextLogFilter;
13813 IOLockUnlock(sKextLoggingLock);
13814
13815 return result;
13816 }
13817
13818 /*********************************************************************
13819 * This function is called by OSMetaClass during kernel C++ setup.
13820 * Be careful what you access here; assume only OSKext::initialize()
13821 * has been called.
13822 *
13823 * Do not call any function that takes sKextLock here!
13824 *********************************************************************/
13825 #define VTRESET "\033[0m"
13826
13827 #define VTBOLD "\033[1m"
13828 #define VTUNDER "\033[4m"
13829
13830 #define VTRED "\033[31m"
13831 #define VTGREEN "\033[32m"
13832 #define VTYELLOW "\033[33m"
13833 #define VTBLUE "\033[34m"
13834 #define VTMAGENTA "\033[35m"
13835 #define VTCYAN "\033[36m"
13836
13837 inline const char *
13838 colorForFlags(OSKextLogSpec flags)
13839 {
13840 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13841
13842 switch (logLevel) {
13843 case kOSKextLogErrorLevel:
13844 return VTRED VTBOLD;
13845 case kOSKextLogWarningLevel:
13846 return VTRED;
13847 case kOSKextLogBasicLevel:
13848 return VTYELLOW VTUNDER;
13849 case kOSKextLogProgressLevel:
13850 return VTYELLOW;
13851 case kOSKextLogStepLevel:
13852 return VTGREEN;
13853 case kOSKextLogDetailLevel:
13854 return VTCYAN;
13855 case kOSKextLogDebugLevel:
13856 return VTMAGENTA;
13857 default:
13858 return ""; // white
13859 }
13860 }
13861
13862 inline bool
13863 logSpecMatch(
13864 OSKextLogSpec msgLogSpec,
13865 OSKextLogSpec logFilter)
13866 {
13867 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
13868 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
13869 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
13870
13871 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
13872 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
13873 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
13874
13875 /* Explicit messages always get logged.
13876 */
13877 if (msgLevel == kOSKextLogExplicitLevel) {
13878 return true;
13879 }
13880
13881 /* Warnings and errors are logged regardless of the flags.
13882 */
13883 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
13884 return true;
13885 }
13886
13887 /* A verbose message that isn't for a logging-enabled kext and isn't global
13888 * does *not* get logged.
13889 */
13890 if (!msgKextGlobal && !filterKextGlobal) {
13891 return false;
13892 }
13893
13894 /* Warnings and errors are logged regardless of the flags.
13895 * All other messages must fit the flags and
13896 * have a level at or below the filter.
13897 *
13898 */
13899 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
13900 return true;
13901 }
13902 return false;
13903 }
13904
13905 extern "C" {
13906 void
13907 OSKextLog(
13908 OSKext * aKext,
13909 OSKextLogSpec msgLogSpec,
13910 const char * format, ...)
13911 {
13912 va_list argList;
13913
13914 va_start(argList, format);
13915 OSKextVLog(aKext, msgLogSpec, format, argList);
13916 va_end(argList);
13917 }
13918
13919 void
13920 OSKextVLog(
13921 OSKext * aKext,
13922 OSKextLogSpec msgLogSpec,
13923 const char * format,
13924 va_list srcArgList)
13925 {
13926 extern int disableConsoleOutput;
13927
13928 bool logForKernel = false;
13929 bool logForUser = false;
13930 va_list argList;
13931 char stackBuffer[120];
13932 uint32_t length = 0;
13933 char * allocBuffer = NULL; // must kfree
13934 OSSharedPtr<OSNumber> logSpecNum;
13935 OSSharedPtr<OSString> logString;
13936 char * buffer = stackBuffer; // do not free
13937
13938 IOLockLock(sKextLoggingLock);
13939
13940 /* Set the kext/global bit in the message spec if we have no
13941 * kext or if the kext requests logging.
13942 */
13943 if (!aKext || aKext->flags.loggingEnabled) {
13944 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
13945 }
13946
13947 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
13948 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
13949 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
13950 }
13951
13952 if (!(logForKernel || logForUser)) {
13953 goto finish;
13954 }
13955
13956 /* No goto from here until past va_end()!
13957 */
13958 va_copy(argList, srcArgList);
13959 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
13960 va_end(argList);
13961
13962 if (length + 1 >= sizeof(stackBuffer)) {
13963 allocBuffer = (char *)kheap_alloc_tag(KHEAP_TEMP,
13964 length + 1, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
13965 if (!allocBuffer) {
13966 goto finish;
13967 }
13968
13969 /* No goto from here until past va_end()!
13970 */
13971 va_copy(argList, srcArgList);
13972 vsnprintf(allocBuffer, length + 1, format, argList);
13973 va_end(argList);
13974
13975 buffer = allocBuffer;
13976 }
13977
13978 /* If user space wants the log message, queue it up.
13979 */
13980 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
13981 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
13982 logString = OSString::withCString(buffer);
13983 if (logSpecNum && logString) {
13984 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
13985 sUserSpaceLogMessageArray->setObject(logString.get());
13986 }
13987 }
13988
13989 /* Always log messages from the kernel according to the kernel's
13990 * log flags.
13991 */
13992 if (logForKernel) {
13993 /* If we are in console mode and have a custom log filter,
13994 * colorize the log message.
13995 */
13996 if (!disableConsoleOutput && sBootArgLogFilterFound) {
13997 const char * color = ""; // do not free
13998 color = colorForFlags(msgLogSpec);
13999 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14000 buffer, color[0] ? VTRESET : "");
14001 } else {
14002 printf("%s\n", buffer);
14003 }
14004 }
14005
14006 finish:
14007 IOLockUnlock(sKextLoggingLock);
14008
14009 if (allocBuffer) {
14010 kheap_free(KHEAP_TEMP, allocBuffer, (length + 1) * sizeof(char));
14011 }
14012 return;
14013 }
14014
14015 #if KASLR_IOREG_DEBUG
14016
14017 #define IOLOG_INDENT( the_indention ) \
14018 { \
14019 int i; \
14020 for ( i = 0; i < (the_indention); i++ ) { \
14021 IOLog(" "); \
14022 } \
14023 }
14024
14025 extern vm_offset_t vm_kernel_stext;
14026 extern vm_offset_t vm_kernel_etext;
14027 extern mach_vm_offset_t kext_alloc_base;
14028 extern mach_vm_offset_t kext_alloc_max;
14029
14030 bool ScanForAddrInObject(OSObject * theObject,
14031 int indent );
14032
14033 bool
14034 ScanForAddrInObject(OSObject * theObject,
14035 int indent)
14036 {
14037 const OSMetaClass * myTypeID;
14038 OSSharedPtr<OSCollectionIterator> myIter;
14039 OSSymbol * myKey;
14040 OSObject * myValue;
14041 bool myResult = false;
14042
14043 if (theObject == NULL) {
14044 IOLog("%s: theObject is NULL \n",
14045 __FUNCTION__);
14046 return myResult;
14047 }
14048
14049 myTypeID = OSTypeIDInst(theObject);
14050
14051 if (myTypeID == OSTypeID(OSDictionary)) {
14052 OSDictionary * myDictionary;
14053
14054 myDictionary = OSDynamicCast(OSDictionary, theObject);
14055 myIter = OSCollectionIterator::withCollection( myDictionary );
14056 if (myIter == NULL) {
14057 return myResult;
14058 }
14059
14060 // !! reset the iterator
14061 myIter->reset();
14062
14063 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14064 bool myTempResult;
14065
14066 myValue = myDictionary->getObject(myKey);
14067 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14068 if (myTempResult) {
14069 // if we ever get a true result return true
14070 myResult = true;
14071 IOLOG_INDENT(indent);
14072 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14073 }
14074 }
14075
14076 // !! release the iterator
14077 myIter.reset();
14078 } else if (myTypeID == OSTypeID(OSArray)) {
14079 OSArray * myArray;
14080
14081 myArray = OSDynamicCast(OSArray, theObject);
14082 myIter = OSCollectionIterator::withCollection(myArray);
14083 if (myIter == NULL) {
14084 return myResult;
14085 }
14086 // !! reset the iterator
14087 myIter->reset();
14088
14089 while ((myValue = myIter->getNextObject())) {
14090 bool myTempResult;
14091 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14092 if (myTempResult) {
14093 // if we ever get a true result return true
14094 myResult = true;
14095 IOLOG_INDENT(indent);
14096 IOLog("OSArray: \n");
14097 }
14098 }
14099 // !! release the iterator
14100 myIter.reset();
14101 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14102 // should we look for addresses in strings?
14103 } else if (myTypeID == OSTypeID(OSData)) {
14104 void * * myPtrPtr;
14105 unsigned int myLen;
14106 OSData * myDataObj;
14107
14108 myDataObj = OSDynamicCast(OSData, theObject);
14109 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14110 myLen = myDataObj->getLength();
14111
14112 if (myPtrPtr && myLen && myLen > 7) {
14113 int i;
14114 int myPtrCount = (myLen / sizeof(void *));
14115
14116 for (i = 0; i < myPtrCount; i++) {
14117 UInt64 numberValue = (UInt64) * (myPtrPtr);
14118
14119 if (kext_alloc_max != 0 &&
14120 numberValue >= kext_alloc_base &&
14121 numberValue < kext_alloc_max) {
14122 OSSharedPtr<OSKext> myKext;
14123 // IOLog("found OSData %p in kext map %p to %p \n",
14124 // *(myPtrPtr),
14125 // (void *) kext_alloc_base,
14126 // (void *) kext_alloc_max);
14127
14128 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14129 if (myKext) {
14130 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14131 *(myPtrPtr),
14132 myKext->getIdentifierCString());
14133 }
14134 myResult = true;
14135 }
14136 if (vm_kernel_etext != 0 &&
14137 numberValue >= vm_kernel_stext &&
14138 numberValue < vm_kernel_etext) {
14139 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14140 *(myPtrPtr),
14141 (void *) vm_kernel_stext,
14142 (void *) vm_kernel_etext);
14143 myResult = true;
14144 }
14145 myPtrPtr++;
14146 }
14147 }
14148 } else if (myTypeID == OSTypeID(OSBoolean)) {
14149 // do nothing here...
14150 } else if (myTypeID == OSTypeID(OSNumber)) {
14151 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14152
14153 UInt64 numberValue = number->unsigned64BitValue();
14154
14155 if (kext_alloc_max != 0 &&
14156 numberValue >= kext_alloc_base &&
14157 numberValue < kext_alloc_max) {
14158 OSSharedPtr<OSKext> myKext;
14159 IOLog("found OSNumber in kext map %p to %p \n",
14160 (void *) kext_alloc_base,
14161 (void *) kext_alloc_max);
14162 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14163
14164 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14165 if (myKext) {
14166 IOLog("found in kext \"%s\" \n",
14167 myKext->getIdentifierCString());
14168 }
14169
14170 myResult = true;
14171 }
14172 if (vm_kernel_etext != 0 &&
14173 numberValue >= vm_kernel_stext &&
14174 numberValue < vm_kernel_etext) {
14175 IOLog("found OSNumber in kernel text segment %p to %p \n",
14176 (void *) vm_kernel_stext,
14177 (void *) vm_kernel_etext);
14178 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14179 myResult = true;
14180 }
14181 }
14182 #if 0
14183 else {
14184 const OSMetaClass* myMetaClass = NULL;
14185
14186 myMetaClass = theObject->getMetaClass();
14187 if (myMetaClass) {
14188 IOLog("class %s \n", myMetaClass->getClassName());
14189 } else {
14190 IOLog("Unknown object \n" );
14191 }
14192 }
14193 #endif
14194
14195 return myResult;
14196 }
14197 #endif // KASLR_KEXT_DEBUG
14198 }; /* extern "C" */
14199
14200 #if PRAGMA_MARK
14201 #pragma mark Backtrace Dump & kmod_get_info() support
14202 #endif
14203 /*********************************************************************
14204 * This function must be safe to call in panic context.
14205 *********************************************************************/
14206 /* static */
14207 void
14208 OSKext::printKextsInBacktrace(
14209 vm_offset_t * addr __unused,
14210 unsigned int cnt __unused,
14211 int (* printf_func)(const char *fmt, ...) __unused,
14212 uint32_t flags __unused)
14213 {
14214 addr64_t summary_page = 0;
14215 addr64_t last_summary_page = 0;
14216 bool found_kmod = false;
14217 u_int i = 0;
14218
14219 if (kPrintKextsLock & flags) {
14220 if (!sKextSummariesLock) {
14221 return;
14222 }
14223 IOLockLock(sKextSummariesLock);
14224 }
14225
14226 if (!gLoadedKextSummaries) {
14227 (*printf_func)(" can't perform kext scan: no kext summary");
14228 goto finish;
14229 }
14230
14231 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14232 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14233 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14234 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14235 (*printf_func)(" can't perform kext scan: "
14236 "missing kext summary page %p", summary_page);
14237 goto finish;
14238 }
14239 }
14240
14241 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14242 OSKextLoadedKextSummary * summary;
14243
14244 summary = gLoadedKextSummaries->summaries + i;
14245 if (!summary->address) {
14246 continue;
14247 }
14248
14249 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14250 continue;
14251 }
14252
14253 if (!found_kmod) {
14254 if (!(kPrintKextsTerse & flags)) {
14255 (*printf_func)(" Kernel Extensions in backtrace:\n");
14256 }
14257 found_kmod = true;
14258 }
14259
14260 printSummary(summary, printf_func, flags);
14261 }
14262
14263 finish:
14264 if (kPrintKextsLock & flags) {
14265 IOLockUnlock(sKextSummariesLock);
14266 }
14267
14268 return;
14269 }
14270
14271 /*********************************************************************
14272 * This function must be safe to call in panic context.
14273 *********************************************************************/
14274 /* static */
14275 boolean_t
14276 OSKext::summaryIsInBacktrace(
14277 OSKextLoadedKextSummary * summary,
14278 vm_offset_t * addr,
14279 unsigned int cnt)
14280 {
14281 u_int i = 0;
14282
14283 for (i = 0; i < cnt; i++) {
14284 vm_offset_t kscan_addr = addr[i];
14285 #if __has_feature(ptrauth_calls)
14286 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14287 #endif /* __has_feature(ptrauth_calls) */
14288 if ((kscan_addr >= summary->text_exec_address) &&
14289 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
14290 return TRUE;
14291 }
14292 }
14293
14294 return FALSE;
14295 }
14296
14297 /*
14298 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14299 * sKextSummariesLock held.
14300 */
14301 OSKextLoadedKextSummary *
14302 OSKext::summaryForAddress(uintptr_t addr)
14303 {
14304 #if __has_feature(ptrauth_calls)
14305 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14306 #endif /* __has_feature(ptrauth_calls) */
14307 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14308 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14309 if (!summary->address) {
14310 continue;
14311 }
14312
14313 #if VM_MAPPED_KEXTS
14314 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14315 * support split kexts, but we also may unmap the kexts, which can
14316 * race with the above codepath (see OSKext::unload). As such,
14317 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14318 */
14319 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14320 return summary;
14321 }
14322 #else
14323 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14324 kernel_segment_command_t *seg;
14325
14326 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14327 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14328 return summary;
14329 }
14330 }
14331 #endif
14332 }
14333
14334 /* addr did not map to any kext */
14335 return NULL;
14336 }
14337
14338 /* static */
14339 void *
14340 OSKext::kextForAddress(const void *address)
14341 {
14342 void * image = NULL;
14343 OSKextActiveAccount * active;
14344 OSKext * kext = NULL;
14345 uint32_t baseIdx;
14346 uint32_t lim;
14347 uintptr_t addr = (uintptr_t) address;
14348 size_t i;
14349
14350 if (!addr) {
14351 return NULL;
14352 }
14353 #if __has_feature(ptrauth_calls)
14354 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14355 #endif /* __has_feature(ptrauth_calls) */
14356
14357 if (sKextAccountsCount) {
14358 IOSimpleLockLock(sKextAccountsLock);
14359 // bsearch sKextAccounts list
14360 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14361 active = &sKextAccounts[baseIdx + (lim >> 1)];
14362 if ((addr >= active->address) && (addr < active->address_end)) {
14363 kext = active->account->kext;
14364 if (kext && kext->kmod_info) {
14365 image = (void *) kext->kmod_info->address;
14366 }
14367 break;
14368 } else if (addr > active->address) {
14369 // move right
14370 baseIdx += (lim >> 1) + 1;
14371 lim--;
14372 }
14373 // else move left
14374 }
14375 IOSimpleLockUnlock(sKextAccountsLock);
14376 }
14377 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14378 image = (void *) &_mh_execute_header;
14379 }
14380 if (!image && gLoadedKextSummaries) {
14381 IOLockLock(sKextSummariesLock);
14382 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14383 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14384 if (addr >= summary->address && addr < summary->address + summary->size) {
14385 image = (void *)summary->address;
14386 }
14387 }
14388 IOLockUnlock(sKextSummariesLock);
14389 }
14390
14391 return image;
14392 }
14393
14394 /*
14395 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14396 * Safe to call in panic context.
14397 */
14398 static OSKextLoadedKextSummary *
14399 findSummary(uint32_t tagID)
14400 {
14401 OSKextLoadedKextSummary * summary;
14402 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14403 summary = gLoadedKextSummaries->summaries + i;
14404 if (summary->loadTag == tagID) {
14405 return summary;
14406 }
14407 }
14408 return NULL;
14409 }
14410
14411 /*********************************************************************
14412 * This function must be safe to call in panic context.
14413 *********************************************************************/
14414 void
14415 OSKext::printSummary(
14416 OSKextLoadedKextSummary * summary,
14417 int (* printf_func)(const char *fmt, ...),
14418 uint32_t flags)
14419 {
14420 kmod_reference_t * kmod_ref = NULL;
14421 uuid_string_t uuid;
14422 char version[kOSKextVersionMaxLength];
14423 uint64_t tmpAddr;
14424 uint64_t tmpSize;
14425 OSKextLoadedKextSummary *dependencySummary;
14426
14427 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14428 strlcpy(version, "unknown version", sizeof(version));
14429 }
14430 (void) uuid_unparse(summary->uuid, uuid);
14431
14432 #if defined(__arm__) || defined(__arm64__)
14433 tmpAddr = summary->text_exec_address;
14434 tmpSize = summary->text_exec_size;
14435 #else
14436 tmpAddr = summary->address;
14437 tmpSize = summary->size;
14438 #endif
14439 if (kPrintKextsUnslide & flags) {
14440 tmpAddr = ml_static_unslide(tmpAddr);
14441 }
14442 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14443 (kPrintKextsTerse & flags) ? "" : " ",
14444 summary->name, version, uuid,
14445 tmpAddr, tmpAddr + tmpSize - 1);
14446
14447 if (kPrintKextsTerse & flags) {
14448 return;
14449 }
14450
14451 /* print dependency info */
14452 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14453 kmod_ref;
14454 kmod_ref = kmod_ref->next) {
14455 kmod_info_t * rinfo;
14456
14457 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14458 (*printf_func)(" kmod dependency scan stopped "
14459 "due to missing dependency page: %p\n",
14460 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14461 break;
14462 }
14463 rinfo = kmod_ref->info;
14464
14465 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14466 (*printf_func)(" kmod dependency scan stopped "
14467 "due to missing kmod page: %p\n",
14468 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14469 break;
14470 }
14471
14472 if (!rinfo->address) {
14473 continue; // skip fake entries for built-ins
14474 }
14475
14476 dependencySummary = findSummary(rinfo->id);
14477 uuid[0] = 0x00;
14478 tmpAddr = rinfo->address;
14479 tmpSize = rinfo->size;
14480 if (dependencySummary) {
14481 (void) uuid_unparse(dependencySummary->uuid, uuid);
14482 #if defined(__arm__) || defined(__arm64__)
14483 tmpAddr = dependencySummary->text_exec_address;
14484 tmpSize = dependencySummary->text_exec_size;
14485 #endif
14486 }
14487
14488 if (kPrintKextsUnslide & flags) {
14489 tmpAddr = ml_static_unslide(tmpAddr);
14490 }
14491 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14492 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
14493 }
14494 return;
14495 }
14496
14497
14498 #if !defined(__arm__) && !defined(__arm64__)
14499 /*******************************************************************************
14500 * substitute() looks at an input string (a pointer within a larger buffer)
14501 * for a match to a substring, and on match it writes the marker & substitution
14502 * character to an output string, updating the scan (from) and
14503 * output (to) indexes as appropriate.
14504 *******************************************************************************/
14505 static int substitute(
14506 const char * scan_string,
14507 char * string_out,
14508 uint32_t * to_index,
14509 uint32_t * from_index,
14510 const char * substring,
14511 char marker,
14512 char substitution);
14513
14514 /* string_out must be at least KMOD_MAX_NAME bytes.
14515 */
14516 static int
14517 substitute(
14518 const char * scan_string,
14519 char * string_out,
14520 uint32_t * to_index,
14521 uint32_t * from_index,
14522 const char * substring,
14523 char marker,
14524 char substitution)
14525 {
14526 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
14527
14528 /* On a substring match, append the marker (if there is one) and then
14529 * the substitution character, updating the output (to) index accordingly.
14530 * Then update the input (from) length by the length of the substring
14531 * that got replaced.
14532 */
14533 if (!strncmp(scan_string, substring, substring_length)) {
14534 if (marker) {
14535 string_out[(*to_index)++] = marker;
14536 }
14537 string_out[(*to_index)++] = substitution;
14538 (*from_index) += substring_length;
14539 return 1;
14540 }
14541 return 0;
14542 }
14543
14544 /*******************************************************************************
14545 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14546 * KMOD_MAX_NAME characters and performs various substitutions of common
14547 * prefixes & substrings as defined by tables in kext_panic_report.h.
14548 *******************************************************************************/
14549 static void compactIdentifier(
14550 const char * identifier,
14551 char * identifier_out,
14552 char ** identifier_out_end);
14553
14554 static void
14555 compactIdentifier(
14556 const char * identifier,
14557 char * identifier_out,
14558 char ** identifier_out_end)
14559 {
14560 uint32_t from_index, to_index;
14561 uint32_t scan_from_index = 0;
14562 uint32_t scan_to_index = 0;
14563 subs_entry_t * subs_entry = NULL;
14564 int did_sub = 0;
14565
14566 from_index = to_index = 0;
14567 identifier_out[0] = '\0';
14568
14569 /* Replace certain identifier prefixes with shorter @+character sequences.
14570 * Check the return value of substitute() so we only replace the prefix.
14571 */
14572 for (subs_entry = &kext_identifier_prefix_subs[0];
14573 subs_entry->substring && !did_sub;
14574 subs_entry++) {
14575 did_sub = substitute(identifier, identifier_out,
14576 &scan_to_index, &scan_from_index,
14577 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14578 }
14579 did_sub = 0;
14580
14581 /* Now scan through the identifier looking for the common substrings
14582 * and replacing them with shorter !+character sequences via substitute().
14583 */
14584 for (/* see above */;
14585 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14586 /* see loop */) {
14587 const char * scan_string = &identifier[scan_from_index];
14588
14589 did_sub = 0;
14590
14591 if (scan_from_index) {
14592 for (subs_entry = &kext_identifier_substring_subs[0];
14593 subs_entry->substring && !did_sub;
14594 subs_entry++) {
14595 did_sub = substitute(scan_string, identifier_out,
14596 &scan_to_index, &scan_from_index,
14597 subs_entry->substring, '!', subs_entry->substitute);
14598 }
14599 }
14600
14601 /* If we didn't substitute, copy the input character to the output.
14602 */
14603 if (!did_sub) {
14604 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14605 }
14606 }
14607
14608 identifier_out[scan_to_index] = '\0';
14609 if (identifier_out_end) {
14610 *identifier_out_end = &identifier_out[scan_to_index];
14611 }
14612
14613 return;
14614 }
14615 #endif /* !defined(__arm__) && !defined(__arm64__) */
14616
14617 /*******************************************************************************
14618 * assemble_identifier_and_version() adds to a string buffer a compacted
14619 * bundle identifier followed by a version string.
14620 *******************************************************************************/
14621
14622 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14623 */
14624 static size_t assemble_identifier_and_version(
14625 kmod_info_t * kmod_info,
14626 char * identPlusVers,
14627 size_t bufSize);
14628
14629 static size_t
14630 assemble_identifier_and_version(
14631 kmod_info_t * kmod_info,
14632 char * identPlusVers,
14633 size_t bufSize)
14634 {
14635 size_t result = 0;
14636
14637 #if defined(__arm__) || defined(__arm64__)
14638 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14639 #else
14640 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14641 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
14642 #endif
14643 identPlusVers[result++] = '\t'; // increment for real char
14644 identPlusVers[result] = '\0'; // don't increment for nul char
14645 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14646 if (result >= bufSize) {
14647 identPlusVers[bufSize - 1] = '\0';
14648 result = bufSize - 1;
14649 }
14650
14651 return result;
14652 }
14653
14654 /*******************************************************************************
14655 * Assumes sKextLock is held.
14656 *******************************************************************************/
14657 /* static */
14658 int
14659 OSKext::saveLoadedKextPanicListTyped(
14660 const char * prefix,
14661 int invertFlag,
14662 int libsFlag,
14663 char * paniclist,
14664 uint32_t list_size)
14665 {
14666 int result = -1;
14667 unsigned int count, i;
14668
14669 count = sLoadedKexts->getCount();
14670 if (!count) {
14671 goto finish;
14672 }
14673
14674 i = count - 1;
14675 do {
14676 OSObject * rawKext = sLoadedKexts->getObject(i);
14677 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14678 int match;
14679 size_t identPlusVersLength;
14680 size_t tempLen;
14681 char identPlusVers[2 * KMOD_MAX_NAME];
14682
14683 if (!rawKext) {
14684 printf("OSKext::saveLoadedKextPanicListTyped - "
14685 "NULL kext in loaded kext list; continuing\n");
14686 continue;
14687 }
14688
14689 if (!theKext) {
14690 printf("OSKext::saveLoadedKextPanicListTyped - "
14691 "Kext type cast failed in loaded kext list; continuing\n");
14692 continue;
14693 }
14694
14695 /* Skip all built-in kexts.
14696 */
14697 if (theKext->isKernelComponent()) {
14698 continue;
14699 }
14700
14701 kmod_info_t * kmod_info = theKext->kmod_info;
14702
14703 /* Filter for kmod name (bundle identifier).
14704 */
14705 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14706 if ((match && invertFlag) || (!match && !invertFlag)) {
14707 continue;
14708 }
14709
14710 /* Filter for libraries (kexts that have a compatible version).
14711 */
14712 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14713 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14714 continue;
14715 }
14716
14717 if (!kmod_info ||
14718 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14719 printf("kext scan stopped due to missing kmod_info page: %p\n",
14720 kmod_info);
14721 goto finish;
14722 }
14723
14724 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14725 identPlusVers,
14726 sizeof(identPlusVers));
14727 if (!identPlusVersLength) {
14728 printf("error saving loaded kext info\n");
14729 goto finish;
14730 }
14731
14732 /* make sure everything fits and we null terminate.
14733 */
14734 tempLen = strlcat(paniclist, identPlusVers, list_size);
14735 if (tempLen >= list_size) {
14736 // panic list is full, keep it and null terminate
14737 paniclist[list_size - 1] = 0x00;
14738 result = 0;
14739 goto finish;
14740 }
14741 tempLen = strlcat(paniclist, "\n", list_size);
14742 if (tempLen >= list_size) {
14743 // panic list is full, keep it and null terminate
14744 paniclist[list_size - 1] = 0x00;
14745 result = 0;
14746 goto finish;
14747 }
14748 } while (i--);
14749
14750 result = 0;
14751 finish:
14752
14753 return result;
14754 }
14755
14756 /*********************************************************************
14757 *********************************************************************/
14758 /* static */
14759 void
14760 OSKext::saveLoadedKextPanicList(void)
14761 {
14762 char * newlist = NULL;
14763 uint32_t newlist_size = 0;
14764
14765 newlist_size = KEXT_PANICLIST_SIZE;
14766 newlist = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, newlist_size,
14767 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14768
14769 if (!newlist) {
14770 OSKextLog(/* kext */ NULL,
14771 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14772 "Couldn't allocate kext panic log buffer.");
14773 goto finish;
14774 }
14775
14776 newlist[0] = '\0';
14777
14778 // non-"com.apple." kexts
14779 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14780 /* libs? */ -1, newlist, newlist_size) != 0) {
14781 goto finish;
14782 }
14783 // "com.apple." nonlibrary kexts
14784 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14785 /* libs? */ 0, newlist, newlist_size) != 0) {
14786 goto finish;
14787 }
14788 // "com.apple." library kexts
14789 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14790 /* libs? */ 1, newlist, newlist_size) != 0) {
14791 goto finish;
14792 }
14793
14794 if (loaded_kext_paniclist) {
14795 kheap_free(KHEAP_DATA_BUFFERS, loaded_kext_paniclist,
14796 loaded_kext_paniclist_size);
14797 }
14798 loaded_kext_paniclist = newlist;
14799 newlist = NULL;
14800 loaded_kext_paniclist_size = newlist_size;
14801
14802 finish:
14803 if (newlist) {
14804 kheap_free(KHEAP_TEMP, newlist, newlist_size);
14805 }
14806 return;
14807 }
14808
14809 /*********************************************************************
14810 * Assumes sKextLock is held.
14811 *********************************************************************/
14812 void
14813 OSKext::savePanicString(bool isLoading)
14814 {
14815 u_long len;
14816
14817 if (!kmod_info) {
14818 return; // do not goto finish here b/c of lock
14819 }
14820
14821 len = assemble_identifier_and_version( kmod_info,
14822 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14823 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14824 if (!len) {
14825 printf("error saving unloaded kext info\n");
14826 goto finish;
14827 }
14828
14829 if (isLoading) {
14830 last_loaded_strlen = len;
14831 last_loaded_address = (void *)kmod_info->address;
14832 last_loaded_size = kmod_info->size;
14833 clock_get_uptime(&last_loaded_timestamp);
14834 } else {
14835 last_unloaded_strlen = len;
14836 last_unloaded_address = (void *)kmod_info->address;
14837 last_unloaded_size = kmod_info->size;
14838 clock_get_uptime(&last_unloaded_timestamp);
14839 }
14840
14841 finish:
14842 return;
14843 }
14844
14845 /*********************************************************************
14846 *********************************************************************/
14847 /* static */
14848 void
14849 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
14850 {
14851 if (last_loaded_strlen) {
14852 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14853 AbsoluteTime_to_scalar(&last_loaded_timestamp),
14854 last_loaded_strlen, last_loaded_str_buf,
14855 last_loaded_address, last_loaded_size);
14856 }
14857
14858 if (last_unloaded_strlen) {
14859 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
14860 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
14861 last_unloaded_strlen, last_unloaded_str_buf,
14862 last_unloaded_address, last_unloaded_size);
14863 }
14864
14865 printf_func("loaded kexts:\n");
14866 if (loaded_kext_paniclist &&
14867 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
14868 loaded_kext_paniclist[0]) {
14869 printf_func("%.*s",
14870 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
14871 loaded_kext_paniclist);
14872 } else {
14873 printf_func("(none)\n");
14874 }
14875 return;
14876 }
14877
14878 /*********************************************************************
14879 * Assumes sKextLock is held.
14880 *********************************************************************/
14881 /* static */
14882 void
14883 OSKext::updateLoadedKextSummaries(void)
14884 {
14885 kern_return_t result = KERN_FAILURE;
14886 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
14887 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
14888 OSKext *aKext;
14889 vm_map_offset_t start, end;
14890 size_t summarySize = 0;
14891 size_t size;
14892 u_int count;
14893 u_int maxKexts;
14894 u_int i, j;
14895 OSKextActiveAccount * accountingList;
14896 OSKextActiveAccount * prevAccountingList;
14897 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
14898
14899 prevAccountingList = NULL;
14900 prevAccountingListCount = 0;
14901
14902 #if DEVELOPMENT || DEBUG
14903 if (IORecursiveLockHaveLock(sKextLock) == false) {
14904 panic("sKextLock must be held");
14905 }
14906 #endif
14907
14908 IOLockLock(sKextSummariesLock);
14909
14910 count = sLoadedKexts->getCount();
14911 for (i = 0, maxKexts = 0; i < count; ++i) {
14912 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14913 maxKexts += (aKext && aKext->isExecutable());
14914 }
14915
14916 if (!maxKexts) {
14917 goto finish;
14918 }
14919 if (maxKexts < kOSKextTypicalLoadCount) {
14920 maxKexts = kOSKextTypicalLoadCount;
14921 }
14922
14923 /* Calculate the size needed for the new summary headers.
14924 */
14925
14926 size = sizeof(*gLoadedKextSummaries);
14927 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
14928 size = round_page(size);
14929
14930 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
14931 if (gLoadedKextSummaries) {
14932 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
14933 gLoadedKextSummaries = NULL;
14934 gLoadedKextSummariesTimestamp = mach_absolute_time();
14935 sLoadedKextSummariesAllocSize = 0;
14936 }
14937 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
14938 if (result != KERN_SUCCESS) {
14939 goto finish;
14940 }
14941 summaryHeader = summaryHeaderAlloc;
14942 summarySize = size;
14943 } else {
14944 summaryHeader = gLoadedKextSummaries;
14945 summarySize = sLoadedKextSummariesAllocSize;
14946
14947 start = (vm_map_offset_t) summaryHeader;
14948 end = start + summarySize;
14949 result = vm_map_protect(kernel_map,
14950 start,
14951 end,
14952 VM_PROT_DEFAULT,
14953 FALSE);
14954 if (result != KERN_SUCCESS) {
14955 goto finish;
14956 }
14957 }
14958
14959 /* Populate the summary header.
14960 */
14961
14962 bzero(summaryHeader, summarySize);
14963 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
14964 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
14965
14966 /* Populate each kext summary.
14967 */
14968
14969 count = sLoadedKexts->getCount();
14970 accountingListAlloc = 0;
14971 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
14972 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14973 if (!aKext || !aKext->isExecutable()) {
14974 continue;
14975 }
14976
14977 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
14978 summaryHeader->numSummaries++;
14979 accountingListAlloc++;
14980 }
14981
14982 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
14983 accountingListCount = 0;
14984 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
14985 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14986 if (!aKext || !aKext->isExecutable()) {
14987 continue;
14988 }
14989
14990 OSKextActiveAccount activeAccount;
14991 aKext->updateActiveAccount(&activeAccount);
14992 // order by address
14993 for (idx = 0; idx < accountingListCount; idx++) {
14994 if (activeAccount.address < accountingList[idx].address) {
14995 break;
14996 }
14997 }
14998 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
14999 accountingList[idx] = activeAccount;
15000 accountingListCount++;
15001 }
15002 assert(accountingListCount == accountingListAlloc);
15003 /* Write protect the buffer and move it into place.
15004 */
15005
15006 start = (vm_map_offset_t) summaryHeader;
15007 end = start + summarySize;
15008
15009 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15010 if (result != KERN_SUCCESS) {
15011 goto finish;
15012 }
15013
15014 gLoadedKextSummaries = summaryHeader;
15015 gLoadedKextSummariesTimestamp = mach_absolute_time();
15016 sLoadedKextSummariesAllocSize = summarySize;
15017 summaryHeaderAlloc = NULL;
15018
15019 /* Call the magic breakpoint function through a static function pointer so
15020 * the compiler can't optimize the function away.
15021 */
15022 if (sLoadedKextSummariesUpdated) {
15023 (*sLoadedKextSummariesUpdated)();
15024 }
15025
15026 IOSimpleLockLock(sKextAccountsLock);
15027 prevAccountingList = sKextAccounts;
15028 prevAccountingListCount = sKextAccountsCount;
15029 sKextAccounts = accountingList;
15030 sKextAccountsCount = accountingListCount;
15031 IOSimpleLockUnlock(sKextAccountsLock);
15032
15033 finish:
15034 IOLockUnlock(sKextSummariesLock);
15035
15036 /* If we had to allocate a new buffer but failed to generate the summaries,
15037 * free that now.
15038 */
15039 if (summaryHeaderAlloc) {
15040 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15041 }
15042 if (prevAccountingList) {
15043 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15044 }
15045
15046 return;
15047 }
15048
15049 /*********************************************************************
15050 *********************************************************************/
15051 void
15052 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15053 {
15054 OSSharedPtr<OSData> uuid;
15055
15056 strlcpy(summary->name, getIdentifierCString(),
15057 sizeof(summary->name));
15058
15059 uuid = copyUUID();
15060 if (uuid) {
15061 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
15062 }
15063
15064 if (flags.builtin) {
15065 // this value will stop lldb from parsing the mach-o header
15066 // summary->address = UINT64_MAX;
15067 // summary->size = 0;
15068 summary->address = kmod_info->address;
15069 summary->size = kmod_info->size;
15070 } else {
15071 summary->address = kmod_info->address;
15072 summary->size = kmod_info->size;
15073 }
15074 summary->version = getVersion();
15075 summary->loadTag = kmod_info->id;
15076 summary->flags = 0;
15077 summary->reference_list = (uint64_t) kmod_info->reference_list;
15078
15079 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15080 if (summary->text_exec_address == 0) {
15081 // Fallback to __TEXT
15082 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15083 }
15084 return;
15085 }
15086
15087 /*********************************************************************
15088 *********************************************************************/
15089
15090 void
15091 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
15092 {
15093 kernel_mach_header_t *hdr = NULL;
15094 kernel_segment_command_t *seg = NULL;
15095
15096 bzero(accountp, sizeof(*accountp));
15097
15098 hdr = (kernel_mach_header_t *)kmod_info->address;
15099 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15100 /*
15101 * If this kext supports split segments (or is in a new
15102 * MH_FILESET kext collection), use the first
15103 * executable segment as the range for instructions
15104 * (and thus for backtracing.
15105 */
15106 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15107 if (seg->initprot & VM_PROT_EXECUTE) {
15108 break;
15109 }
15110 }
15111 }
15112 if (seg) {
15113 accountp->address = seg->vmaddr;
15114 if (accountp->address) {
15115 accountp->address_end = seg->vmaddr + seg->vmsize;
15116 }
15117 } else {
15118 /* For non-split kexts and for kexts without executable
15119 * segments, just use the kmod_info range (as the kext
15120 * is either all in one range or should not show up in
15121 * instruction backtraces).
15122 */
15123 accountp->address = kmod_info->address;
15124 if (accountp->address) {
15125 accountp->address_end = kmod_info->address + kmod_info->size;
15126 }
15127 }
15128
15129 accountp->account = this->account;
15130 }
15131
15132 bool
15133 OSKext::isDriverKit(void)
15134 {
15135 OSString *bundleType;
15136
15137 if (infoDict) {
15138 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15139 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15140 return TRUE;
15141 }
15142 }
15143 return FALSE;
15144 }
15145
15146 bool
15147 OSKext::isInFileset(void)
15148 {
15149 if (!kmod_info) {
15150 goto check_prelinked;
15151 }
15152
15153 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15154 return true;
15155 }
15156
15157 check_prelinked:
15158 if (isPrelinked()) {
15159 /*
15160 * If we haven't setup kmod_info yet, but we know
15161 * we're loading a prelinked kext in an MH_FILESET KC,
15162 * then return true
15163 */
15164 kc_format_t kc_format;
15165 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15166 return true;
15167 }
15168 }
15169 return false;
15170 }
15171
15172 bool
15173 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15174 {
15175 kern_return_t result;
15176 if (!super::init()) {
15177 return false;
15178 }
15179 if (seg == nullptr) {
15180 return false;
15181 }
15182 result = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&data, seg->vmsize, VM_KERN_MEMORY_KEXT);
15183 if (result != KERN_SUCCESS) {
15184 return false;
15185 }
15186 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15187 savedSegment = seg;
15188 vmsize = seg->vmsize;
15189 vmaddr = seg->vmaddr;
15190 return true;
15191 }
15192
15193 OSSharedPtr<OSKextSavedMutableSegment>
15194 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15195 {
15196 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15197 if (me && !me->initWithSegment(seg)) {
15198 return nullptr;
15199 }
15200 return me;
15201 }
15202
15203 void
15204 OSKextSavedMutableSegment::free(void)
15205 {
15206 if (data) {
15207 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15208 }
15209 }
15210
15211 vm_offset_t
15212 OSKextSavedMutableSegment::getVMAddr() const
15213 {
15214 return vmaddr;
15215 }
15216
15217 vm_offset_t
15218 OSKextSavedMutableSegment::getVMSize() const
15219 {
15220 return vmsize;
15221 }
15222
15223 OSReturn
15224 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15225 {
15226 if (seg != savedSegment) {
15227 return kOSKextReturnInvalidArgument;
15228 }
15229 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15230 return kOSKextReturnInvalidArgument;
15231 }
15232 memcpy((void *)seg->vmaddr, data, vmsize);
15233 return kOSReturnSuccess;
15234 }
15235
15236 extern "C" const vm_allocation_site_t *
15237 OSKextGetAllocationSiteForCaller(uintptr_t address)
15238 {
15239 OSKextActiveAccount * active;
15240 vm_allocation_site_t * site;
15241 vm_allocation_site_t * releasesite;
15242
15243 uint32_t baseIdx;
15244 uint32_t lim;
15245 #if __has_feature(ptrauth_calls)
15246 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15247 #endif /* __has_feature(ptrauth_calls) */
15248
15249 IOSimpleLockLock(sKextAccountsLock);
15250 site = releasesite = NULL;
15251
15252 // bsearch sKextAccounts list
15253 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15254 active = &sKextAccounts[baseIdx + (lim >> 1)];
15255 if ((address >= active->address) && (address < active->address_end)) {
15256 site = &active->account->site;
15257 if (!site->tag) {
15258 vm_tag_alloc_locked(site, &releasesite);
15259 }
15260 break;
15261 } else if (address > active->address) {
15262 // move right
15263 baseIdx += (lim >> 1) + 1;
15264 lim--;
15265 }
15266 // else move left
15267 }
15268 IOSimpleLockUnlock(sKextAccountsLock);
15269 if (releasesite) {
15270 kern_allocation_name_release(releasesite);
15271 }
15272
15273 return site;
15274 }
15275
15276 extern "C" uint32_t
15277 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
15278 {
15279 OSKextAccount * account = (typeof(account))site;
15280 const char * kname;
15281
15282 if (name) {
15283 if (account->kext) {
15284 kname = account->kext->getIdentifierCString();
15285 } else {
15286 kname = "<>";
15287 }
15288 strlcpy(name, kname, namelen);
15289 }
15290
15291 return account->loadTag;
15292 }
15293
15294 extern "C" void
15295 OSKextFreeSite(vm_allocation_site_t * site)
15296 {
15297 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15298 IODelete(freeAccount, OSKextAccount, 1);
15299 }
15300
15301 /*********************************************************************
15302 *********************************************************************/
15303
15304 #if CONFIG_IMAGEBOOT
15305 int
15306 OSKextGetUUIDForName(const char *name, uuid_t uuid)
15307 {
15308 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
15309 if (!kext) {
15310 return 1;
15311 }
15312
15313 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
15314 if (uuid_data) {
15315 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
15316 return 0;
15317 }
15318
15319 return 1;
15320 }
15321 #endif
15322
15323 static int
15324 sysctl_willuserspacereboot
15325 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15326 {
15327 int new_value = 0, old_value = 0, changed = 0;
15328 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15329 if (error) {
15330 return error;
15331 }
15332 if (changed) {
15333 OSKext::willUserspaceReboot();
15334 }
15335 return 0;
15336 }
15337
15338 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15339 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15340 NULL, 0, sysctl_willuserspacereboot, "I", "");