]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSKext.cpp
xnu-7195.101.1.tar.gz
[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_kld = NULL;
979 kernel_segment_command_t * seg_klddata = NULL;
980 kernel_segment_command_t * seg_linkedit = NULL;
981
982 const char __unused * dt_segment_name = NULL;
983 void __unused * segment_paddress = NULL;
984 int __unused segment_size = 0;
985
986 OSKextLog(/* kext */ NULL,
987 kOSKextLogProgressLevel |
988 kOSKextLogGeneralFlag,
989 "Jettisoning kext bootstrap segments.");
990
991 /*
992 * keep the linkedit segment around when booted from a new MH_FILESET
993 * KC because all the kexts shared a linkedit segment.
994 */
995 kc_format_t kc_format;
996 if (!PE_get_primary_kc_format(&kc_format)) {
997 OSKextLog(/* kext */ NULL,
998 kOSKextLogErrorLevel |
999 kOSKextLogGeneralFlag,
1000 "Unable to determine primary KC format");
1001 }
1002
1003 /*****
1004 * Dispose of unnecessary stuff that the booter didn't need to load.
1005 */
1006 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1007 (void **)&dt_mach_header, &dt_mach_header_size);
1008 if (dt_result == 0 && dt_mach_header) {
1009 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1010 round_page_32(dt_mach_header_size));
1011 }
1012 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1013 (void **)&dt_symtab, &dt_symtab_size);
1014 if (dt_result == 0 && dt_symtab) {
1015 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1016 round_page_32(dt_symtab_size));
1017 }
1018
1019 /*****
1020 * KLD & KLDDATA bootstrap segments.
1021 */
1022 // xxx - should rename KLD segment
1023 seg_kld = getsegbyname("__KLD");
1024 seg_klddata = getsegbyname("__KLDDATA");
1025 if (seg_klddata) {
1026 // __mod_term_func is part of __KLDDATA
1027 OSRuntimeUnloadCPPForSegment(seg_klddata);
1028 }
1029
1030 #if __arm__ || __arm64__
1031 /* Free the memory that was set up by iBoot.
1032 */
1033 #if !defined(KERNEL_INTEGRITY_KTRR) && !defined(KERNEL_INTEGRITY_CTRR)
1034 /* We cannot free the KLD segment with CTRR enabled as it contains text and
1035 * is covered by the contiguous rorgn.
1036 */
1037 dt_segment_name = "Kernel-__KLD";
1038 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1039 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1040 (int)segment_size); // calls ml_static_mfree
1041 } else if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1042 /* With fileset KCs, the Kernel KLD segment is not recorded in the DT. */
1043 ml_static_mfree(ml_static_ptovirt(seg_kld->vmaddr - gVirtBase + gPhysBase),
1044 seg_kld->vmsize);
1045 }
1046 #endif
1047 dt_segment_name = "Kernel-__KLDDATA";
1048 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1049 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1050 (int)segment_size); // calls ml_static_mfree
1051 } else if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1052 /* With fileset KCs, the Kernel KLDDATA segment is not recorded in the DT. */
1053 ml_static_mfree(ml_static_ptovirt(seg_klddata->vmaddr - gVirtBase + gPhysBase),
1054 seg_klddata->vmsize);
1055 }
1056 #elif __i386__ || __x86_64__
1057 /* On x86, use the mapping data from the segment load command to
1058 * unload KLD & KLDDATA directly.
1059 * This may invalidate any assumptions about "avail_start"
1060 * defining the lower bound for valid physical addresses.
1061 */
1062 if (seg_kld && seg_kld->vmaddr && seg_kld->vmsize) {
1063 bzero((void *)seg_kld->vmaddr, seg_kld->vmsize);
1064 ml_static_mfree(seg_kld->vmaddr, seg_kld->vmsize);
1065 }
1066 if (seg_klddata && seg_klddata->vmaddr && seg_klddata->vmsize) {
1067 bzero((void *)seg_klddata->vmaddr, seg_klddata->vmsize);
1068 ml_static_mfree(seg_klddata->vmaddr, seg_klddata->vmsize);
1069 }
1070 #else
1071 #error arch
1072 #endif
1073
1074 /*****
1075 * Prelinked kernel's symtab (if there is one).
1076 */
1077 if (kc_format != KCFormatFileset) {
1078 kernel_section_t * sect;
1079 sect = getsectbyname("__PRELINK", "__symtab");
1080 if (sect && sect->addr && sect->size) {
1081 ml_static_mfree(sect->addr, sect->size);
1082 }
1083 }
1084
1085 seg_linkedit = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1086
1087 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1088 * pageable, unless keepsyms is set. To do that, we have to copy it from
1089 * its booter-allocated memory, free the booter memory, reallocate proper
1090 * managed memory, then copy the segment back in.
1091 *
1092 * NOTE: This optimization is not valid for fileset KCs because each
1093 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1094 * that points to one fileset-global LINKEDIT segment. This
1095 * optimization is also only valid for platforms that support vm
1096 * mapped kexts or mapped kext collections (pageable KCs)
1097 */
1098 #if VM_MAPPED_KEXTS
1099 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1100 kern_return_t mem_result;
1101 void *seg_copy = NULL;
1102 void *seg_data = NULL;
1103 vm_map_offset_t seg_offset = 0;
1104 vm_map_offset_t seg_copy_offset = 0;
1105 vm_map_size_t seg_length = 0;
1106
1107 seg_data = (void *) seg_linkedit->vmaddr;
1108 seg_offset = (vm_map_offset_t) seg_linkedit->vmaddr;
1109 seg_length = (vm_map_size_t) seg_linkedit->vmsize;
1110
1111 /* Allocate space for the LINKEDIT copy.
1112 */
1113 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1114 seg_length, VM_KERN_MEMORY_KEXT);
1115 if (mem_result != KERN_SUCCESS) {
1116 OSKextLog(/* kext */ NULL,
1117 kOSKextLogErrorLevel |
1118 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1119 "Can't copy __LINKEDIT segment for VM reassign.");
1120 return result;
1121 }
1122 seg_copy_offset = (vm_map_offset_t) seg_copy;
1123
1124 /* Copy it out.
1125 */
1126 memcpy(seg_copy, seg_data, seg_length);
1127
1128 /* Dump the booter memory.
1129 */
1130 ml_static_mfree(seg_offset, seg_length);
1131
1132 /* Set up the VM region.
1133 */
1134 mem_result = vm_map_enter_mem_object(
1135 kernel_map,
1136 &seg_offset,
1137 seg_length, /* mask */ 0,
1138 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1139 VM_MAP_KERNEL_FLAGS_NONE,
1140 VM_KERN_MEMORY_NONE,
1141 (ipc_port_t)NULL,
1142 (vm_object_offset_t) 0,
1143 /* copy */ FALSE,
1144 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1145 /* max_protection */ VM_PROT_ALL,
1146 /* inheritance */ VM_INHERIT_DEFAULT);
1147 if ((mem_result != KERN_SUCCESS) ||
1148 (seg_offset != (vm_map_offset_t) seg_data)) {
1149 OSKextLog(/* kext */ NULL,
1150 kOSKextLogErrorLevel |
1151 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1152 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1153 seg_data, seg_length, mem_result);
1154 return result;
1155 }
1156
1157 /* And copy it back.
1158 */
1159 memcpy(seg_data, seg_copy, seg_length);
1160
1161 /* Free the copy.
1162 */
1163 kmem_free(kernel_map, seg_copy_offset, seg_length);
1164 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1165 /* Remove the linkedit segment of the Boot KC */
1166 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1167 OSKext::jettisonFileSetLinkeditSegment(mh);
1168 }
1169 #else // !VM_MAPPED_KEXTS
1170 /*****
1171 * Dump the LINKEDIT segment, unless keepsyms is set.
1172 */
1173 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1174 dt_segment_name = "Kernel-__LINKEDIT";
1175 if (0 == IODTGetLoaderInfo(dt_segment_name,
1176 &segment_paddress, &segment_size)) {
1177 #ifdef SECURE_KERNEL
1178 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1179 bzero((void*)vmaddr, segment_size);
1180 #endif
1181 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1182 (int)segment_size);
1183 }
1184 } else {
1185 OSKextLog(/* kext */ NULL,
1186 kOSKextLogBasicLevel |
1187 kOSKextLogGeneralFlag,
1188 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1189 }
1190 #endif // VM_MAPPED_KEXTS
1191
1192 result = kOSReturnSuccess;
1193
1194 return result;
1195 }
1196
1197 #if CONFIG_KXLD
1198 /*********************************************************************
1199 *********************************************************************/
1200 void
1201 OSKext::flushNonloadedKexts(
1202 Boolean flushPrelinkedKexts)
1203 {
1204 OSSharedPtr<OSSet> keepKexts;
1205
1206 /* TODO: make this more efficient with MH_FILESET kexts */
1207
1208 // Do not unload prelinked kexts on arm because the kernelcache is not
1209 // structured in a way that allows them to be unmapped
1210 #if !defined(__x86_64__)
1211 flushPrelinkedKexts = false;
1212 #endif /* defined(__x86_64__) */
1213
1214 IORecursiveLockLock(sKextLock);
1215
1216 OSKextLog(/* kext */ NULL,
1217 kOSKextLogProgressLevel |
1218 kOSKextLogKextBookkeepingFlag,
1219 "Flushing nonloaded kexts and other unused data.");
1220
1221 OSKext::considerDestroyingLinkContext();
1222
1223 /* If we aren't flushing unused prelinked kexts, we have to put them
1224 * aside while we flush everything else so make a container for them.
1225 */
1226 keepKexts = OSSet::withCapacity(16);
1227 if (!keepKexts) {
1228 goto finish;
1229 }
1230
1231 /* Set aside prelinked kexts (in-use or not) and break
1232 * any lingering inter-kext references for nonloaded kexts
1233 * so they have min. retain counts.
1234 */
1235 {
1236 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1237 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1238 if (!thisKext) {
1239 return false;
1240 }
1241 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1242 keepKexts->setObject(thisKext);
1243 } else if (!thisKext->declaresExecutable()) {
1244 /*
1245 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1246 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1247 * flushNonloadedKexts().
1248 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1249 */
1250 keepKexts->setObject(thisKext);
1251 } else if (thisKext->isInFileset()) {
1252 /* keep all kexts in the new MH_FILESET KC */
1253 keepKexts->setObject(thisKext);
1254 }
1255
1256 thisKext->flushDependencies(/* forceIfLoaded */ false);
1257 return false;
1258 });
1259 }
1260 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1261 */
1262 sKextsByID->flushCollection();
1263
1264 /* Now put the loaded kexts back into the ID dictionary.
1265 */
1266 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1267 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1268 if (!thisKext) {
1269 return false;
1270 }
1271 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1272 return false;
1273 });
1274
1275 /* Finally, put back the kept kexts if we saved any.
1276 */
1277 keepKexts->iterateObjects(^bool (OSObject * obj) {
1278 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1279 if (!thisKext) {
1280 return false;
1281 }
1282 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1283 return false;
1284 });
1285
1286 finish:
1287 IORecursiveLockUnlock(sKextLock);
1288 return;
1289 }
1290 #else /* !CONFIG_KXLD */
1291
1292 void
1293 OSKext::flushNonloadedKexts(
1294 Boolean flushPrelinkedKexts __unused)
1295 {
1296 IORecursiveLockLock(sKextLock);
1297
1298 OSKextLog(/* kext */ NULL,
1299 kOSKextLogProgressLevel |
1300 kOSKextLogKextBookkeepingFlag,
1301 "Flushing dependency info for non-loaded kexts.");
1302
1303 /*
1304 * In a world where we don't dynamically link kexts, they all come
1305 * from a kext collection that's either in wired memory, or
1306 * wire-on-demand. We don't need to mess around with moving kexts in
1307 * and out of the sKextsByID array - they can all just stay there.
1308 * Here we just flush the dependency list for kexts that are not
1309 * loaded.
1310 */
1311 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1312 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1313 if (!thisKext) {
1314 return false;
1315 }
1316 thisKext->flushDependencies(/* forceIfLoaded */ false);
1317 return false;
1318 });
1319
1320 IORecursiveLockUnlock(sKextLock);
1321 return;
1322 }
1323
1324 #endif /* CONFIG_KXLD */
1325
1326 /*********************************************************************
1327 *********************************************************************/
1328 /* static */
1329 void
1330 OSKext::setIOKitDaemonActive(bool active)
1331 {
1332 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1333 IORecursiveLockLock(sKextLock);
1334 sIOKitDaemonActive = active;
1335 if (sKernelRequests->getCount()) {
1336 OSKext::pingIOKitDaemon();
1337 }
1338 IORecursiveLockUnlock(sKextLock);
1339
1340 return;
1341 }
1342
1343 /*********************************************************************
1344 * OSKextLib.cpp might need access to this someday but for now it's
1345 * private.
1346 *********************************************************************/
1347 extern "C" {
1348 extern void ipc_port_release_send(ipc_port_t);
1349 };
1350
1351 /* static */
1352 OSReturn
1353 OSKext::pingIOKitDaemon(void)
1354 {
1355 OSReturn result = kOSReturnError;
1356 #if !NO_KEXTD
1357 mach_port_t kextd_port = IPC_PORT_NULL;
1358
1359 if (!sIOKitDaemonActive) {
1360 result = kOSKextReturnDisabled; // basically unavailable
1361 goto finish;
1362 }
1363
1364 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1365 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1366 OSKextLog(/* kext */ NULL,
1367 kOSKextLogErrorLevel |
1368 kOSKextLogIPCFlag,
1369 "Can't get " kIOKitDaemonName " port.");
1370 goto finish;
1371 }
1372
1373 result = kextd_ping(kextd_port);
1374 if (result != KERN_SUCCESS) {
1375 OSKextLog(/* kext */ NULL,
1376 kOSKextLogErrorLevel |
1377 kOSKextLogIPCFlag,
1378 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1379 goto finish;
1380 }
1381
1382 finish:
1383 if (IPC_PORT_VALID(kextd_port)) {
1384 ipc_port_release_send(kextd_port);
1385 }
1386 #endif
1387
1388 return result;
1389 }
1390
1391 /*********************************************************************
1392 *********************************************************************/
1393 /* static */
1394 void
1395 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1396 {
1397 IORecursiveLockLock(sKextLock);
1398 sDeferredLoadSucceeded = succeeded;
1399 IORecursiveLockUnlock(sKextLock);
1400
1401 return;
1402 }
1403
1404 /*********************************************************************
1405 * Called from IOSystemShutdownNotification.
1406 *********************************************************************/
1407 /* static */
1408 void
1409 OSKext::willShutdown(void)
1410 {
1411 #if !NO_KEXTD
1412 OSReturn checkResult = kOSReturnError;
1413 #endif
1414 OSSharedPtr<OSDictionary> exitRequest;
1415
1416 IORecursiveLockLock(sKextLock);
1417
1418 OSKext::setLoadEnabled(false);
1419 OSKext::setUnloadEnabled(false);
1420 OSKext::setAutounloadsEnabled(false);
1421 OSKext::setKernelRequestsEnabled(false);
1422
1423 #if defined(__x86_64__) || defined(__i386__)
1424 if (IOPMRootDomainGetWillShutdown()) {
1425 OSKext::freeKCFileSetcontrol();
1426 }
1427 #endif // (__x86_64__) || defined(__i386__)
1428
1429 #if !NO_KEXTD
1430 OSKextLog(/* kext */ NULL,
1431 kOSKextLogProgressLevel |
1432 kOSKextLogGeneralFlag,
1433 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1434
1435 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1436 exitRequest);
1437 if (checkResult != kOSReturnSuccess) {
1438 goto finish;
1439 }
1440 if (!sKernelRequests->setObject(exitRequest.get())) {
1441 goto finish;
1442 }
1443
1444 OSKext::pingIOKitDaemon();
1445
1446 finish:
1447 #endif
1448
1449 IORecursiveLockUnlock(sKextLock);
1450 return;
1451 }
1452
1453 void
1454 OSKext::willUserspaceReboot(void)
1455 {
1456 OSKext::willShutdown();
1457 IOService::userSpaceWillReboot();
1458 gIOCatalogue->terminateDriversForUserspaceReboot();
1459 }
1460
1461 void
1462 OSKext::resetAfterUserspaceReboot(void)
1463 {
1464 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1465 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1466
1467 IORecursiveLockLock(sKextLock);
1468 gIOCatalogue->resetAfterUserspaceReboot();
1469 IOService::userSpaceDidReboot();
1470 OSKext::setLoadEnabled(true);
1471 OSKext::setUnloadEnabled(true);
1472 OSKext::setAutounloadsEnabled(true);
1473 OSKext::setKernelRequestsEnabled(true);
1474 sOSKextWasResetAfterUserspaceReboot = true;
1475 IORecursiveLockUnlock(sKextLock);
1476 }
1477
1478 extern "C" void
1479 OSKextResetAfterUserspaceReboot(void)
1480 {
1481 OSKext::resetAfterUserspaceReboot();
1482 }
1483
1484 /*********************************************************************
1485 *********************************************************************/
1486 /* static */
1487 bool
1488 OSKext::getLoadEnabled(void)
1489 {
1490 bool result;
1491
1492 IORecursiveLockLock(sKextLock);
1493 result = sLoadEnabled;
1494 IORecursiveLockUnlock(sKextLock);
1495 return result;
1496 }
1497
1498 /*********************************************************************
1499 *********************************************************************/
1500 /* static */
1501 bool
1502 OSKext::setLoadEnabled(bool flag)
1503 {
1504 bool result;
1505
1506 IORecursiveLockLock(sKextLock);
1507 result = sLoadEnabled;
1508 sLoadEnabled = (flag ? true : false);
1509
1510 if (sLoadEnabled != result) {
1511 OSKextLog(/* kext */ NULL,
1512 kOSKextLogBasicLevel |
1513 kOSKextLogLoadFlag,
1514 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1515 }
1516
1517 IORecursiveLockUnlock(sKextLock);
1518
1519 return result;
1520 }
1521
1522 /*********************************************************************
1523 *********************************************************************/
1524 /* static */
1525 bool
1526 OSKext::getUnloadEnabled(void)
1527 {
1528 bool result;
1529
1530 IORecursiveLockLock(sKextLock);
1531 result = sUnloadEnabled;
1532 IORecursiveLockUnlock(sKextLock);
1533 return result;
1534 }
1535
1536 /*********************************************************************
1537 *********************************************************************/
1538 /* static */
1539 bool
1540 OSKext::setUnloadEnabled(bool flag)
1541 {
1542 bool result;
1543
1544 IORecursiveLockLock(sKextLock);
1545 result = sUnloadEnabled;
1546 sUnloadEnabled = (flag ? true : false);
1547 IORecursiveLockUnlock(sKextLock);
1548
1549 if (sUnloadEnabled != result) {
1550 OSKextLog(/* kext */ NULL,
1551 kOSKextLogBasicLevel |
1552 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1553 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1554 }
1555
1556 return result;
1557 }
1558
1559 /*********************************************************************
1560 * Do not call any function that takes sKextLock here!
1561 *********************************************************************/
1562 /* static */
1563 bool
1564 OSKext::getAutounloadEnabled(void)
1565 {
1566 bool result;
1567
1568 IORecursiveLockLock(sKextInnerLock);
1569 result = sAutounloadEnabled ? true : false;
1570 IORecursiveLockUnlock(sKextInnerLock);
1571 return result;
1572 }
1573
1574 /*********************************************************************
1575 * Do not call any function that takes sKextLock here!
1576 *********************************************************************/
1577 /* static */
1578 bool
1579 OSKext::setAutounloadsEnabled(bool flag)
1580 {
1581 bool result;
1582
1583 IORecursiveLockLock(sKextInnerLock);
1584
1585 result = sAutounloadEnabled;
1586 sAutounloadEnabled = (flag ? true : false);
1587 if (!sAutounloadEnabled && sUnloadCallout) {
1588 thread_call_cancel(sUnloadCallout);
1589 }
1590
1591 if (sAutounloadEnabled != result) {
1592 OSKextLog(/* kext */ NULL,
1593 kOSKextLogBasicLevel |
1594 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1595 "Kext autounloading now %sabled.",
1596 sAutounloadEnabled ? "en" : "dis");
1597 }
1598
1599 IORecursiveLockUnlock(sKextInnerLock);
1600
1601 return result;
1602 }
1603
1604 /*********************************************************************
1605 *********************************************************************/
1606 /* instance method operating on OSKext field */
1607 bool
1608 OSKext::setAutounloadEnabled(bool flag)
1609 {
1610 bool result = flags.autounloadEnabled ? true : false;
1611 flags.autounloadEnabled = flag ? (0 == flags.unloadUnsupported) : 0;
1612
1613 if (result != (flag ? true : false)) {
1614 OSKextLog(this,
1615 kOSKextLogProgressLevel |
1616 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1617 "Autounloading for kext %s now %sabled.",
1618 getIdentifierCString(),
1619 flags.autounloadEnabled ? "en" : "dis");
1620 }
1621 return result;
1622 }
1623
1624 /*********************************************************************
1625 *********************************************************************/
1626 /* static */
1627 bool
1628 OSKext::setKernelRequestsEnabled(bool flag)
1629 {
1630 bool result;
1631
1632 IORecursiveLockLock(sKextLock);
1633 result = sKernelRequestsEnabled;
1634 sKernelRequestsEnabled = flag ? true : false;
1635
1636 if (sKernelRequestsEnabled != result) {
1637 OSKextLog(/* kext */ NULL,
1638 kOSKextLogBasicLevel |
1639 kOSKextLogGeneralFlag,
1640 "Kernel requests now %sabled.",
1641 sKernelRequestsEnabled ? "en" : "dis");
1642 }
1643 IORecursiveLockUnlock(sKextLock);
1644 return result;
1645 }
1646
1647 /*********************************************************************
1648 *********************************************************************/
1649 /* static */
1650 bool
1651 OSKext::getKernelRequestsEnabled(void)
1652 {
1653 bool result;
1654
1655 IORecursiveLockLock(sKextLock);
1656 result = sKernelRequestsEnabled;
1657 IORecursiveLockUnlock(sKextLock);
1658 return result;
1659 }
1660
1661 static bool
1662 segmentIsMutable(kernel_segment_command_t *seg)
1663 {
1664 /* Mutable segments have to have VM_PROT_WRITE */
1665 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1666 return false;
1667 }
1668 /* Exclude the __DATA_CONST segment */
1669 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1670 return false;
1671 }
1672 /* Exclude __LINKEDIT */
1673 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1674 return false;
1675 }
1676 return true;
1677 }
1678
1679 #if PRAGMA_MARK
1680 #pragma mark Kext Life Cycle
1681 #endif
1682 /*********************************************************************
1683 *********************************************************************/
1684 OSSharedPtr<OSKext>
1685 OSKext::withPrelinkedInfoDict(
1686 OSDictionary * anInfoDict,
1687 bool doCoalescedSlides,
1688 kc_kind_t type)
1689 {
1690 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1691
1692 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1693 return NULL;
1694 }
1695
1696 return newKext;
1697 }
1698
1699 /*********************************************************************
1700 *********************************************************************/
1701 bool
1702 OSKext::initWithPrelinkedInfoDict(
1703 OSDictionary * anInfoDict,
1704 bool doCoalescedSlides,
1705 kc_kind_t type)
1706 {
1707 bool result = false;
1708 OSString * kextPath = NULL; // do not release
1709 OSNumber * addressNum = NULL; // reused; do not release
1710 OSNumber * lengthNum = NULL; // reused; do not release
1711 OSBoolean * scratchBool = NULL; // do not release
1712 void * data = NULL; // do not free
1713 void * srcData = NULL; // do not free
1714 OSSharedPtr<OSData> prelinkedExecutable;
1715 uint32_t length = 0; // reused
1716 uintptr_t kext_slide = PE_get_kc_slide(type);
1717 bool shouldSaveSegments = false;
1718
1719 if (!super::init()) {
1720 goto finish;
1721 }
1722
1723 /* Get the path. Don't look for an arch-specific path property.
1724 */
1725 kextPath = OSDynamicCast(OSString,
1726 anInfoDict->getObject(kPrelinkBundlePathKey));
1727
1728 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1729 goto finish;
1730 }
1731
1732 #if KASLR_KEXT_DEBUG
1733 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1734 #endif
1735
1736 /* Also get the executable's bundle-relative path if present.
1737 * Don't look for an arch-specific path property.
1738 */
1739 executableRelPath.reset(OSDynamicCast(OSString,
1740 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1741 userExecutableRelPath.reset(OSDynamicCast(OSString,
1742 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1743
1744 /* Don't need the paths to be in the info dictionary any more.
1745 */
1746 anInfoDict->removeObject(kPrelinkBundlePathKey);
1747 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1748
1749 scratchBool = OSDynamicCast(OSBoolean,
1750 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1751 if (scratchBool == kOSBooleanTrue) {
1752 flags.requireExplicitLoad = 1;
1753 }
1754
1755 /* Create an OSData wrapper around the linked executable.
1756 */
1757 addressNum = OSDynamicCast(OSNumber,
1758 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1759 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1760 lengthNum = OSDynamicCast(OSNumber,
1761 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1762 if (!lengthNum) {
1763 OSKextLog(this,
1764 kOSKextLogErrorLevel |
1765 kOSKextLogArchiveFlag,
1766 "Kext %s can't find prelinked kext executable size.",
1767 getIdentifierCString());
1768 return result;
1769 }
1770
1771 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1772 length = (uint32_t) (lengthNum->unsigned32BitValue());
1773
1774 #if KASLR_KEXT_DEBUG
1775 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1776 (unsigned long)ml_static_unslide((vm_offset_t)data),
1777 (unsigned long)data,
1778 length);
1779 #endif
1780
1781 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1782 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1783
1784 /* If the kext's load address differs from its source address, allocate
1785 * space in the kext map at the load address and copy the kext over.
1786 */
1787 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1788 if (addressNum) {
1789 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1790
1791 #if KASLR_KEXT_DEBUG
1792 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1793 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1794 (unsigned long)srcData);
1795 #endif
1796
1797 if (data != srcData) {
1798 #if __LP64__
1799 kern_return_t alloc_result;
1800
1801 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1802 if (alloc_result != KERN_SUCCESS) {
1803 OSKextLog(this,
1804 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1805 "Failed to allocate space for prelinked kext %s.",
1806 getIdentifierCString());
1807 goto finish;
1808 }
1809 memcpy(data, srcData, length);
1810 #else
1811 OSKextLog(this,
1812 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1813 "Error: prelinked kext %s - source and load addresses "
1814 "differ on ILP32 architecture.",
1815 getIdentifierCString());
1816 goto finish;
1817 #endif /* __LP64__ */
1818 }
1819
1820 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1821 }
1822
1823 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1824 if (!prelinkedExecutable) {
1825 OSKextLog(this,
1826 kOSKextLogErrorLevel |
1827 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1828 "Kext %s failed to create executable wrapper.",
1829 getIdentifierCString());
1830 goto finish;
1831 }
1832
1833 #if VM_MAPPED_KEXTS
1834 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1835 #else
1836 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1837 #endif
1838 setLinkedExecutable(prelinkedExecutable.get());
1839 addressNum = OSDynamicCast(OSNumber,
1840 anInfoDict->getObject(kPrelinkKmodInfoKey));
1841 if (!addressNum) {
1842 OSKextLog(this,
1843 kOSKextLogErrorLevel |
1844 kOSKextLogArchiveFlag,
1845 "Kext %s can't find prelinked kext kmod_info address.",
1846 getIdentifierCString());
1847 goto finish;
1848 }
1849
1850 if (addressNum->unsigned64BitValue() != 0) {
1851 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1852 if (kmod_info->address) {
1853 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
1854 } else {
1855 kmod_info->address = (uintptr_t)data;
1856 kmod_info->size = length;
1857 }
1858 #if KASLR_KEXT_DEBUG
1859 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1860 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
1861 (unsigned long)kmod_info);
1862 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1863 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
1864 (unsigned long)kmod_info->address);
1865 #endif
1866 }
1867
1868 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1869 }
1870
1871 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
1872 uintptr_t builtinTextStart;
1873 uintptr_t builtinTextEnd;
1874
1875 flags.builtin = true;
1876 builtinKmodIdx = addressNum->unsigned32BitValue();
1877 assert(builtinKmodIdx < gBuiltinKmodsCount);
1878
1879 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1880 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1881
1882 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1883 kmod_info->address = builtinTextStart;
1884 kmod_info->size = builtinTextEnd - builtinTextStart;
1885 }
1886
1887 /* If the plist has a UUID for an interface, save that off.
1888 */
1889 if (isInterface()) {
1890 interfaceUUID.reset(OSDynamicCast(OSData,
1891 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
1892 if (interfaceUUID) {
1893 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1894 }
1895 }
1896
1897 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
1898 if (!result) {
1899 goto finish;
1900 }
1901
1902 kc_type = type;
1903 /* Exclude builtin and codeless kexts */
1904 if (prelinkedExecutable && kmod_info) {
1905 switch (kc_type) {
1906 case KCKindPrimary:
1907 shouldSaveSegments = (
1908 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
1909 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
1910 if (shouldSaveSegments) {
1911 flags.resetSegmentsFromImmutableCopy = 1;
1912 } else {
1913 flags.unloadUnsupported = 1;
1914 }
1915 break;
1916 case KCKindPageable:
1917 flags.resetSegmentsFromVnode = 1;
1918 break;
1919 case KCKindAuxiliary:
1920 if (!pageableKCloaded) {
1921 flags.resetSegmentsFromImmutableCopy = 1;
1922 } else if (resetAuxKCSegmentOnUnload) {
1923 flags.resetSegmentsFromVnode = 1;
1924 } else {
1925 flags.unloadUnsupported = 1;
1926 }
1927 break;
1928 default:
1929 break;
1930 }
1931 }
1932
1933 if (flags.resetSegmentsFromImmutableCopy) {
1934 /* Save a pristine copy of the mutable segments */
1935 kernel_segment_command_t *seg = NULL;
1936 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
1937
1938 savedMutableSegments = OSArray::withCapacity(0);
1939
1940 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
1941 if (!segmentIsMutable(seg)) {
1942 continue;
1943 }
1944 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
1945 uint64_t vmsize = seg->vmsize;
1946 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1947 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1948 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
1949 if (!savedSegment) {
1950 OSKextLog(this,
1951 kOSKextLogErrorLevel |
1952 kOSKextLogGeneralFlag,
1953 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1954 result = kOSKextReturnInternalError;
1955 goto finish;
1956 }
1957 savedMutableSegments->setObject(savedSegment);
1958 }
1959 }
1960
1961 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
1962 /*
1963 * set VM protections now, wire pages for the old style Aux KC now,
1964 * wire pages for the rest of the KC types at load time.
1965 */
1966 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
1967 if (!result) {
1968 goto finish;
1969 }
1970 }
1971
1972 flags.prelinked = true;
1973
1974 /* If we created a kext from prelink info,
1975 * we must be booting from a prelinked kernel.
1976 */
1977 sPrelinkBoot = true;
1978
1979 result = registerIdentifier();
1980
1981 finish:
1982 return result;
1983 }
1984
1985 /*********************************************************************
1986 *********************************************************************/
1987 /* static */
1988 OSSharedPtr<OSKext>
1989 OSKext::withCodelessInfo(OSDictionary * anInfoDict)
1990 {
1991 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
1992
1993 if (newKext && !newKext->initWithCodelessInfo(anInfoDict)) {
1994 return NULL;
1995 }
1996
1997 return newKext;
1998 }
1999
2000 /*********************************************************************
2001 *********************************************************************/
2002 bool
2003 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
2004 {
2005 bool result = false;
2006 OSString * kextPath = NULL; // do not release
2007 OSBoolean * scratchBool = NULL; // do not release
2008
2009 if (anInfoDict == NULL || !super::init()) {
2010 goto finish;
2011 }
2012
2013 /*
2014 * Get the path. Don't look for an arch-specific path property.
2015 */
2016 kextPath = OSDynamicCast(OSString,
2017 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
2018 if (!kextPath) {
2019 OSKextLog(NULL,
2020 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2021 "Requested codeless kext dictionary does not contain the '%s' key",
2022 kKextRequestArgumentCodelessInfoBundlePathKey);
2023 goto finish;
2024 }
2025
2026 uniquePersonalityProperties(anInfoDict);
2027
2028 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2029 goto finish;
2030 }
2031
2032 /*
2033 * This path is meant to initialize codeless kexts only. Refuse
2034 * anything that looks like it has an executable and/or declares
2035 * itself as a kernel component.
2036 */
2037 if (declaresExecutable() || isKernelComponent()) {
2038 OSKextLog(NULL,
2039 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2040 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2041 getIdentifierCString());
2042 goto finish;
2043 }
2044
2045 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2046 boolean_t updated = updateExcludeList(infoDict.get());
2047 if (updated) {
2048 OSKextLog(this,
2049 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2050 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2051 }
2052 }
2053
2054 kc_type = KCKindNone;
2055
2056 scratchBool = OSDynamicCast(OSBoolean,
2057 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2058 if (scratchBool == kOSBooleanTrue) {
2059 flags.requireExplicitLoad = 1;
2060 }
2061
2062 /* Also get the executable's bundle-relative path if present.
2063 * Don't look for an arch-specific path property.
2064 */
2065 userExecutableRelPath.reset(OSDynamicCast(OSString,
2066 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2067
2068 /* remove unnecessary paths from the info dict */
2069 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2070
2071 result = registerIdentifier();
2072
2073 finish:
2074 return result;
2075 }
2076
2077 /*********************************************************************
2078 *********************************************************************/
2079 /* static */
2080 void
2081 OSKext::setAllVMAttributes(void)
2082 {
2083 OSSharedPtr<OSCollectionIterator> kextIterator;
2084 const OSSymbol * thisID = NULL; // do not release
2085
2086 IORecursiveLockLock(sKextLock);
2087
2088 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2089 if (!kextIterator) {
2090 goto finish;
2091 }
2092
2093 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2094 OSKext * thisKext; // do not release
2095
2096 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2097 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2098 continue;
2099 }
2100
2101 if (!thisKext->flags.resetSegmentsFromVnode) {
2102 /*
2103 * set VM protections now, wire pages for the old style Aux KC now,
2104 * wire pages for the rest of the KC types at load time.
2105 */
2106 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2107 }
2108 }
2109
2110 finish:
2111 IORecursiveLockUnlock(sKextLock);
2112
2113 return;
2114 }
2115
2116 /*********************************************************************
2117 *********************************************************************/
2118 OSSharedPtr<OSKext>
2119 OSKext::withBooterData(
2120 OSString * deviceTreeName,
2121 OSData * booterData)
2122 {
2123 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2124
2125 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2126 return NULL;
2127 }
2128
2129 return newKext;
2130 }
2131
2132 /*********************************************************************
2133 *********************************************************************/
2134 typedef struct _BooterKextFileInfo {
2135 uint32_t infoDictPhysAddr;
2136 uint32_t infoDictLength;
2137 uint32_t executablePhysAddr;
2138 uint32_t executableLength;
2139 uint32_t bundlePathPhysAddr;
2140 uint32_t bundlePathLength;
2141 } _BooterKextFileInfo;
2142
2143 bool
2144 OSKext::initWithBooterData(
2145 OSString * deviceTreeName,
2146 OSData * booterData)
2147 {
2148 bool result = false;
2149 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2150 char * infoDictAddr = NULL; // do not free
2151 void * executableAddr = NULL; // do not free
2152 char * bundlePathAddr = NULL; // do not free
2153
2154 OSDictionary * theInfoDict = NULL; // do not release
2155 OSSharedPtr<OSObject> parsedXML;
2156 OSSharedPtr<OSString> kextPath;
2157
2158 OSSharedPtr<OSString> errorString;
2159 OSSharedPtr<OSData> executable;
2160
2161 if (!super::init()) {
2162 goto finish;
2163 }
2164
2165 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2166 if (!kextFileInfo) {
2167 OSKextLog(this,
2168 kOSKextLogErrorLevel |
2169 kOSKextLogGeneralFlag,
2170 "No booter-provided data for kext device tree entry %s.",
2171 deviceTreeName->getCStringNoCopy());
2172 goto finish;
2173 }
2174
2175 /* The info plist must exist or we can't read the kext.
2176 */
2177 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2178 OSKextLog(this,
2179 kOSKextLogErrorLevel |
2180 kOSKextLogGeneralFlag,
2181 "No kext info dictionary for booter device tree entry %s.",
2182 deviceTreeName->getCStringNoCopy());
2183 goto finish;
2184 }
2185
2186 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2187 if (!infoDictAddr) {
2188 OSKextLog(this,
2189 kOSKextLogErrorLevel |
2190 kOSKextLogGeneralFlag,
2191 "Can't translate physical address 0x%x of kext info dictionary "
2192 "for device tree entry %s.",
2193 (int)kextFileInfo->infoDictPhysAddr,
2194 deviceTreeName->getCStringNoCopy());
2195 goto finish;
2196 }
2197
2198 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2199 if (parsedXML) {
2200 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2201 }
2202 if (!theInfoDict) {
2203 const char * errorCString = "(unknown error)";
2204
2205 if (errorString && errorString->getCStringNoCopy()) {
2206 errorCString = errorString->getCStringNoCopy();
2207 } else if (parsedXML) {
2208 errorCString = "not a dictionary";
2209 }
2210 OSKextLog(this,
2211 kOSKextLogErrorLevel |
2212 kOSKextLogGeneralFlag,
2213 "Error unserializing info dictionary for device tree entry %s: %s.",
2214 deviceTreeName->getCStringNoCopy(), errorCString);
2215 goto finish;
2216 }
2217
2218 /* A bundle path is not mandatory.
2219 */
2220 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2221 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2222 if (!bundlePathAddr) {
2223 OSKextLog(this,
2224 kOSKextLogErrorLevel |
2225 kOSKextLogGeneralFlag,
2226 "Can't translate physical address 0x%x of kext bundle path "
2227 "for device tree entry %s.",
2228 (int)kextFileInfo->bundlePathPhysAddr,
2229 deviceTreeName->getCStringNoCopy());
2230 goto finish;
2231 }
2232 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2233
2234 kextPath = OSString::withCString(bundlePathAddr);
2235 if (!kextPath) {
2236 OSKextLog(this,
2237 kOSKextLogErrorLevel |
2238 kOSKextLogGeneralFlag,
2239 "Failed to create wrapper for device tree entry %s kext path %s.",
2240 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2241 goto finish;
2242 }
2243 }
2244
2245 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2246 goto finish;
2247 }
2248
2249 /* An executable is not mandatory.
2250 */
2251 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2252 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2253 if (!executableAddr) {
2254 OSKextLog(this,
2255 kOSKextLogErrorLevel |
2256 kOSKextLogGeneralFlag,
2257 "Can't translate physical address 0x%x of kext executable "
2258 "for device tree entry %s.",
2259 (int)kextFileInfo->executablePhysAddr,
2260 deviceTreeName->getCStringNoCopy());
2261 goto finish;
2262 }
2263
2264 executable = OSData::withBytesNoCopy(executableAddr,
2265 kextFileInfo->executableLength);
2266 if (!executable) {
2267 OSKextLog(this,
2268 kOSKextLogErrorLevel |
2269 kOSKextLogGeneralFlag,
2270 "Failed to create executable wrapper for device tree entry %s.",
2271 deviceTreeName->getCStringNoCopy());
2272 goto finish;
2273 }
2274
2275 /* A kext with an executable needs to retain the whole booterData
2276 * object to keep the executable in memory.
2277 */
2278 if (!setExecutable(executable.get(), booterData)) {
2279 OSKextLog(this,
2280 kOSKextLogErrorLevel |
2281 kOSKextLogGeneralFlag,
2282 "Failed to set kext executable for device tree entry %s.",
2283 deviceTreeName->getCStringNoCopy());
2284 goto finish;
2285 }
2286 }
2287
2288 result = registerIdentifier();
2289
2290 finish:
2291 return result;
2292 }
2293
2294 /*********************************************************************
2295 *********************************************************************/
2296 bool
2297 OSKext::registerIdentifier(void)
2298 {
2299 bool result = false;
2300 OSKext * existingKext = NULL; // do not release
2301 bool existingIsLoaded = false;
2302 bool existingIsPrelinked = false;
2303 bool existingIsCodeless = false;
2304 bool existingIsDext = false;
2305 OSKextVersion newVersion = -1;
2306 OSKextVersion existingVersion = -1;
2307 char newVersionCString[kOSKextVersionMaxLength];
2308 char existingVersionCString[kOSKextVersionMaxLength];
2309 OSSharedPtr<OSData> newUUID;
2310 OSSharedPtr<OSData> existingUUID;
2311
2312 IORecursiveLockLock(sKextLock);
2313
2314 /* Get the new kext's version for checks & log messages.
2315 */
2316 newVersion = getVersion();
2317 OSKextVersionGetString(newVersion, newVersionCString,
2318 kOSKextVersionMaxLength);
2319
2320 /* If we don't have an existing kext with this identifier,
2321 * just record the new kext and we're done!
2322 */
2323 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2324 if (!existingKext) {
2325 sKextsByID->setObject(bundleID.get(), this);
2326 result = true;
2327 goto finish;
2328 }
2329
2330 /* Get the existing kext's version for checks & log messages.
2331 */
2332 existingVersion = existingKext->getVersion();
2333 OSKextVersionGetString(existingVersion,
2334 existingVersionCString, kOSKextVersionMaxLength);
2335
2336 existingIsLoaded = existingKext->isLoaded();
2337 existingIsPrelinked = existingKext->isPrelinked();
2338 existingIsDext = existingKext->isDriverKit();
2339 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2340
2341 /* If we have a non-codeless kext with this identifier that's already
2342 * loaded/prelinked, we can't use the new one, but let's be really
2343 * thorough and check how the two are related for a precise diagnostic
2344 * log message.
2345 *
2346 * This check is valid for kexts that declare an executable and for
2347 * dexts, but not for codeless kexts - we can just replace those.
2348 */
2349 if ((!existingIsCodeless || existingIsDext) &&
2350 (existingIsLoaded || existingIsPrelinked)) {
2351 bool sameVersion = (newVersion == existingVersion);
2352 bool sameExecutable = true; // assume true unless we have UUIDs
2353
2354 /* Only get the UUID if the existing kext is loaded. Doing so
2355 * might have to uncompress an mkext executable and we shouldn't
2356 * take that hit when neither kext is loaded.
2357 *
2358 * Note: there is no decompression that happens when all kexts
2359 * are loaded from kext collecitons.
2360 */
2361 newUUID = copyUUID();
2362 existingUUID = existingKext->copyUUID();
2363
2364 if (existingIsDext && !isDriverKit()) {
2365 OSKextLog(this,
2366 kOSKextLogWarningLevel |
2367 kOSKextLogKextBookkeepingFlag,
2368 "Notice - new kext %s, v%s matches a %s dext"
2369 "with the same bundle ID, v%s.",
2370 getIdentifierCString(), newVersionCString,
2371 (existingIsLoaded ? "loaded" : "prelinked"),
2372 existingVersionCString);
2373 goto finish;
2374 }
2375
2376 /* I'm entirely too paranoid about checking equivalence of executables,
2377 * but I remember nasty problems with it in the past.
2378 *
2379 * - If we have UUIDs for both kexts, compare them.
2380 * - If only one kext has a UUID, they're definitely different.
2381 */
2382 if (newUUID && existingUUID) {
2383 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2384 } else if (newUUID || existingUUID) {
2385 sameExecutable = false;
2386 }
2387
2388 if (!newUUID && !existingUUID) {
2389 /* If there are no UUIDs, we can't really tell that the executables
2390 * are *different* without a lot of work; the loaded kext's
2391 * unrelocated executable is no longer around (and we never had it
2392 * in-kernel for a prelinked kext). We certainly don't want to do
2393 * a whole fake link for the new kext just to compare, either.
2394 */
2395 OSKextLog(this,
2396 kOSKextLogWarningLevel |
2397 kOSKextLogKextBookkeepingFlag,
2398 "Notice - new kext %s, v%s matches %s kext "
2399 "but can't determine if executables are the same (no UUIDs).",
2400 getIdentifierCString(),
2401 newVersionCString,
2402 (existingIsLoaded ? "loaded" : "prelinked"));
2403 }
2404
2405 if (sameVersion && sameExecutable) {
2406 OSKextLog(this,
2407 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2408 kOSKextLogKextBookkeepingFlag,
2409 "Refusing new kext %s, v%s: a %s copy is already present "
2410 "(same version and executable).",
2411 getIdentifierCString(), newVersionCString,
2412 (existingIsLoaded ? "loaded" : "prelinked"));
2413 } else {
2414 if (!sameVersion) {
2415 /* This condition is significant so log it under warnings.
2416 */
2417 OSKextLog(this,
2418 kOSKextLogWarningLevel |
2419 kOSKextLogKextBookkeepingFlag,
2420 "Refusing new kext %s, v%s: already have %s v%s.",
2421 getIdentifierCString(),
2422 newVersionCString,
2423 (existingIsLoaded ? "loaded" : "prelinked"),
2424 existingVersionCString);
2425 } else {
2426 /* This condition is significant so log it under warnings.
2427 */
2428 OSKextLog(this,
2429 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2430 "Refusing new kext %s, v%s: a %s copy with a different "
2431 "executable UUID is already present.",
2432 getIdentifierCString(), newVersionCString,
2433 (existingIsLoaded ? "loaded" : "prelinked"));
2434 }
2435 }
2436 goto finish;
2437 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2438
2439 /* Refuse to allow an existing loaded codeless kext be replaced by a
2440 * normal kext with the same bundle ID.
2441 */
2442 if (existingIsCodeless && declaresExecutable()) {
2443 OSKextLog(this,
2444 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2445 "Refusing new kext %s, v%s: a codeless copy is already %s",
2446 getIdentifierCString(), newVersionCString,
2447 (existingIsLoaded ? "loaded" : "prelinked"));
2448 goto finish;
2449 }
2450
2451 /* Dexts packaged in the BootKC will be protected against replacement
2452 * by non-dexts by the logic above which checks if they are prelinked.
2453 * Dexts which are prelinked into the System KC will be registered
2454 * before any other kexts in the AuxKC are registered, and we never
2455 * put dexts in the AuxKC. Therefore, there is no need to check if an
2456 * existing object is a dext and is being replaced by a non-dext.
2457 * The scenario cannot happen by construction.
2458 *
2459 * See: OSKext::loadFileSetKexts()
2460 */
2461
2462 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2463 * user loads are happening or if we're still in early boot. User agents are
2464 * supposed to resolve dependencies topside and include only the exact
2465 * kexts needed; so we always accept the new kext (in fact we should never
2466 * see an older unloaded copy hanging around).
2467 */
2468 if (sUserLoadsActive) {
2469 sKextsByID->setObject(bundleID.get(), this);
2470 result = true;
2471
2472 OSKextLog(this,
2473 kOSKextLogStepLevel |
2474 kOSKextLogKextBookkeepingFlag,
2475 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2476 getIdentifierCString(),
2477 existingVersionCString,
2478 newVersionCString);
2479
2480 goto finish;
2481 }
2482
2483 /* During early boot, the kext with the highest version always wins out.
2484 * Prelinked kernels will never hit this, but mkexts and booter-read
2485 * kexts might have duplicates.
2486 */
2487 if (newVersion > existingVersion) {
2488 sKextsByID->setObject(bundleID.get(), this);
2489 result = true;
2490
2491 OSKextLog(this,
2492 kOSKextLogStepLevel |
2493 kOSKextLogKextBookkeepingFlag,
2494 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2495 existingVersionCString,
2496 getIdentifierCString(),
2497 newVersionCString);
2498 } else {
2499 OSKextLog(this,
2500 kOSKextLogStepLevel |
2501 kOSKextLogKextBookkeepingFlag,
2502 "Kext %s is already registered with a higher/same version (v%s); "
2503 "dropping newly-added (v%s).",
2504 getIdentifierCString(),
2505 existingVersionCString,
2506 newVersionCString);
2507 }
2508
2509 /* result has been set appropriately by now. */
2510
2511 finish:
2512
2513 IORecursiveLockUnlock(sKextLock);
2514
2515 if (result) {
2516 OSKextLog(this,
2517 kOSKextLogStepLevel |
2518 kOSKextLogKextBookkeepingFlag,
2519 "Kext %s, v%s registered and available for loading.",
2520 getIdentifierCString(), newVersionCString);
2521 }
2522
2523 return result;
2524 }
2525
2526 /*********************************************************************
2527 * Does the bare minimum validation to look up a kext.
2528 * All other validation is done on the spot as needed.
2529 **********************************************************************/
2530 bool
2531 OSKext::setInfoDictionaryAndPath(
2532 OSDictionary * aDictionary,
2533 OSString * aPath)
2534 {
2535 bool result = false;
2536 OSString * bundleIDString = NULL; // do not release
2537 OSString * versionString = NULL; // do not release
2538 OSString * compatibleVersionString = NULL; // do not release
2539 const char * versionCString = NULL; // do not free
2540 const char * compatibleVersionCString = NULL; // do not free
2541 OSBoolean * scratchBool = NULL; // do not release
2542 OSDictionary * scratchDict = NULL; // do not release
2543
2544 if (infoDict) {
2545 panic("Attempt to set info dictionary on a kext "
2546 "that already has one (%s).",
2547 getIdentifierCString());
2548 }
2549
2550 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2551 goto finish;
2552 }
2553
2554 infoDict.reset(aDictionary, OSRetain);
2555
2556 /* Check right away if the info dictionary has any log flags.
2557 */
2558 scratchBool = OSDynamicCast(OSBoolean,
2559 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2560 if (scratchBool == kOSBooleanTrue) {
2561 flags.loggingEnabled = 1;
2562 }
2563
2564 /* The very next thing to get is the bundle identifier. Unlike
2565 * in user space, a kext with no bundle identifier gets axed
2566 * immediately.
2567 */
2568 bundleIDString = OSDynamicCast(OSString,
2569 getPropertyForHostArch(kCFBundleIdentifierKey));
2570 if (!bundleIDString) {
2571 OSKextLog(this,
2572 kOSKextLogErrorLevel |
2573 kOSKextLogValidationFlag,
2574 "CFBundleIdentifier missing/invalid type in kext %s.",
2575 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2576 goto finish;
2577 }
2578 bundleID = OSSymbol::withString(bundleIDString);
2579 if (!bundleID) {
2580 OSKextLog(this,
2581 kOSKextLogErrorLevel |
2582 kOSKextLogValidationFlag,
2583 "Can't copy bundle identifier as symbol for kext %s.",
2584 bundleIDString->getCStringNoCopy());
2585 goto finish;
2586 }
2587
2588 /* Save the path if we got one (it should always be available but it's
2589 * just something nice to have for bookkeeping).
2590 */
2591 if (aPath) {
2592 path.reset(aPath, OSRetain);
2593 }
2594
2595 /*****
2596 * Minimal validation to initialize. We'll do other validation on the spot.
2597 */
2598 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2599 OSKextLog(this,
2600 kOSKextLogErrorLevel |
2601 kOSKextLogValidationFlag,
2602 "Kext %s error - CFBundleIdentifier over max length %d.",
2603 getIdentifierCString(), KMOD_MAX_NAME - 1);
2604 goto finish;
2605 }
2606
2607 version = compatibleVersion = -1;
2608
2609 versionString = OSDynamicCast(OSString,
2610 getPropertyForHostArch(kCFBundleVersionKey));
2611 if (!versionString) {
2612 OSKextLog(this,
2613 kOSKextLogErrorLevel |
2614 kOSKextLogValidationFlag,
2615 "Kext %s error - CFBundleVersion missing/invalid type.",
2616 getIdentifierCString());
2617 goto finish;
2618 }
2619 versionCString = versionString->getCStringNoCopy();
2620 version = OSKextParseVersionString(versionCString);
2621 if (version < 0) {
2622 OSKextLog(this,
2623 kOSKextLogErrorLevel |
2624 kOSKextLogValidationFlag,
2625 "Kext %s error - CFBundleVersion bad value '%s'.",
2626 getIdentifierCString(), versionCString);
2627 goto finish;
2628 }
2629
2630 compatibleVersion = -1; // set to illegal value for kexts that don't have
2631
2632 compatibleVersionString = OSDynamicCast(OSString,
2633 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2634 if (compatibleVersionString) {
2635 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2636 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2637 if (compatibleVersion < 0) {
2638 OSKextLog(this,
2639 kOSKextLogErrorLevel |
2640 kOSKextLogValidationFlag,
2641 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2642 getIdentifierCString(), compatibleVersionCString);
2643 goto finish;
2644 }
2645
2646 if (compatibleVersion > version) {
2647 OSKextLog(this,
2648 kOSKextLogErrorLevel |
2649 kOSKextLogValidationFlag,
2650 "Kext %s error - %s %s > %s %s (must be <=).",
2651 getIdentifierCString(),
2652 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2653 kCFBundleVersionKey, versionCString);
2654 goto finish;
2655 }
2656 }
2657
2658 /* Check to see if this kext is in exclude list */
2659 if (isInExcludeList()) {
2660 OSKextLog(this,
2661 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2662 "Kext %s is in exclude list, not loadable",
2663 getIdentifierCString());
2664 goto finish;
2665 }
2666
2667 /* Set flags for later use if the infoDict gets flushed. We only
2668 * check for true values, not false ones(!)
2669 */
2670 scratchBool = OSDynamicCast(OSBoolean,
2671 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2672 if (scratchBool == kOSBooleanTrue) {
2673 flags.interface = 1;
2674 }
2675
2676 scratchBool = OSDynamicCast(OSBoolean,
2677 getPropertyForHostArch(kOSKernelResourceKey));
2678 if (scratchBool == kOSBooleanTrue) {
2679 flags.kernelComponent = 1;
2680 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2681 flags.started = 1;
2682
2683 /* A kernel component has one implicit dependency on the kernel.
2684 */
2685 flags.hasAllDependencies = 1;
2686 }
2687
2688 /* Make sure common string values in personalities are uniqued to OSSymbols.
2689 */
2690 scratchDict = OSDynamicCast(OSDictionary,
2691 getPropertyForHostArch(kIOKitPersonalitiesKey));
2692 if (scratchDict) {
2693 uniquePersonalityProperties(scratchDict);
2694 }
2695
2696 result = true;
2697
2698 finish:
2699
2700 return result;
2701 }
2702
2703 /*********************************************************************
2704 * Not used for prelinked kernel boot as there is no unrelocated
2705 * executable.
2706 *********************************************************************/
2707 bool
2708 OSKext::setExecutable(
2709 OSData * anExecutable,
2710 OSData * externalData,
2711 bool externalDataIsMkext)
2712 {
2713 bool result = false;
2714 const char * executableKey = NULL; // do not free
2715
2716 if (!anExecutable) {
2717 infoDict->removeObject(_kOSKextExecutableKey);
2718 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2719 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2720 result = true;
2721 goto finish;
2722 }
2723
2724 if (infoDict->getObject(_kOSKextExecutableKey) ||
2725 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2726 panic("Attempt to set an executable on a kext "
2727 "that already has one (%s).",
2728 getIdentifierCString());
2729 goto finish;
2730 }
2731
2732 if (externalDataIsMkext) {
2733 executableKey = _kOSKextMkextExecutableReferenceKey;
2734 } else {
2735 executableKey = _kOSKextExecutableKey;
2736 }
2737
2738 if (anExecutable) {
2739 infoDict->setObject(executableKey, anExecutable);
2740 if (externalData) {
2741 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2742 }
2743 }
2744
2745 result = true;
2746
2747 finish:
2748 return result;
2749 }
2750
2751 /*********************************************************************
2752 *********************************************************************/
2753 static void
2754 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2755 {
2756 OSObject * value = NULL; // do not release
2757 OSString * stringValue = NULL; // do not release
2758 OSSharedPtr<const OSSymbol> symbolValue;
2759
2760 value = dict->getObject(key);
2761 if (!value) {
2762 goto finish;
2763 }
2764 if (OSDynamicCast(OSSymbol, value)) {
2765 /* this is already an OSSymbol: we're good */
2766 goto finish;
2767 }
2768
2769 stringValue = OSDynamicCast(OSString, value);
2770 if (!stringValue) {
2771 goto finish;
2772 }
2773
2774 symbolValue = OSSymbol::withString(stringValue);
2775 if (!symbolValue) {
2776 goto finish;
2777 }
2778
2779 dict->setObject(key, symbolValue.get());
2780
2781 finish:
2782 return;
2783 }
2784
2785 /*********************************************************************
2786 *********************************************************************/
2787 static void
2788 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2789 {
2790 OSObject * value = NULL; // do not release
2791 OSString * stringValue = NULL; // do not release
2792 OSSharedPtr<const OSSymbol> symbolValue;
2793
2794 value = dict->getObject(key);
2795 if (!value) {
2796 goto finish;
2797 }
2798 if (OSDynamicCast(OSSymbol, value)) {
2799 /* this is already an OSSymbol: we're good */
2800 goto finish;
2801 }
2802
2803 stringValue = OSDynamicCast(OSString, value);
2804 if (!stringValue) {
2805 goto finish;
2806 }
2807
2808 symbolValue = OSSymbol::withString(stringValue);
2809 if (!symbolValue) {
2810 goto finish;
2811 }
2812
2813 dict->setObject(key, symbolValue.get());
2814
2815 finish:
2816 return;
2817 }
2818
2819 void
2820 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2821 {
2822 OSKext::uniquePersonalityProperties(personalityDict, true);
2823 }
2824
2825 /*********************************************************************
2826 * Replace common personality property values with uniqued instances
2827 * to save on wired memory.
2828 *********************************************************************/
2829 /* static */
2830 void
2831 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
2832 {
2833 /* Properties every personality has.
2834 */
2835 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2836 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2837 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
2838 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
2839 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
2840 } else if (defaultAddKernelBundleIdentifier) {
2841 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
2842 }
2843
2844 /* Other commonly used properties.
2845 */
2846 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2847 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2848 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2849
2850 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2851 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2852 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2853 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2854 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2855 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2856 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2857 uniqueStringPlistProperty(personalityDict, "Vendor");
2858 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2859 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2860 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2861 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2862 uniqueStringPlistProperty(personalityDict, "idProduct");
2863
2864 return;
2865 }
2866
2867 /*********************************************************************
2868 *********************************************************************/
2869 void
2870 OSKext::free(void)
2871 {
2872 if (isLoaded()) {
2873 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2874 }
2875
2876 infoDict.reset();
2877 bundleID.reset();
2878 path.reset();
2879 executableRelPath.reset();
2880 userExecutableRelPath.reset();
2881 dependencies.reset();
2882 linkedExecutable.reset();
2883 metaClasses.reset();
2884 interfaceUUID.reset();
2885 driverKitUUID.reset();
2886
2887 if (isInterface() && kmod_info) {
2888 kfree(kmod_info, sizeof(kmod_info_t));
2889 }
2890
2891 super::free();
2892 return;
2893 }
2894
2895 #if PRAGMA_MARK
2896 #pragma mark Mkext files
2897 #endif
2898
2899 #if CONFIG_KXLD
2900 /*
2901 * mkext archives are really only relevant on kxld-enabled kernels.
2902 * Without a dynamic kernel linker, we don't need to support any mkexts.
2903 */
2904
2905 /*********************************************************************
2906 *********************************************************************/
2907 OSReturn
2908 OSKext::readMkextArchive(OSData * mkextData,
2909 uint32_t * checksumPtr)
2910 {
2911 OSReturn result = kOSKextReturnBadData;
2912 uint32_t mkextLength = 0;
2913 mkext_header * mkextHeader = NULL; // do not free
2914 uint32_t mkextVersion = 0;
2915
2916 /* Note default return of kOSKextReturnBadData above.
2917 */
2918 mkextLength = mkextData->getLength();
2919 if (mkextLength < sizeof(mkext_basic_header)) {
2920 OSKextLog(/* kext */ NULL,
2921 kOSKextLogErrorLevel |
2922 kOSKextLogArchiveFlag,
2923 "Mkext archive too small to be valid.");
2924 goto finish;
2925 }
2926
2927 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2928
2929 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2930 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2931 OSKextLog(/* kext */ NULL,
2932 kOSKextLogErrorLevel |
2933 kOSKextLogArchiveFlag,
2934 "Mkext archive has invalid magic or signature.");
2935 goto finish;
2936 }
2937
2938 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2939 OSKextLog(/* kext */ NULL,
2940 kOSKextLogErrorLevel |
2941 kOSKextLogArchiveFlag,
2942 "Mkext archive recorded length doesn't match actual file length.");
2943 goto finish;
2944 }
2945
2946 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2947
2948 if (mkextVersion == MKEXT_VERS_2) {
2949 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2950 } else {
2951 OSKextLog(/* kext */ NULL,
2952 kOSKextLogErrorLevel |
2953 kOSKextLogArchiveFlag,
2954 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2955 result = kOSKextReturnUnsupported;
2956 }
2957
2958 finish:
2959 return result;
2960 }
2961
2962 /*********************************************************************
2963 * Assumes magic, signature, version, length have been checked.
2964 * xxx - need to add further bounds checking for each file entry
2965 *
2966 * Should keep track of all kexts created so far, and if we hit a
2967 * fatal error halfway through, remove those kexts. If we've dropped
2968 * an older version that had already been read, whoops! Might want to
2969 * add a level of buffering?
2970 *********************************************************************/
2971 /* static */
2972 OSReturn
2973 OSKext::readMkext2Archive(
2974 OSData * mkextData,
2975 OSDictionary ** mkextPlistOut,
2976 uint32_t * checksumPtr)
2977 {
2978 OSReturn result = kOSReturnError;
2979 uint32_t mkextLength;
2980 mkext2_header * mkextHeader = NULL; // do not free
2981 void * mkextEnd = NULL; // do not free
2982 uint32_t mkextVersion;
2983 uint8_t * crc_address = NULL;
2984 size_t crc_buffer_size = 0;
2985 uint32_t checksum;
2986 uint32_t mkextPlistOffset;
2987 uint32_t mkextPlistCompressedSize;
2988 char * mkextPlistEnd = NULL; // do not free
2989 uint32_t mkextPlistFullSize;
2990 OSSharedPtr<OSString> errorString;
2991 OSSharedPtr<OSData> mkextPlistUncompressedData;
2992 const char * mkextPlistDataBuffer = NULL; // do not free
2993 OSSharedPtr<OSObject> parsedXML;
2994 OSDictionary * mkextPlist = NULL; // do not release
2995 OSArray * mkextInfoDictArray = NULL; // do not release
2996 uint32_t count, i;
2997 kc_format_t kc_format;
2998
2999 if (!PE_get_primary_kc_format(&kc_format)) {
3000 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
3001 "Unable to determine primary KC format");
3002 goto finish;
3003 }
3004
3005 mkextLength = mkextData->getLength();
3006 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
3007 mkextEnd = (char *)mkextHeader + mkextLength;
3008 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
3009
3010 crc_address = (u_int8_t *)&mkextHeader->version;
3011 crc_buffer_size = (uintptr_t)mkextHeader +
3012 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
3013 if (crc_buffer_size > INT32_MAX) {
3014 OSKextLog(/* kext */ NULL,
3015 kOSKextLogErrorLevel |
3016 kOSKextLogArchiveFlag,
3017 "Mkext archive size is too large (%lu > INT32_MAX).",
3018 crc_buffer_size);
3019 result = kOSKextReturnBadData;
3020 goto finish;
3021 }
3022 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3023
3024 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3025 OSKextLog(/* kext */ NULL,
3026 kOSKextLogErrorLevel |
3027 kOSKextLogArchiveFlag,
3028 "Mkext archive has bad checksum.");
3029 result = kOSKextReturnBadData;
3030 goto finish;
3031 }
3032
3033 if (checksumPtr) {
3034 *checksumPtr = checksum;
3035 }
3036
3037 /* Check that the CPU type & subtype match that of the running kernel. */
3038 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3039 OSKextLog(/* kext */ NULL,
3040 kOSKextLogErrorLevel |
3041 kOSKextLogArchiveFlag,
3042 "Mkext archive must have a specific CPU type.");
3043 result = kOSKextReturnBadData;
3044 goto finish;
3045 } else {
3046 if ((UInt32)_mh_execute_header.cputype !=
3047 MKEXT_GET_CPUTYPE(mkextHeader)) {
3048 OSKextLog(/* kext */ NULL,
3049 kOSKextLogErrorLevel |
3050 kOSKextLogArchiveFlag,
3051 "Mkext archive does not match the running kernel's CPU type.");
3052 result = kOSKextReturnArchNotFound;
3053 goto finish;
3054 }
3055 }
3056
3057 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3058 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3059 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3060 mkextPlistCompressedSize;
3061 if (mkextPlistEnd > mkextEnd) {
3062 OSKextLog(/* kext */ NULL,
3063 kOSKextLogErrorLevel |
3064 kOSKextLogArchiveFlag,
3065 "Mkext archive file overrun.");
3066 result = kOSKextReturnBadData;
3067 }
3068
3069 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3070 if (mkextPlistCompressedSize) {
3071 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3072 (UInt8 *)mkextHeader + mkextPlistOffset,
3073 "plist",
3074 mkextPlistCompressedSize, mkextPlistFullSize);
3075 if (!mkextPlistUncompressedData) {
3076 goto finish;
3077 }
3078 mkextPlistDataBuffer = (const char *)
3079 mkextPlistUncompressedData->getBytesNoCopy();
3080 } else {
3081 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3082 }
3083
3084 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3085 */
3086 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3087 if (parsedXML) {
3088 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3089 }
3090 if (!mkextPlist) {
3091 const char * errorCString = "(unknown error)";
3092
3093 if (errorString && errorString->getCStringNoCopy()) {
3094 errorCString = errorString->getCStringNoCopy();
3095 } else if (parsedXML) {
3096 errorCString = "not a dictionary";
3097 }
3098 OSKextLog(/* kext */ NULL,
3099 kOSKextLogErrorLevel |
3100 kOSKextLogArchiveFlag,
3101 "Error unserializing mkext plist: %s.", errorCString);
3102 goto finish;
3103 }
3104
3105 mkextInfoDictArray = OSDynamicCast(OSArray,
3106 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3107 if (!mkextInfoDictArray) {
3108 OSKextLog(/* kext */ NULL,
3109 kOSKextLogErrorLevel |
3110 kOSKextLogArchiveFlag,
3111 "Mkext archive contains no kext info dictionaries.");
3112 goto finish;
3113 }
3114
3115 count = mkextInfoDictArray->getCount();
3116 for (i = 0; i < count; i++) {
3117 OSDictionary * infoDict;
3118
3119
3120 infoDict = OSDynamicCast(OSDictionary,
3121 mkextInfoDictArray->getObject(i));
3122
3123 /* Create the kext for the entry, then release it, because the
3124 * kext system keeps them around until explicitly removed.
3125 * Any creation/registration failures are already logged for us.
3126 */
3127 if (infoDict) {
3128 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3129
3130 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3131 if (kc_format == KCFormatFileset &&
3132 newKext &&
3133 !(newKext->isPrelinked()) &&
3134 newKext->declaresExecutable()) {
3135 result = kOSReturnError;
3136 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3137 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3138
3139 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3140 "Dynamic loading of kext denied for kext %s\n",
3141 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3142 goto finish;
3143 }
3144 }
3145 }
3146
3147 /* If the caller needs the plist, hand them back our copy
3148 */
3149 if (mkextPlistOut) {
3150 *mkextPlistOut = mkextPlist;
3151 parsedXML.detach();
3152 }
3153
3154 /* Even if we didn't keep any kexts from the mkext, we may have a load
3155 * request to process, so we are successful (no errors occurred).
3156 */
3157 result = kOSReturnSuccess;
3158
3159 finish:
3160 return result;
3161 }
3162
3163 /* static */
3164 OSReturn
3165 OSKext::readMkext2Archive(
3166 OSData * mkextData,
3167 OSSharedPtr<OSDictionary> &mkextPlistOut,
3168 uint32_t * checksumPtr)
3169 {
3170 OSDictionary * mkextPlist = NULL;
3171 OSReturn ret;
3172
3173 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3174 &mkextPlist,
3175 checksumPtr))) {
3176 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3177 }
3178 return ret;
3179 }
3180
3181 /*********************************************************************
3182 *********************************************************************/
3183 /* static */
3184 OSSharedPtr<OSKext>
3185 OSKext::withMkext2Info(
3186 OSDictionary * anInfoDict,
3187 OSData * mkextData)
3188 {
3189 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3190
3191 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3192 return NULL;
3193 }
3194
3195 return newKext;
3196 }
3197
3198 /*********************************************************************
3199 *********************************************************************/
3200 bool
3201 OSKext::initWithMkext2Info(
3202 OSDictionary * anInfoDict,
3203 OSData * mkextData)
3204 {
3205 bool result = false;
3206 OSString * kextPath = NULL; // do not release
3207 OSNumber * executableOffsetNum = NULL; // do not release
3208 OSSharedPtr<OSData> executable;
3209
3210 if (anInfoDict == NULL || !super::init()) {
3211 goto finish;
3212 }
3213
3214 /* Get the path. Don't look for an arch-specific path property.
3215 */
3216 kextPath = OSDynamicCast(OSString,
3217 anInfoDict->getObject(kMKEXTBundlePathKey));
3218
3219 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3220 goto finish;
3221 }
3222
3223 /* If we have a path to the executable, save it.
3224 */
3225 executableRelPath.reset(OSDynamicCast(OSString,
3226 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3227
3228 /* Don't need the paths to be in the info dictionary any more.
3229 */
3230 anInfoDict->removeObject(kMKEXTBundlePathKey);
3231 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3232
3233 executableOffsetNum = OSDynamicCast(OSNumber,
3234 infoDict->getObject(kMKEXTExecutableKey));
3235 if (executableOffsetNum) {
3236 executable = createMkext2FileEntry(mkextData,
3237 executableOffsetNum, "executable");
3238 infoDict->removeObject(kMKEXTExecutableKey);
3239 if (!executable) {
3240 goto finish;
3241 }
3242 if (!setExecutable(executable.get(), mkextData, true)) {
3243 goto finish;
3244 }
3245 }
3246
3247 result = registerIdentifier();
3248
3249 finish:
3250 return result;
3251 }
3252
3253 /*********************************************************************
3254 *********************************************************************/
3255 OSSharedPtr<OSData>
3256 OSKext::createMkext2FileEntry(
3257 OSData * mkextData,
3258 OSNumber * offsetNum,
3259 const char * name)
3260 {
3261 OSSharedPtr<OSData> result;
3262 MkextEntryRef entryRef;
3263 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3264 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3265
3266 result = OSData::withCapacity(sizeof(entryRef));
3267 if (!result) {
3268 goto finish;
3269 }
3270
3271 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3272 entryRef.fileinfo = mkextBuffer + entryOffset;
3273 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
3274 result.reset();
3275 goto finish;
3276 }
3277
3278 finish:
3279 if (!result) {
3280 OSKextLog(this,
3281 kOSKextLogErrorLevel |
3282 kOSKextLogArchiveFlag,
3283 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3284 name, getIdentifierCString());
3285 }
3286 return result;
3287 }
3288
3289 /*********************************************************************
3290 *********************************************************************/
3291 extern "C" {
3292 static void * z_alloc(void *, u_int items, u_int size);
3293 static void z_free(void *, void *ptr);
3294
3295 typedef struct z_mem {
3296 uint32_t alloc_size;
3297 uint8_t data[0];
3298 } z_mem;
3299
3300 /*
3301 * Space allocation and freeing routines for use by zlib routines.
3302 */
3303 void *
3304 z_alloc(void * notused __unused, u_int num_items, u_int size)
3305 {
3306 void * result = NULL;
3307 z_mem * zmem = NULL;
3308
3309 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3310 //Check for overflow due to multiplication
3311 if (total > UINT32_MAX) {
3312 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
3313 notused, num_items, size, num_items, size);
3314 }
3315
3316 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3317 //Check for overflow due to addition
3318 if (allocSize64 > UINT32_MAX) {
3319 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
3320 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3321 }
3322 uint32_t allocSize = (uint32_t)allocSize64;
3323
3324 zmem = (z_mem *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, allocSize,
3325 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
3326 if (!zmem) {
3327 goto finish;
3328 }
3329 zmem->alloc_size = allocSize;
3330 result = (void *)&(zmem->data);
3331 finish:
3332 return result;
3333 }
3334
3335 void
3336 z_free(void * notused __unused, void * ptr)
3337 {
3338 uint32_t * skipper = (uint32_t *)ptr - 1;
3339 z_mem * zmem = (z_mem *)skipper;
3340 kheap_free(KHEAP_DATA_BUFFERS, zmem, zmem->alloc_size);
3341 return;
3342 }
3343 };
3344
3345 OSSharedPtr<OSData>
3346 OSKext::extractMkext2FileData(
3347 UInt8 * data,
3348 const char * name,
3349 uint32_t compressedSize,
3350 uint32_t fullSize)
3351 {
3352 OSSharedPtr<OSData> result;
3353 OSSharedPtr<OSData> uncompressedData; // release on error
3354
3355 uint8_t * uncompressedDataBuffer = NULL; // do not free
3356 unsigned long uncompressedSize;
3357 z_stream zstream;
3358 bool zstream_inited = false;
3359 int zlib_result;
3360
3361 /* If the file isn't compressed, we want to make a copy
3362 * so that we don't have the tie to the larger mkext file buffer any more.
3363 */
3364 if (!compressedSize) {
3365 uncompressedData = OSData::withBytes(data, fullSize);
3366 // xxx - no check for failure?
3367 result = uncompressedData;
3368 goto finish;
3369 }
3370
3371 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3372 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
3373 /* How's this for cheesy? The kernel is only asked to extract
3374 * kext plists so we tailor the log messages.
3375 */
3376 if (isKernel()) {
3377 OSKextLog(this,
3378 kOSKextLogErrorLevel |
3379 kOSKextLogArchiveFlag,
3380 "Allocation failure extracting %s from mkext.", name);
3381 } else {
3382 OSKextLog(this,
3383 kOSKextLogErrorLevel |
3384 kOSKextLogArchiveFlag,
3385 "Allocation failure extracting %s from mkext for kext %s.",
3386 name, getIdentifierCString());
3387 }
3388
3389 goto finish;
3390 }
3391 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3392 if (!uncompressedData) {
3393 if (isKernel()) {
3394 OSKextLog(this,
3395 kOSKextLogErrorLevel |
3396 kOSKextLogArchiveFlag,
3397 "Allocation failure extracting %s from mkext.", name);
3398 } else {
3399 OSKextLog(this,
3400 kOSKextLogErrorLevel |
3401 kOSKextLogArchiveFlag,
3402 "Allocation failure extracting %s from mkext for kext %s.",
3403 name, getIdentifierCString());
3404 }
3405 goto finish;
3406 }
3407 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3408
3409 if (isKernel()) {
3410 OSKextLog(this,
3411 kOSKextLogDetailLevel |
3412 kOSKextLogArchiveFlag,
3413 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3414 name, compressedSize, fullSize);
3415 } else {
3416 OSKextLog(this,
3417 kOSKextLogDetailLevel |
3418 kOSKextLogArchiveFlag,
3419 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3420 getIdentifierCString(), name, compressedSize, fullSize);
3421 }
3422
3423 bzero(&zstream, sizeof(zstream));
3424 zstream.next_in = (UInt8 *)data;
3425 zstream.avail_in = compressedSize;
3426
3427 zstream.next_out = uncompressedDataBuffer;
3428 zstream.avail_out = fullSize;
3429
3430 zstream.zalloc = z_alloc;
3431 zstream.zfree = z_free;
3432
3433 zlib_result = inflateInit(&zstream);
3434 if (Z_OK != zlib_result) {
3435 if (isKernel()) {
3436 OSKextLog(this,
3437 kOSKextLogErrorLevel |
3438 kOSKextLogArchiveFlag,
3439 "Mkext error; zlib inflateInit failed (%d) for %s.",
3440 zlib_result, name);
3441 } else {
3442 OSKextLog(this,
3443 kOSKextLogErrorLevel |
3444 kOSKextLogArchiveFlag,
3445 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3446 getIdentifierCString(), zlib_result, name);
3447 }
3448 goto finish;
3449 } else {
3450 zstream_inited = true;
3451 }
3452
3453 zlib_result = inflate(&zstream, Z_FINISH);
3454
3455 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3456 uncompressedSize = zstream.total_out;
3457 } else {
3458 if (isKernel()) {
3459 OSKextLog(this,
3460 kOSKextLogErrorLevel |
3461 kOSKextLogArchiveFlag,
3462 "Mkext error; zlib inflate failed (%d) for %s.",
3463 zlib_result, name);
3464 } else {
3465 OSKextLog(this,
3466 kOSKextLogErrorLevel |
3467 kOSKextLogArchiveFlag,
3468 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3469 getIdentifierCString(), zlib_result, name);
3470 }
3471 if (zstream.msg) {
3472 OSKextLog(this,
3473 kOSKextLogErrorLevel |
3474 kOSKextLogArchiveFlag,
3475 "zlib error: %s.", zstream.msg);
3476 }
3477 goto finish;
3478 }
3479
3480 if (uncompressedSize != fullSize) {
3481 if (isKernel()) {
3482 OSKextLog(this,
3483 kOSKextLogErrorLevel |
3484 kOSKextLogArchiveFlag,
3485 "Mkext error; zlib inflate discrepancy for %s, "
3486 "uncompressed size != original size.", name);
3487 } else {
3488 OSKextLog(this,
3489 kOSKextLogErrorLevel |
3490 kOSKextLogArchiveFlag,
3491 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3492 "uncompressed size != original size.",
3493 getIdentifierCString(), name);
3494 }
3495 goto finish;
3496 }
3497
3498 result = os::move(uncompressedData);
3499
3500 finish:
3501 /* Don't bother checking return, nothing we can do on fail.
3502 */
3503 if (zstream_inited) {
3504 inflateEnd(&zstream);
3505 }
3506
3507 return result;
3508 }
3509
3510 /*********************************************************************
3511 *********************************************************************/
3512 /* static */
3513 OSReturn
3514 OSKext::loadFromMkext(
3515 OSKextLogSpec clientLogFilter,
3516 char * mkextBuffer,
3517 uint32_t mkextBufferLength,
3518 char ** logInfoOut,
3519 uint32_t * logInfoLengthOut)
3520 {
3521 OSReturn result = kOSReturnError;
3522 OSReturn tempResult = kOSReturnError;
3523
3524 OSSharedPtr<OSData> mkextData;
3525 OSSharedPtr<OSDictionary> mkextPlist;
3526
3527 OSSharedPtr<OSArray> logInfoArray;
3528 OSSharedPtr<OSSerialize> serializer;
3529
3530 OSString * predicate = NULL; // do not release
3531 OSDictionary * requestArgs = NULL; // do not release
3532
3533 OSString * kextIdentifier = NULL; // do not release
3534 OSNumber * startKextExcludeNum = NULL; // do not release
3535 OSNumber * startMatchingExcludeNum = NULL; // do not release
3536 OSBoolean * delayAutounloadBool = NULL; // do not release
3537 OSArray * personalityNames = NULL; // do not release
3538
3539 /* Default values for these two options: regular autounload behavior,
3540 * load all kexts, send no personalities.
3541 */
3542 Boolean delayAutounload = false;
3543 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3544 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3545
3546 IORecursiveLockLock(sKextLock);
3547
3548 if (logInfoOut) {
3549 *logInfoOut = NULL;
3550 *logInfoLengthOut = 0;
3551 }
3552
3553 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3554
3555 OSKextLog(/* kext */ NULL,
3556 kOSKextLogDebugLevel |
3557 kOSKextLogIPCFlag,
3558 "Received kext load request from user space.");
3559
3560 /* Regardless of processing, the fact that we have gotten here means some
3561 * user-space program is up and talking to us, so we'll switch our kext
3562 * registration to reflect that.
3563 */
3564 if (!sUserLoadsActive) {
3565 OSKextLog(/* kext */ NULL,
3566 kOSKextLogProgressLevel |
3567 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3568 "Switching to late startup (user-space) kext loading policy.");
3569
3570 sUserLoadsActive = true;
3571 }
3572
3573 if (!sLoadEnabled) {
3574 OSKextLog(/* kext */ NULL,
3575 kOSKextLogErrorLevel |
3576 kOSKextLogLoadFlag,
3577 "Kext loading is disabled.");
3578 result = kOSKextReturnDisabled;
3579 goto finish;
3580 }
3581
3582 /* Note that we do not set a dealloc function on this OSData
3583 * object! No references to it can remain after the loadFromMkext()
3584 * call since we are in a MIG function, and will vm_deallocate()
3585 * the buffer.
3586 */
3587 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3588 mkextBufferLength);
3589 if (!mkextData) {
3590 OSKextLog(/* kext */ NULL,
3591 kOSKextLogErrorLevel |
3592 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3593 "Failed to create wrapper for kext load request.");
3594 result = kOSKextReturnNoMemory;
3595 goto finish;
3596 }
3597
3598 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3599 if (result != kOSReturnSuccess) {
3600 OSKextLog(/* kext */ NULL,
3601 kOSKextLogErrorLevel |
3602 kOSKextLogLoadFlag,
3603 "Failed to read kext load request.");
3604 goto finish;
3605 }
3606
3607 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3608 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3609 OSKextLog(/* kext */ NULL,
3610 kOSKextLogErrorLevel |
3611 kOSKextLogLoadFlag,
3612 "Received kext load request with no predicate; skipping.");
3613 result = kOSKextReturnInvalidArgument;
3614 goto finish;
3615 }
3616
3617 requestArgs = OSDynamicCast(OSDictionary,
3618 mkextPlist->getObject(kKextRequestArgumentsKey));
3619 if (!requestArgs || !requestArgs->getCount()) {
3620 OSKextLog(/* kext */ NULL,
3621 kOSKextLogErrorLevel |
3622 kOSKextLogLoadFlag,
3623 "Received kext load request with no arguments.");
3624 result = kOSKextReturnInvalidArgument;
3625 goto finish;
3626 }
3627
3628 kextIdentifier = OSDynamicCast(OSString,
3629 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3630
3631 if (!kextIdentifier) {
3632 OSKextLog(/* kext */ NULL,
3633 kOSKextLogErrorLevel |
3634 kOSKextLogLoadFlag,
3635 "Received kext load request with no kext identifier.");
3636 result = kOSKextReturnInvalidArgument;
3637 goto finish;
3638 }
3639
3640 startKextExcludeNum = OSDynamicCast(OSNumber,
3641 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3642 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3643 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3644 delayAutounloadBool = OSDynamicCast(OSBoolean,
3645 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3646 personalityNames = OSDynamicCast(OSArray,
3647 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3648
3649 if (delayAutounloadBool) {
3650 delayAutounload = delayAutounloadBool->getValue();
3651 }
3652 if (startKextExcludeNum) {
3653 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3654 }
3655 if (startMatchingExcludeNum) {
3656 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3657 }
3658
3659 OSKextLog(/* kext */ NULL,
3660 kOSKextLogProgressLevel |
3661 kOSKextLogIPCFlag,
3662 "Received request from user space to load kext %s.",
3663 kextIdentifier->getCStringNoCopy());
3664
3665 /* Load the kext, with no deferral, since this is a load from outside
3666 * the kernel.
3667 * xxx - Would like a better way to handle the default values for the
3668 * xxx - start/match opt args.
3669 */
3670 result = OSKext::loadKextWithIdentifier(
3671 kextIdentifier,
3672 /* kextRef */ NULL,
3673 /* allowDefer */ false,
3674 delayAutounload,
3675 startKextExcludeLevel,
3676 startMatchingExcludeLevel,
3677 personalityNames);
3678 if (result != kOSReturnSuccess) {
3679 goto finish;
3680 }
3681 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3682 * for matching via a separate IOKit calldown.
3683 */
3684
3685 finish:
3686
3687 /* Gather up the collected log messages for user space. Any
3688 * error messages past this call will not make it up as log messages
3689 * but will be in the system log.
3690 */
3691 logInfoArray = OSKext::clearUserSpaceLogFilter();
3692
3693 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3694 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3695 logInfoOut, logInfoLengthOut);
3696 if (tempResult != kOSReturnSuccess) {
3697 result = tempResult;
3698 }
3699 }
3700
3701 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3702
3703 IORecursiveLockUnlock(sKextLock);
3704
3705 /* Note: mkextDataObject will have been retained by every kext w/an
3706 * executable in it. That should all have been flushed out at the
3707 * and of the load operation, but you never know....
3708 */
3709 if (mkextData && mkextData->getRetainCount() > 1) {
3710 OSKextLog(/* kext */ NULL,
3711 kOSKextLogErrorLevel |
3712 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3713 "Kext load request buffer from user space still retained by a kext; "
3714 "probable memory leak.");
3715 }
3716
3717 return result;
3718 }
3719
3720 #endif // CONFIG_KXLD
3721
3722 /*********************************************************************
3723 *********************************************************************/
3724 /* static */
3725 OSReturn
3726 OSKext::serializeLogInfo(
3727 OSArray * logInfoArray,
3728 char ** logInfoOut,
3729 uint32_t * logInfoLengthOut)
3730 {
3731 OSReturn result = kOSReturnError;
3732 char * buffer = NULL;
3733 kern_return_t kmem_result = KERN_FAILURE;
3734 OSSharedPtr<OSSerialize> serializer;
3735 char * logInfo = NULL; // returned by reference
3736 uint32_t logInfoLength = 0;
3737
3738 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3739 OSKextLog(/* kext */ NULL,
3740 kOSKextLogErrorLevel |
3741 kOSKextLogIPCFlag,
3742 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3743 /* Bad programmer. */
3744 result = kOSKextReturnInvalidArgument;
3745 goto finish;
3746 }
3747
3748 serializer = OSSerialize::withCapacity(0);
3749 if (!serializer) {
3750 OSKextLog(/* kext */ NULL,
3751 kOSKextLogErrorLevel |
3752 kOSKextLogIPCFlag,
3753 "Failed to create serializer on log info for request from user space.");
3754 /* Incidental error; we're going to (try to) allow the request
3755 * itself to succeed. */
3756 }
3757
3758 if (!logInfoArray->serialize(serializer.get())) {
3759 OSKextLog(/* kext */ NULL,
3760 kOSKextLogErrorLevel |
3761 kOSKextLogIPCFlag,
3762 "Failed to serialize log info for request from user space.");
3763 /* Incidental error; we're going to (try to) allow the request
3764 * itself to succeed. */
3765 } else {
3766 logInfo = serializer->text();
3767 logInfoLength = serializer->getLength();
3768
3769 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3770 if (kmem_result != KERN_SUCCESS) {
3771 OSKextLog(/* kext */ NULL,
3772 kOSKextLogErrorLevel |
3773 kOSKextLogIPCFlag,
3774 "Failed to copy log info for request from user space.");
3775 /* Incidental error; we're going to (try to) allow the request
3776 * to succeed. */
3777 } else {
3778 /* 11981737 - clear uninitialized data in last page */
3779 bzero((void *)(buffer + logInfoLength),
3780 (round_page(logInfoLength) - logInfoLength));
3781 memcpy(buffer, logInfo, logInfoLength);
3782 *logInfoOut = buffer;
3783 *logInfoLengthOut = logInfoLength;
3784 }
3785 }
3786
3787 result = kOSReturnSuccess;
3788 finish:
3789 return result;
3790 }
3791
3792 #if PRAGMA_MARK
3793 #pragma mark Instance Management Methods
3794 #endif
3795 /*********************************************************************
3796 *********************************************************************/
3797 OSSharedPtr<OSKext>
3798 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3799 {
3800 OSSharedPtr<OSKext> foundKext;
3801
3802 IORecursiveLockLock(sKextLock);
3803 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
3804 IORecursiveLockUnlock(sKextLock);
3805
3806 return foundKext;
3807 }
3808
3809 /*********************************************************************
3810 *********************************************************************/
3811 OSSharedPtr<OSKext>
3812 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3813 {
3814 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3815 }
3816
3817 /*********************************************************************
3818 *********************************************************************/
3819 OSSharedPtr<OSKext>
3820 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3821 {
3822 OSSharedPtr<OSKext> foundKext; // returned
3823 uint32_t i, j;
3824 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3825 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3826
3827 IORecursiveLockLock(sKextLock);
3828
3829 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3830 for (i = 0; i < count[j]; i++) {
3831 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3832 if (thisKext->getLoadTag() == aTag) {
3833 foundKext.reset(thisKext, OSRetain);
3834 goto finish;
3835 }
3836 }
3837 }
3838
3839 finish:
3840 IORecursiveLockUnlock(sKextLock);
3841
3842 return foundKext;
3843 }
3844
3845 /*********************************************************************
3846 *********************************************************************/
3847 OSSharedPtr<OSKext>
3848 OSKext::lookupKextWithAddress(vm_address_t address)
3849 {
3850 OSSharedPtr<OSKext> foundKext; // returned
3851 uint32_t count, i;
3852 kmod_info_t *kmod_info;
3853 vm_address_t originalAddress;
3854 #if defined(__arm64__)
3855 uint64_t textExecBase;
3856 size_t textExecSize;
3857 #endif /* defined(__arm64__) */
3858
3859 originalAddress = address;
3860 #if __has_feature(ptrauth_calls)
3861 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3862 #endif /* __has_feature(ptrauth_calls) */
3863
3864 IORecursiveLockLock(sKextLock);
3865
3866 count = sLoadedKexts->getCount();
3867 for (i = 0; i < count; i++) {
3868 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3869 if (thisKext == sKernelKext) {
3870 continue;
3871 }
3872 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3873 kmod_info = thisKext->kmod_info;
3874 vm_address_t kext_start = kmod_info->address;
3875 vm_address_t kext_end = kext_start + kmod_info->size;
3876 if ((kext_start <= address) && (address < kext_end)) {
3877 foundKext.reset(thisKext, OSRetain);
3878 goto finish;
3879 }
3880 #if defined(__arm64__)
3881 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3882 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3883 foundKext.reset(thisKext, OSRetain);
3884 goto finish;
3885 }
3886 #endif /* defined (__arm64__) */
3887 }
3888 }
3889 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3890 foundKext.reset(sKernelKext, OSRetain);
3891 goto finish;
3892 }
3893 /*
3894 * DriverKit userspace executables do not have a kernel linkedExecutable,
3895 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3896 * here, so use the original address passed to this method.
3897 *
3898 * This is supposed to be used for logging reasons only. When logd
3899 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3900 * remove it here before checking it against the LoadTag.
3901 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3902 */
3903
3904 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
3905 count = sLoadedDriverKitKexts->getCount();
3906 for (i = 0; i < count; i++) {
3907 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
3908 if (thisKext->getLoadTag() == address) {
3909 foundKext.reset(thisKext, OSRetain);
3910 }
3911 }
3912
3913 finish:
3914 IORecursiveLockUnlock(sKextLock);
3915
3916 return foundKext;
3917 }
3918
3919 OSSharedPtr<OSData>
3920 OSKext::copyKextUUIDForAddress(OSNumber *address)
3921 {
3922 OSSharedPtr<OSData> uuid;
3923 OSSharedPtr<OSKext> kext;
3924
3925 if (!address) {
3926 return NULL;
3927 }
3928
3929 #if CONFIG_MACF
3930 /* Is the calling process allowed to query kext info? */
3931 if (current_task() != kernel_task) {
3932 int macCheckResult = 0;
3933 kauth_cred_t cred = NULL;
3934
3935 cred = kauth_cred_get_with_ref();
3936 macCheckResult = mac_kext_check_query(cred);
3937 kauth_cred_unref(&cred);
3938
3939 if (macCheckResult != 0) {
3940 OSKextLog(/* kext */ NULL,
3941 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3942 "Failed to query kext UUID (MAC policy error 0x%x).",
3943 macCheckResult);
3944 return NULL;
3945 }
3946 }
3947 #endif
3948
3949 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3950 if (slidAddress != 0) {
3951 kext = lookupKextWithAddress(slidAddress);
3952 if (kext) {
3953 uuid = kext->copyTextUUID();
3954 }
3955 }
3956
3957 if (!uuid) {
3958 /*
3959 * If we still don't have a UUID, then we failed to match the slid + stripped address with
3960 * a kext. This might have happened because the log message came from a dext.
3961 *
3962 * Try again with the original address.
3963 */
3964 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
3965 if (kext && kext->isDriverKit()) {
3966 uuid = kext->copyTextUUID();
3967 }
3968 }
3969
3970 return uuid;
3971 }
3972
3973 /*********************************************************************
3974 *********************************************************************/
3975 OSSharedPtr<OSKext>
3976 OSKext::lookupKextWithUUID(uuid_t wanted)
3977 {
3978 OSSharedPtr<OSKext> foundKext; // returned
3979 uint32_t j, i;
3980 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3981 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3982
3983
3984 IORecursiveLockLock(sKextLock);
3985
3986 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3987 for (i = 0; i < count[j]; i++) {
3988 OSKext * thisKext = NULL;
3989
3990 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3991 if (!thisKext) {
3992 continue;
3993 }
3994
3995 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
3996 if (!uuid_data) {
3997 continue;
3998 }
3999
4000 uuid_t uuid;
4001 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
4002
4003 if (0 == uuid_compare(wanted, uuid)) {
4004 foundKext.reset(thisKext, OSRetain);
4005 goto finish;
4006 }
4007 }
4008 }
4009 finish:
4010 IORecursiveLockUnlock(sKextLock);
4011
4012 return foundKext;
4013 }
4014
4015
4016
4017
4018 /*********************************************************************
4019 *********************************************************************/
4020 /* static */
4021 bool
4022 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4023 {
4024 bool result = false;
4025 OSKext * foundKext = NULL; // returned
4026
4027 IORecursiveLockLock(sKextLock);
4028
4029 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4030 if (foundKext && foundKext->isLoaded()) {
4031 result = true;
4032 }
4033
4034 IORecursiveLockUnlock(sKextLock);
4035
4036 return result;
4037 }
4038
4039 /*********************************************************************
4040 * xxx - should spawn a separate thread so a kext can safely have
4041 * xxx - itself unloaded.
4042 *********************************************************************/
4043 /* static */
4044 OSReturn
4045 OSKext::removeKext(
4046 OSKext * aKext,
4047 #if CONFIG_EMBEDDED
4048 __unused
4049 #endif
4050 bool terminateServicesAndRemovePersonalitiesFlag)
4051 {
4052 #if CONFIG_EMBEDDED
4053 OSKextLog(aKext,
4054 kOSKextLogErrorLevel |
4055 kOSKextLogKextBookkeepingFlag,
4056 "removeKext() called for %s, not supported on embedded",
4057 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4058
4059 return kOSReturnSuccess;
4060 #else /* CONFIG_EMBEDDED */
4061
4062 OSReturn result = kOSKextReturnInUse;
4063 OSKext * checkKext = NULL; // do not release
4064 #if CONFIG_MACF
4065 int macCheckResult = 0;
4066 kauth_cred_t cred = NULL;
4067 #endif
4068
4069 IORecursiveLockLock(sKextLock);
4070
4071 /* If the kext has no identifier, it failed to init
4072 * so isn't in sKextsByID and it isn't loaded.
4073 */
4074 if (!aKext->getIdentifier()) {
4075 result = kOSReturnSuccess;
4076 goto finish;
4077 }
4078
4079 checkKext = OSDynamicCast(OSKext,
4080 sKextsByID->getObject(aKext->getIdentifier()));
4081 if (checkKext != aKext) {
4082 result = kOSKextReturnNotFound;
4083 goto finish;
4084 }
4085
4086 if (aKext->isLoaded()) {
4087 #if CONFIG_MACF
4088 if (current_task() != kernel_task) {
4089 cred = kauth_cred_get_with_ref();
4090 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4091 kauth_cred_unref(&cred);
4092 }
4093
4094 if (macCheckResult != 0) {
4095 result = kOSReturnError;
4096 OSKextLog(aKext,
4097 kOSKextLogErrorLevel |
4098 kOSKextLogKextBookkeepingFlag,
4099 "Failed to remove kext %s (MAC policy error 0x%x).",
4100 aKext->getIdentifierCString(), macCheckResult);
4101 goto finish;
4102 }
4103 #endif
4104
4105 /* make sure there are no resource requests in flight - 17187548 */
4106 if (aKext->countRequestCallbacks()) {
4107 goto finish;
4108 }
4109 if (aKext->flags.unloadUnsupported) {
4110 result = kOSKextReturnInUse;
4111 OSKextLog(aKext,
4112 kOSKextLogErrorLevel |
4113 kOSKextLogKextBookkeepingFlag,
4114 "Can't remove kext %s; unsupported by cache.",
4115 aKext->getIdentifierCString());
4116 goto finish;
4117 }
4118
4119 /* If we are terminating, send the request to the IOCatalogue
4120 * (which will actually call us right back but that's ok we have
4121 * a recursive lock don't you know) but do not ask the IOCatalogue
4122 * to call back with an unload, we'll do that right here.
4123 */
4124 if (terminateServicesAndRemovePersonalitiesFlag) {
4125 result = gIOCatalogue->terminateDriversForModule(
4126 aKext->getIdentifierCString(), /* unload */ false);
4127 if (result != kOSReturnSuccess) {
4128 OSKextLog(aKext,
4129 kOSKextLogErrorLevel |
4130 kOSKextLogKextBookkeepingFlag,
4131 "Can't remove kext %s; services failed to terminate - 0x%x.",
4132 aKext->getIdentifierCString(), result);
4133 goto finish;
4134 }
4135 }
4136
4137 result = aKext->unload();
4138 if (result != kOSReturnSuccess) {
4139 goto finish;
4140 }
4141 }
4142
4143 /* Remove personalities as requested. This is a bit redundant for a loaded
4144 * kext as IOCatalogue::terminateDriversForModule() removes driver
4145 * personalities, but it doesn't restart matching, which we always want
4146 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4147 * that happens.
4148 */
4149 if (terminateServicesAndRemovePersonalitiesFlag) {
4150 aKext->removePersonalitiesFromCatalog();
4151 }
4152
4153 if (aKext->isInFileset()) {
4154 OSKextLog(aKext,
4155 kOSKextLogProgressLevel |
4156 kOSKextLogKextBookkeepingFlag,
4157 "Fileset kext %s unloaded.",
4158 aKext->getIdentifierCString());
4159 } else {
4160 OSKextLog(aKext,
4161 kOSKextLogProgressLevel |
4162 kOSKextLogKextBookkeepingFlag,
4163 "Removing kext %s.",
4164 aKext->getIdentifierCString());
4165
4166 sKextsByID->removeObject(aKext->getIdentifier());
4167 }
4168 result = kOSReturnSuccess;
4169
4170 finish:
4171 IORecursiveLockUnlock(sKextLock);
4172 return result;
4173 #endif /* CONFIG_EMBEDDED */
4174 }
4175
4176 /*********************************************************************
4177 *********************************************************************/
4178 /* static */
4179 OSReturn
4180 OSKext::removeKextWithIdentifier(
4181 const char * kextIdentifier,
4182 bool terminateServicesAndRemovePersonalitiesFlag)
4183 {
4184 OSReturn result = kOSReturnError;
4185
4186 IORecursiveLockLock(sKextLock);
4187
4188 OSKext * aKext = OSDynamicCast(OSKext,
4189 sKextsByID->getObject(kextIdentifier));
4190 if (!aKext) {
4191 result = kOSKextReturnNotFound;
4192 OSKextLog(/* kext */ NULL,
4193 kOSKextLogErrorLevel |
4194 kOSKextLogKextBookkeepingFlag,
4195 "Can't remove kext %s - not found.",
4196 kextIdentifier);
4197 goto finish;
4198 }
4199
4200 result = OSKext::removeKext(aKext,
4201 terminateServicesAndRemovePersonalitiesFlag);
4202
4203 finish:
4204 IORecursiveLockUnlock(sKextLock);
4205
4206 return result;
4207 }
4208
4209 /*********************************************************************
4210 *********************************************************************/
4211 /* static */
4212 OSReturn
4213 OSKext::removeKextWithLoadTag(
4214 OSKextLoadTag loadTag,
4215 bool terminateServicesAndRemovePersonalitiesFlag)
4216 {
4217 OSReturn result = kOSReturnError;
4218 OSKext * foundKext = NULL;
4219 uint32_t i, j;
4220 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4221 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4222
4223
4224 IORecursiveLockLock(sKextLock);
4225
4226 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4227 for (i = 0; i < count[j]; i++) {
4228 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4229 if (thisKext->loadTag == loadTag) {
4230 foundKext = thisKext;
4231 break;
4232 }
4233 }
4234 }
4235
4236 if (!foundKext) {
4237 result = kOSKextReturnNotFound;
4238 OSKextLog(/* kext */ NULL,
4239 kOSKextLogErrorLevel |
4240 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4241 "Can't remove kext with load tag %d - not found.",
4242 loadTag);
4243 goto finish;
4244 }
4245
4246 result = OSKext::removeKext(foundKext,
4247 terminateServicesAndRemovePersonalitiesFlag);
4248
4249 finish:
4250 IORecursiveLockUnlock(sKextLock);
4251
4252 return result;
4253 }
4254
4255 /*********************************************************************
4256 *********************************************************************/
4257 OSSharedPtr<OSDictionary>
4258 OSKext::copyKexts(void)
4259 {
4260 OSSharedPtr<OSDictionary> result;
4261
4262 IORecursiveLockLock(sKextLock);
4263 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4264 IORecursiveLockUnlock(sKextLock);
4265
4266 return result;
4267 }
4268
4269 /*********************************************************************
4270 *********************************************************************/
4271 #define BOOTER_KEXT_PREFIX "Driver-"
4272
4273 typedef struct _DeviceTreeBuffer {
4274 uint32_t paddr;
4275 uint32_t length;
4276 } _DeviceTreeBuffer;
4277
4278 /*********************************************************************
4279 * Create a dictionary of excluded kexts from the given booter data.
4280 *********************************************************************/
4281 /* static */
4282 void
4283 OSKext::createExcludeListFromBooterData(
4284 OSDictionary * theDictionary,
4285 OSCollectionIterator * theIterator )
4286 {
4287 OSString * deviceTreeName = NULL; // do not release
4288 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4289 char * booterDataPtr = NULL; // do not release
4290 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4291 char * infoDictAddr = NULL; // do not release
4292 OSSharedPtr<OSObject> parsedXML;
4293 OSDictionary * theInfoDict = NULL; // do not release
4294
4295 theIterator->reset();
4296
4297 /* look for AppleKextExcludeList.kext */
4298 while ((deviceTreeName =
4299 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4300 const char * devTreeNameCString;
4301 OSData * deviceTreeEntry; // do not release
4302 OSString * myBundleID; // do not release
4303
4304 deviceTreeEntry =
4305 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4306 if (!deviceTreeEntry) {
4307 continue;
4308 }
4309
4310 /* Make sure it is a kext */
4311 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4312 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4313 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4314 OSKextLog(NULL,
4315 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4316 "\"%s\" not a kext",
4317 devTreeNameCString);
4318 continue;
4319 }
4320
4321 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4322 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4323 if (!deviceTreeBuffer) {
4324 continue;
4325 }
4326
4327 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4328 if (!booterDataPtr) {
4329 continue;
4330 }
4331
4332 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4333 if (!kextFileInfo->infoDictPhysAddr ||
4334 !kextFileInfo->infoDictLength) {
4335 continue;
4336 }
4337
4338 infoDictAddr = (char *)
4339 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4340 if (!infoDictAddr) {
4341 continue;
4342 }
4343
4344 parsedXML = OSUnserializeXML(infoDictAddr);
4345 if (!parsedXML) {
4346 continue;
4347 }
4348
4349 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4350 if (!theInfoDict) {
4351 continue;
4352 }
4353
4354 myBundleID =
4355 OSDynamicCast(OSString,
4356 theInfoDict->getObject(kCFBundleIdentifierKey));
4357 if (myBundleID &&
4358 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4359 boolean_t updated = updateExcludeList(theInfoDict);
4360 if (!updated) {
4361 /* 25322874 */
4362 panic("Missing OSKextExcludeList dictionary\n");
4363 }
4364 break;
4365 }
4366 } // while ( (deviceTreeName = ...) )
4367
4368 return;
4369 }
4370
4371 /*********************************************************************
4372 * Create a dictionary of excluded kexts from the given prelink
4373 * info (kernelcache).
4374 *********************************************************************/
4375 /* static */
4376 void
4377 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4378 {
4379 OSDictionary * myInfoDict = NULL; // do not release
4380 OSString * myBundleID; // do not release
4381 u_int i;
4382
4383 /* Find the Apple Kext Exclude List. */
4384 for (i = 0; i < theInfoArray->getCount(); i++) {
4385 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4386 if (!myInfoDict) {
4387 continue;
4388 }
4389 myBundleID =
4390 OSDynamicCast(OSString,
4391 myInfoDict->getObject(kCFBundleIdentifierKey));
4392 if (myBundleID &&
4393 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4394 boolean_t updated = updateExcludeList(myInfoDict);
4395 if (!updated) {
4396 /* 25322874 */
4397 panic("Missing OSKextExcludeList dictionary\n");
4398 }
4399 break;
4400 }
4401 } // for (i = 0; i < theInfoArray->getCount()...
4402
4403 return;
4404 }
4405
4406 /* static */
4407 boolean_t
4408 OSKext::updateExcludeList(OSDictionary *infoDict)
4409 {
4410 OSDictionary *myTempDict = NULL; // do not free
4411 OSString *myTempString = NULL; // do not free
4412 OSKextVersion newVersion = 0;
4413 boolean_t updated = false;
4414
4415 if (!infoDict) {
4416 return false;
4417 }
4418
4419 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4420 if (!myTempDict) {
4421 return false;
4422 }
4423
4424 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4425 if (!myTempString) {
4426 return false;
4427 }
4428
4429 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4430 if (newVersion == 0) {
4431 return false;
4432 }
4433
4434 IORecursiveLockLock(sKextLock);
4435
4436 if (newVersion > sExcludeListVersion) {
4437 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4438 sExcludeListVersion = newVersion;
4439 updated = true;
4440 }
4441
4442 IORecursiveLockUnlock(sKextLock);
4443 return updated;
4444 }
4445
4446 #if PRAGMA_MARK
4447 #pragma mark Accessors
4448 #endif
4449 /*********************************************************************
4450 *********************************************************************/
4451 const OSSymbol *
4452 OSKext::getIdentifier(void)
4453 {
4454 return bundleID.get();
4455 }
4456
4457 /*********************************************************************
4458 * A kext must have a bundle identifier to even survive initialization;
4459 * this is guaranteed to exist past then.
4460 *********************************************************************/
4461 const char *
4462 OSKext::getIdentifierCString(void)
4463 {
4464 return bundleID->getCStringNoCopy();
4465 }
4466
4467 /*********************************************************************
4468 *********************************************************************/
4469 OSKextVersion
4470 OSKext::getVersion(void)
4471 {
4472 return version;
4473 }
4474
4475 /*********************************************************************
4476 *********************************************************************/
4477 OSKextVersion
4478 OSKext::getCompatibleVersion(void)
4479 {
4480 return compatibleVersion;
4481 }
4482
4483 /*********************************************************************
4484 *********************************************************************/
4485 bool
4486 OSKext::isLibrary(void)
4487 {
4488 return getCompatibleVersion() > 0;
4489 }
4490
4491 /*********************************************************************
4492 *********************************************************************/
4493 bool
4494 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4495 {
4496 if ((compatibleVersion > -1 && version > -1) &&
4497 (compatibleVersion <= version && aVersion <= version)) {
4498 return true;
4499 }
4500 return false;
4501 }
4502
4503 /*********************************************************************
4504 *********************************************************************/
4505 bool
4506 OSKext::declaresExecutable(void)
4507 {
4508 if (isDriverKit()) {
4509 return false;
4510 }
4511 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4512 }
4513
4514 /*********************************************************************
4515 *********************************************************************/
4516 OSData *
4517 OSKext::getExecutable(void)
4518 {
4519 OSData * result = NULL;
4520 OSSharedPtr<OSData> extractedExecutable;
4521
4522 if (flags.builtin) {
4523 return sKernelKext->linkedExecutable.get();
4524 }
4525
4526 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4527 if (result) {
4528 return result;
4529 }
4530
4531 #if CONFIG_KXLD
4532 OSData * mkextExecutableRef = NULL; // do not release
4533 mkextExecutableRef = OSDynamicCast(OSData,
4534 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4535
4536 if (mkextExecutableRef) {
4537 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4538 mkextExecutableRef->getBytesNoCopy();
4539 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4540 if (mkextVersion == MKEXT_VERS_2) {
4541 mkext2_file_entry * fileinfo =
4542 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4543 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4544 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4545 extractedExecutable = extractMkext2FileData(
4546 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4547 compressedSize, fullSize);
4548 } else {
4549 OSKextLog(this, kOSKextLogErrorLevel |
4550 kOSKextLogArchiveFlag,
4551 "Kext %s - unknown mkext version 0x%x for executable.",
4552 getIdentifierCString(), mkextVersion);
4553 }
4554
4555 /* Regardless of success, remove the mkext executable,
4556 * and drop one reference on the mkext. (setExecutable() does not
4557 * replace, it removes, or panics if asked to replace.)
4558 */
4559 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4560 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4561
4562 if (extractedExecutable && extractedExecutable->getLength()) {
4563 if (!setExecutable(extractedExecutable.get())) {
4564 goto finish;
4565 }
4566 result = extractedExecutable.get();
4567 } else {
4568 goto finish;
4569 }
4570 }
4571
4572 finish:
4573 #endif // CONFIG_KXLD
4574 return result;
4575 }
4576
4577 /*********************************************************************
4578 *********************************************************************/
4579 bool
4580 OSKext::isInterface(void)
4581 {
4582 return flags.interface;
4583 }
4584
4585 /*********************************************************************
4586 *********************************************************************/
4587 bool
4588 OSKext::isKernel(void)
4589 {
4590 return this == sKernelKext;
4591 }
4592
4593 /*********************************************************************
4594 *********************************************************************/
4595 bool
4596 OSKext::isKernelComponent(void)
4597 {
4598 return flags.kernelComponent ? true : false;
4599 }
4600
4601 /*********************************************************************
4602 *********************************************************************/
4603 bool
4604 OSKext::isExecutable(void)
4605 {
4606 return !isKernel() && !isInterface() && declaresExecutable();
4607 }
4608
4609 /*********************************************************************
4610 * We might want to check this recursively for all dependencies,
4611 * since a subtree of dependencies could get loaded before we hit
4612 * a dependency that isn't safe-boot-loadable.
4613 *
4614 * xxx - Might want to return false if OSBundleEnableKextLogging or
4615 * OSBundleDebugLevel
4616 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4617 * the point except it's usually development drivers, which might
4618 * cause panics on startup, that have those properties). Heh; could
4619 * use a "kx" boot-arg!
4620 *********************************************************************/
4621 bool
4622 OSKext::isLoadableInSafeBoot(void)
4623 {
4624 bool result = false;
4625 OSString * required = NULL; // do not release
4626
4627 if (isKernel()) {
4628 result = true;
4629 goto finish;
4630 }
4631
4632 if (isDriverKit()) {
4633 result = true;
4634 goto finish;
4635 }
4636
4637 required = OSDynamicCast(OSString,
4638 getPropertyForHostArch(kOSBundleRequiredKey));
4639 if (!required) {
4640 goto finish;
4641 }
4642 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4643 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4644 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4645 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4646 required->isEqualTo(kOSBundleRequiredConsole)) {
4647 result = true;
4648 }
4649
4650 finish:
4651 return result;
4652 }
4653
4654 /*********************************************************************
4655 *********************************************************************/
4656 bool
4657 OSKext::isPrelinked(void)
4658 {
4659 return flags.prelinked ? true : false;
4660 }
4661
4662 /*********************************************************************
4663 *********************************************************************/
4664 bool
4665 OSKext::isLoaded(void)
4666 {
4667 return flags.loaded ? true : false;
4668 }
4669
4670 /*********************************************************************
4671 *********************************************************************/
4672 bool
4673 OSKext::isStarted(void)
4674 {
4675 return flags.started ? true : false;
4676 }
4677
4678 /*********************************************************************
4679 *********************************************************************/
4680 bool
4681 OSKext::isCPPInitialized(void)
4682 {
4683 return flags.CPPInitialized;
4684 }
4685
4686 /*********************************************************************
4687 *********************************************************************/
4688 void
4689 OSKext::setCPPInitialized(bool initialized)
4690 {
4691 flags.CPPInitialized = initialized;
4692 }
4693
4694 /*********************************************************************
4695 *********************************************************************/
4696 uint32_t
4697 OSKext::getLoadTag(void)
4698 {
4699 return loadTag;
4700 }
4701
4702 /*********************************************************************
4703 *********************************************************************/
4704 void
4705 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4706 {
4707 if (linkedExecutable) {
4708 *loadSize = linkedExecutable->getLength();
4709
4710 /* If we have a kmod_info struct, calculated the wired size
4711 * from that. Otherwise it's the full load size.
4712 */
4713 if (kmod_info) {
4714 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
4715 } else {
4716 *wiredSize = *loadSize;
4717 }
4718 } else {
4719 *wiredSize = 0;
4720 *loadSize = 0;
4721 }
4722 }
4723
4724 /*********************************************************************
4725 *********************************************************************/
4726 OSSharedPtr<OSData>
4727 OSKext::copyUUID(void)
4728 {
4729 OSSharedPtr<OSData> result;
4730 OSData * theExecutable = NULL; // do not release
4731 const kernel_mach_header_t * header;
4732
4733 /* An interface kext doesn't have a linked executable with an LC_UUID,
4734 * we create one when it's linked.
4735 */
4736 if (interfaceUUID) {
4737 result = interfaceUUID;
4738 goto finish;
4739 }
4740
4741 if (flags.builtin || isInterface()) {
4742 return sKernelKext->copyUUID();
4743 }
4744
4745 if (isDriverKit() && infoDict) {
4746 return driverKitUUID;
4747 }
4748
4749 /* For real kexts, try to get the UUID from the linked executable,
4750 * or if is hasn't been linked yet, the unrelocated executable.
4751 */
4752 theExecutable = linkedExecutable.get();
4753 if (!theExecutable) {
4754 theExecutable = getExecutable();
4755 }
4756
4757 if (!theExecutable) {
4758 goto finish;
4759 }
4760
4761 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4762 result = copyMachoUUID(header);
4763
4764 finish:
4765 return result;
4766 }
4767
4768 /*********************************************************************
4769 *********************************************************************/
4770 OSSharedPtr<OSData>
4771 OSKext::copyTextUUID(void)
4772 {
4773 if (flags.builtin) {
4774 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4775 }
4776 return copyUUID();
4777 }
4778
4779 /*********************************************************************
4780 *********************************************************************/
4781 OSSharedPtr<OSData>
4782 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4783 {
4784 OSSharedPtr<OSData> result;
4785 const struct load_command * load_cmd = NULL;
4786 const struct uuid_command * uuid_cmd = NULL;
4787 uint32_t i;
4788
4789 load_cmd = (const struct load_command *)&header[1];
4790
4791 if (header->magic != MH_MAGIC_KERNEL) {
4792 OSKextLog(NULL,
4793 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4794 "%s: bad header %p",
4795 __func__,
4796 header);
4797 goto finish;
4798 }
4799
4800 for (i = 0; i < header->ncmds; i++) {
4801 if (load_cmd->cmd == LC_UUID) {
4802 uuid_cmd = (struct uuid_command *)load_cmd;
4803 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4804 goto finish;
4805 }
4806 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4807 }
4808
4809 finish:
4810 return result;
4811 }
4812
4813 void
4814 OSKext::setDriverKitUUID(OSData *uuid)
4815 {
4816 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4817 OSSafeReleaseNULL(uuid);
4818 }
4819 }
4820
4821 /*********************************************************************
4822 *********************************************************************/
4823 #if defined (__arm__)
4824 #include <arm/arch.h>
4825 #endif
4826
4827 #if defined (__x86_64__)
4828 #define ARCHNAME "x86_64"
4829 #elif defined (__arm64__)
4830 #define ARCHNAME "arm64"
4831 #elif defined (__arm__)
4832
4833 #if defined (__ARM_ARCH_7S__)
4834 #define ARCHNAME "armv7s"
4835 #elif defined (__ARM_ARCH_7F__)
4836 #define ARCHNAME "armv7f"
4837 #elif defined (__ARM_ARCH_7K__)
4838 #define ARCHNAME "armv7k"
4839 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4840 #define ARCHNAME "armv7"
4841 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4842 #define ARCHNAME "armv6"
4843 #endif
4844
4845 #elif defined (__arm64__)
4846 #define ARCHNAME "arm64"
4847 #else
4848 #error architecture not supported
4849 #endif
4850
4851 #define ARCH_SEPARATOR_CHAR '_'
4852
4853 static char *
4854 makeHostArchKey(const char * key, size_t * keySizeOut)
4855 {
4856 char * result = NULL;
4857 size_t keyLength = strlen(key);
4858 size_t keySize;
4859
4860 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4861 */
4862 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4863 result = (char *)kheap_alloc_tag(KHEAP_TEMP, keySize,
4864 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4865
4866 if (!result) {
4867 goto finish;
4868 }
4869 strlcpy(result, key, keySize);
4870 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4871 result[keyLength] = '\0';
4872 strlcat(result, ARCHNAME, keySize);
4873 *keySizeOut = keySize;
4874
4875 finish:
4876 return result;
4877 }
4878
4879 /*********************************************************************
4880 *********************************************************************/
4881 OSObject *
4882 OSKext::getPropertyForHostArch(const char * key)
4883 {
4884 OSObject * result = NULL;// do not release
4885 size_t hostArchKeySize = 0;
4886 char * hostArchKey = NULL;// must kfree
4887
4888 if (!key || !infoDict) {
4889 goto finish;
4890 }
4891
4892 /* Some properties are not allowed to be arch-variant:
4893 * - Any CFBundle... property.
4894 * - OSBundleIsInterface.
4895 * - OSKernelResource.
4896 */
4897 if (STRING_HAS_PREFIX(key, "OS") ||
4898 STRING_HAS_PREFIX(key, "IO")) {
4899 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4900 if (!hostArchKey) {
4901 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4902 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4903 "Allocation failure.");
4904 goto finish;
4905 }
4906 result = infoDict->getObject(hostArchKey);
4907 }
4908
4909 if (!result) {
4910 result = infoDict->getObject(key);
4911 }
4912
4913 finish:
4914 if (hostArchKey) {
4915 kheap_free(KHEAP_TEMP, hostArchKey, hostArchKeySize);
4916 }
4917 return result;
4918 }
4919
4920 #if PRAGMA_MARK
4921 #pragma mark Load/Start/Stop/Unload
4922 #endif
4923
4924 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4925
4926 /*********************************************************************
4927 * sExcludeListByID is a dictionary with keys / values of:
4928 * key = bundleID string of kext we will not allow to load
4929 * value = version string(s) of the kext that is to be denied loading.
4930 * The version strings can be comma delimited. For example if kext
4931 * com.foocompany.fookext has two versions that we want to deny
4932 * loading then the version strings might look like:
4933 * 1.0.0, 1.0.1
4934 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4935 * not load the kext.
4936 *
4937 * Value may also be in the form of "LE 2.0.0" (version numbers
4938 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4939 * number less than 2.0.0 will not load)
4940 *
4941 * NOTE - we cannot use the characters "<=" or "<" because we have code
4942 * that serializes plists and treats '<' as a special character.
4943 *********************************************************************/
4944 bool
4945 OSKext::isInExcludeList(void)
4946 {
4947 OSString * versionString = NULL; // do not release
4948 char * versionCString = NULL; // do not free
4949 size_t i;
4950 boolean_t wantLessThan = false;
4951 boolean_t wantLessThanEqualTo = false;
4952 boolean_t isInExcludeList = true;
4953 char myBuffer[32];
4954
4955 IORecursiveLockLock(sKextLock);
4956
4957 if (!sExcludeListByID) {
4958 isInExcludeList = false;
4959 } else {
4960 /* look up by bundleID in our exclude list and if found get version
4961 * string (or strings) that we will not allow to load
4962 */
4963 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
4964 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
4965 isInExcludeList = false;
4966 }
4967 }
4968
4969 IORecursiveLockUnlock(sKextLock);
4970
4971 if (!isInExcludeList) {
4972 return false;
4973 }
4974
4975 /* parse version strings */
4976 versionCString = (char *) versionString->getCStringNoCopy();
4977
4978 /* look for "LT" or "LE" form of version string, must be in first two
4979 * positions.
4980 */
4981 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
4982 wantLessThan = true;
4983 versionCString += 2;
4984 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
4985 wantLessThanEqualTo = true;
4986 versionCString += 2;
4987 }
4988
4989 for (i = 0; *versionCString != 0x00; versionCString++) {
4990 /* skip whitespace */
4991 if (isWhiteSpace(*versionCString)) {
4992 continue;
4993 }
4994
4995 /* peek ahead for version string separator or null terminator */
4996 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
4997 /* OK, we have a version string */
4998 myBuffer[i++] = *versionCString;
4999 myBuffer[i] = 0x00;
5000
5001 OSKextVersion excludeVers;
5002 excludeVers = OSKextParseVersionString(myBuffer);
5003
5004 if (wantLessThanEqualTo) {
5005 if (version <= excludeVers) {
5006 return true;
5007 }
5008 } else if (wantLessThan) {
5009 if (version < excludeVers) {
5010 return true;
5011 }
5012 } else if (version == excludeVers) {
5013 return true;
5014 }
5015
5016 /* reset for the next (if any) version string */
5017 i = 0;
5018 wantLessThan = false;
5019 wantLessThanEqualTo = false;
5020 } else {
5021 /* save valid version character */
5022 myBuffer[i++] = *versionCString;
5023
5024 /* make sure bogus version string doesn't overrun local buffer */
5025 if (i >= sizeof(myBuffer)) {
5026 break;
5027 }
5028 }
5029 }
5030
5031 return false;
5032 }
5033
5034 /*********************************************************************
5035 * sNonLoadableKextsByID is a dictionary with keys / values of:
5036 * key = bundleID string of kext we will not allow to load
5037 * value = boolean (true == loadable, false == not loadable)
5038 *
5039 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5040 * i.e., the value for the kext's bundleID will be false. All kexts in
5041 * the primary and system KCs will always be marked as "loadable."
5042 *
5043 * This list ultimately comes from kexts which have been uninstalled
5044 * in user space by deleting the kext from disk, but which have not
5045 * yet been removed from the AuxKC. Because the user could choose to
5046 * re-install the exact same version of the kext, we need to keep
5047 * a dictionary of boolean values so that user space only needs to
5048 * keep a simple list of "uninstalled" or "missing" bundles. When
5049 * a bundle is re-installed, the iokit daemon can use the
5050 * AucKCBundleAvailable predicate to set the individual kext's
5051 * availability to true.
5052 *********************************************************************/
5053 bool
5054 OSKext::isLoadable(void)
5055 {
5056 bool isLoadable = true;
5057
5058 if (kc_type != KCKindAuxiliary) {
5059 /* this filtering only applies to kexts in the auxkc */
5060 return true;
5061 }
5062
5063 IORecursiveLockLock(sKextLock);
5064
5065 if (sNonLoadableKextsByID) {
5066 /* look up by bundleID in our exclude list and if found get version
5067 * string (or strings) that we will not allow to load
5068 */
5069 OSBoolean *loadableVal;
5070 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5071 if (loadableVal && !loadableVal->getValue()) {
5072 isLoadable = false;
5073 }
5074 }
5075 IORecursiveLockUnlock(sKextLock);
5076
5077 return isLoadable;
5078 }
5079
5080 /*********************************************************************
5081 *********************************************************************/
5082 /* static */
5083 OSReturn
5084 OSKext::loadKextWithIdentifier(
5085 const char * kextIdentifierCString,
5086 Boolean allowDeferFlag,
5087 Boolean delayAutounloadFlag,
5088 OSKextExcludeLevel startOpt,
5089 OSKextExcludeLevel startMatchingOpt,
5090 OSArray * personalityNames)
5091 {
5092 OSReturn result = kOSReturnError;
5093 OSSharedPtr<OSString> kextIdentifier;
5094
5095 kextIdentifier = OSString::withCString(kextIdentifierCString);
5096 if (!kextIdentifier) {
5097 result = kOSKextReturnNoMemory;
5098 goto finish;
5099 }
5100 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5101 NULL /* kextRef */,
5102 allowDeferFlag, delayAutounloadFlag,
5103 startOpt, startMatchingOpt, personalityNames);
5104
5105 finish:
5106 return result;
5107 }
5108
5109 OSReturn
5110 OSKext::loadKextWithIdentifier(
5111 OSString * kextIdentifier,
5112 OSSharedPtr<OSObject> &kextRef,
5113 Boolean allowDeferFlag,
5114 Boolean delayAutounloadFlag,
5115 OSKextExcludeLevel startOpt,
5116 OSKextExcludeLevel startMatchingOpt,
5117 OSArray * personalityNames)
5118 {
5119 OSObject * kextRefRaw = NULL;
5120 OSReturn result;
5121
5122 result = loadKextWithIdentifier(kextIdentifier,
5123 &kextRefRaw,
5124 allowDeferFlag,
5125 delayAutounloadFlag,
5126 startOpt,
5127 startMatchingOpt,
5128 personalityNames);
5129 if ((kOSReturnSuccess == result) && kextRefRaw) {
5130 kextRef.reset(kextRefRaw, OSNoRetain);
5131 }
5132 return result;
5133 }
5134
5135 /*********************************************************************
5136 *********************************************************************/
5137 OSReturn
5138 OSKext::loadKextWithIdentifier(
5139 OSString * kextIdentifier,
5140 OSObject ** kextRef,
5141 Boolean allowDeferFlag,
5142 Boolean delayAutounloadFlag,
5143 OSKextExcludeLevel startOpt,
5144 OSKextExcludeLevel startMatchingOpt,
5145 OSArray * personalityNames)
5146 {
5147 OSReturn result = kOSReturnError;
5148 OSReturn pingResult = kOSReturnError;
5149 OSKext * theKext = NULL; // do not release
5150 OSSharedPtr<OSDictionary> loadRequest;
5151 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5152
5153 if (kextRef) {
5154 *kextRef = NULL;
5155 }
5156
5157 IORecursiveLockLock(sKextLock);
5158
5159 if (!kextIdentifier) {
5160 result = kOSKextReturnInvalidArgument;
5161 goto finish;
5162 }
5163
5164 OSKext::recordIdentifierRequest(kextIdentifier);
5165
5166 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5167 if (!theKext) {
5168 if (!allowDeferFlag) {
5169 OSKextLog(/* kext */ NULL,
5170 kOSKextLogErrorLevel |
5171 kOSKextLogLoadFlag,
5172 "Can't load kext %s - not found.",
5173 kextIdentifier->getCStringNoCopy());
5174 goto finish;
5175 }
5176
5177 if (!sKernelRequestsEnabled) {
5178 OSKextLog(theKext,
5179 kOSKextLogErrorLevel |
5180 kOSKextLogLoadFlag,
5181 "Can't load kext %s - requests to user space are disabled.",
5182 kextIdentifier->getCStringNoCopy());
5183 result = kOSKextReturnDisabled;
5184 goto finish;
5185 }
5186
5187 /* Create a new request unless one is already sitting
5188 * in sKernelRequests for this bundle identifier
5189 */
5190 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5191 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5192 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5193 loadRequest);
5194 if (result != kOSReturnSuccess) {
5195 goto finish;
5196 }
5197 if (!_OSKextSetRequestArgument(loadRequest.get(),
5198 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5199 result = kOSKextReturnNoMemory;
5200 goto finish;
5201 }
5202 if (!sKernelRequests->setObject(loadRequest.get())) {
5203 result = kOSKextReturnNoMemory;
5204 goto finish;
5205 }
5206
5207 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5208 result = kOSKextReturnNoMemory;
5209 goto finish;
5210 }
5211
5212 OSKextLog(theKext,
5213 kOSKextLogDebugLevel |
5214 kOSKextLogLoadFlag,
5215 "Kext %s not found; queued load request to user space.",
5216 kextIdentifier->getCStringNoCopy());
5217 }
5218
5219 pingResult = OSKext::pingIOKitDaemon();
5220 if (pingResult == kOSKextReturnDisabled) {
5221 OSKextLog(/* kext */ NULL,
5222 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5223 kOSKextLogLoadFlag,
5224 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5225 kextIdentifier->getCStringNoCopy());
5226 }
5227
5228 result = kOSKextReturnDeferred;
5229 goto finish;
5230 }
5231
5232 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5233
5234 if (result != kOSReturnSuccess) {
5235 OSKextLog(theKext,
5236 kOSKextLogErrorLevel |
5237 kOSKextLogLoadFlag,
5238 "Failed to load kext %s (error 0x%x).",
5239 kextIdentifier->getCStringNoCopy(), (int)result);
5240
5241 if (theKext->kc_type == KCKindUnknown) {
5242 OSKext::removeKext(theKext,
5243 /* terminateService/removePersonalities */ true);
5244 }
5245 goto finish;
5246 }
5247
5248 if (delayAutounloadFlag) {
5249 OSKextLog(theKext,
5250 kOSKextLogProgressLevel |
5251 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5252 "Setting delayed autounload for %s.",
5253 kextIdentifier->getCStringNoCopy());
5254 theKext->flags.delayAutounload = 1;
5255 }
5256
5257 finish:
5258 if ((kOSReturnSuccess == result) && kextRef) {
5259 *kextRef = theKext;
5260 theKext->matchingRefCount++;
5261 theKext->retain();
5262 }
5263
5264 IORecursiveLockUnlock(sKextLock);
5265
5266 return result;
5267 }
5268
5269 /*********************************************************************
5270 *********************************************************************/
5271 /* static */
5272 OSReturn
5273 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5274 {
5275 OSReturn result = kOSReturnError;
5276
5277 OSBoolean *delayAutounloadBool = NULL; // do not release
5278 OSNumber *startKextExcludeNum = NULL; // do not release
5279 OSNumber *startMatchingExcludeNum = NULL; // do not release
5280 OSArray *personalityNames = NULL; // do not release
5281
5282 /*
5283 * Default values for these options:
5284 * regular autounload behavior
5285 * start the kext
5286 * send all personalities to the catalog
5287 */
5288 Boolean delayAutounload = false;
5289 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5290 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5291
5292 IORecursiveLockLock(sKextLock);
5293
5294 OSKextLog(/* kext */ NULL,
5295 kOSKextLogDebugLevel |
5296 kOSKextLogIPCFlag,
5297 "Received kext KC load request from user space.");
5298
5299 /* Regardless of processing, the fact that we have gotten here means some
5300 * user-space program is up and talking to us, so we'll switch our kext
5301 * registration to reflect that.
5302 */
5303 if (!sUserLoadsActive) {
5304 OSKextLog(/* kext */ NULL,
5305 kOSKextLogProgressLevel |
5306 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5307 "Switching to late startup (user-space) kext loading policy.");
5308 sUserLoadsActive = true;
5309 }
5310
5311 delayAutounloadBool = OSDynamicCast(OSBoolean,
5312 _OSKextGetRequestArgument(requestDict,
5313 kKextRequestArgumentDelayAutounloadKey));
5314 startKextExcludeNum = OSDynamicCast(OSNumber,
5315 _OSKextGetRequestArgument(requestDict,
5316 kKextRequestArgumentStartExcludeKey));
5317 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5318 _OSKextGetRequestArgument(requestDict,
5319 kKextRequestArgumentStartMatchingExcludeKey));
5320 personalityNames = OSDynamicCast(OSArray,
5321 _OSKextGetRequestArgument(requestDict,
5322 kKextRequestArgumentPersonalityNamesKey));
5323
5324 if (delayAutounloadBool) {
5325 delayAutounload = delayAutounloadBool->getValue();
5326 }
5327 if (startKextExcludeNum) {
5328 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5329 }
5330 if (startMatchingExcludeNum) {
5331 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5332 }
5333
5334 OSKextLog(/* kext */ NULL,
5335 kOSKextLogProgressLevel |
5336 kOSKextLogIPCFlag,
5337 "Received request from user space to load KC kext %s.",
5338 theKext->getIdentifierCString());
5339
5340 /* this could be in the Auxiliary KC, so record the load request */
5341 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5342
5343 /*
5344 * Load the kext
5345 */
5346 result = theKext->load(startKextExcludeLevel,
5347 startMatchingExcludeLevel, personalityNames);
5348
5349 if (result != kOSReturnSuccess) {
5350 OSKextLog(theKext,
5351 kOSKextLogErrorLevel |
5352 kOSKextLogLoadFlag,
5353 "Failed to load kext %s (error 0x%x).",
5354 theKext->getIdentifierCString(), (int)result);
5355
5356 OSKext::removeKext(theKext,
5357 /* terminateService/removePersonalities */ true);
5358 goto finish;
5359 } else {
5360 OSKextLog(theKext,
5361 kOSKextLogProgressLevel |
5362 kOSKextLogLoadFlag,
5363 "Kext %s Loaded successfully from %s KC",
5364 theKext->getIdentifierCString(), theKext->getKCTypeString());
5365 }
5366
5367 if (delayAutounload) {
5368 OSKextLog(theKext,
5369 kOSKextLogProgressLevel |
5370 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5371 "Setting delayed autounload for %s.",
5372 theKext->getIdentifierCString());
5373 theKext->flags.delayAutounload = 1;
5374 }
5375
5376 finish:
5377 IORecursiveLockUnlock(sKextLock);
5378
5379 return result;
5380 }
5381
5382 /*********************************************************************
5383 *********************************************************************/
5384 /* static */
5385 OSReturn
5386 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5387 {
5388 OSReturn result = kOSReturnError;
5389 OSDictionary *anInfoDict = NULL; // do not release
5390
5391 anInfoDict = OSDynamicCast(OSDictionary,
5392 _OSKextGetRequestArgument(requestDict,
5393 kKextRequestArgumentCodelessInfoKey));
5394 if (anInfoDict == NULL) {
5395 OSKextLog(/* kext */ NULL,
5396 kOSKextLogErrorLevel |
5397 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5398 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5399 kextIdentifier->getCStringNoCopy());
5400 return kOSKextReturnInvalidArgument;
5401 }
5402
5403 IORecursiveLockLock(sKextLock);
5404
5405 OSKextLog(/* kext */ NULL,
5406 kOSKextLogProgressLevel |
5407 kOSKextLogIPCFlag,
5408 "Received request from user space to load codeless kext %s.",
5409 kextIdentifier->getCStringNoCopy());
5410
5411 {
5412 // instantiate a new kext, and don't hold a reference
5413 // (the kext subsystem will hold one implicitly)
5414 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5415 if (!newKext) {
5416 OSKextLog(/* kext */ NULL,
5417 kOSKextLogErrorLevel |
5418 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5419 "Could not instantiate codeless kext.");
5420 result = kOSKextReturnNotLoadable;
5421 goto finish;
5422 }
5423 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5424 OSKextLog(/* kext */ NULL,
5425 kOSKextLogErrorLevel |
5426 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5427 "Codeless kext identifiers don't match '%s' != '%s'",
5428 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5429
5430 OSKext::removeKext(newKext.get(), false);
5431 result = kOSKextReturnInvalidArgument;
5432 goto finish;
5433 }
5434
5435 /* Record the request for the codeless kext */
5436 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5437
5438 result = kOSReturnSuccess;
5439 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5440 result = newKext->sendPersonalitiesToCatalog(true, NULL);
5441 }
5442
5443 finish:
5444 IORecursiveLockUnlock(sKextLock);
5445
5446 return result;
5447 }
5448
5449 /*********************************************************************
5450 *********************************************************************/
5451 /* static */
5452 void
5453 OSKext::dropMatchingReferences(
5454 OSSet * kexts)
5455 {
5456 IORecursiveLockLock(sKextLock);
5457 kexts->iterateObjects(^bool (OSObject * obj) {
5458 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5459 if (!thisKext) {
5460 return false;
5461 }
5462 thisKext->matchingRefCount--;
5463 return false;
5464 });
5465 IORecursiveLockUnlock(sKextLock);
5466 }
5467
5468 /*********************************************************************
5469 *********************************************************************/
5470 /* static */
5471 void
5472 OSKext::recordIdentifierRequest(
5473 OSString * kextIdentifier)
5474 {
5475 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5476 bool fail = false;
5477
5478 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5479 goto finish;
5480 }
5481
5482 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5483 if (!kextIdentifierSymbol) {
5484 // xxx - this is really a basic alloc failure
5485 fail = true;
5486 goto finish;
5487 }
5488
5489 IORecursiveLockLock(sKextLock);
5490 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5491 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5492 fail = true;
5493 } else {
5494 // xxx - need to find a way to associate this whole func w/the kext
5495 OSKextLog(/* kext */ NULL,
5496 // xxx - check level
5497 kOSKextLogStepLevel |
5498 kOSKextLogArchiveFlag,
5499 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5500 kextIdentifier->getCStringNoCopy());
5501 }
5502 }
5503 IORecursiveLockUnlock(sKextLock);
5504
5505 finish:
5506
5507 if (fail) {
5508 OSKextLog(/* kext */ NULL,
5509 kOSKextLogErrorLevel |
5510 kOSKextLogArchiveFlag,
5511 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5512 kextIdentifier->getCStringNoCopy());
5513 }
5514 return;
5515 }
5516
5517 /*********************************************************************
5518 *********************************************************************/
5519 OSReturn
5520 OSKext::load(
5521 OSKextExcludeLevel startOpt,
5522 OSKextExcludeLevel startMatchingOpt,
5523 OSArray * personalityNames)
5524 {
5525 OSReturn result = kOSReturnError;
5526 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5527 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5528 unsigned int i, count;
5529 Boolean alreadyLoaded = false;
5530 OSKext * lastLoadedKext = NULL; // do not release
5531
5532 if (isInExcludeList()) {
5533 OSKextLog(this,
5534 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5535 kOSKextLogLoadFlag,
5536 "Kext %s is in exclude list, not loadable",
5537 getIdentifierCString());
5538
5539 result = kOSKextReturnNotLoadable;
5540 goto finish;
5541 }
5542 if (!isLoadable()) {
5543 OSKextLog(this,
5544 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5545 kOSKextLogLoadFlag,
5546 "Kext %s is not loadable",
5547 getIdentifierCString());
5548
5549 result = kOSKextReturnNotLoadable;
5550 goto finish;
5551 }
5552
5553 if (isLoaded()) {
5554 alreadyLoaded = true;
5555 result = kOSReturnSuccess;
5556
5557 OSKextLog(this,
5558 kOSKextLogDebugLevel |
5559 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5560 "Kext %s is already loaded.",
5561 getIdentifierCString());
5562 goto loaded;
5563 }
5564
5565 #if CONFIG_MACF && XNU_TARGET_OS_OSX
5566 #if CONFIG_KXLD
5567 if (current_task() != kernel_task) {
5568 #else
5569 /*
5570 * On non-kxld systems, only check the mac-hook for kexts in the
5571 * Pageable and Aux KCs. This means on Apple silicon devices that
5572 * the mac hook will only be useful to block 3rd party kexts.
5573 *
5574 * Note that this should _not_ be called on kexts loaded from the
5575 * kernel bootstrap thread as the kernel proc's cred struct is not
5576 * yet initialized! This won't happen on macOS because all the kexts
5577 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5578 */
5579 if (kc_type != KCKindPrimary && kc_type != KCKindUnknown) {
5580 #endif /* CONFIG_KXLD */
5581 int macCheckResult = 0;
5582 kauth_cred_t cred = NULL;
5583
5584 cred = kauth_cred_get_with_ref();
5585 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5586 kauth_cred_unref(&cred);
5587
5588 if (macCheckResult != 0) {
5589 result = kOSReturnError;
5590 OSKextLog(this,
5591 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5592 "Failed to load kext %s (MAC policy error 0x%x).",
5593 getIdentifierCString(), macCheckResult);
5594 goto finish;
5595 }
5596 }
5597 #endif
5598
5599 if (!sLoadEnabled) {
5600 OSKextLog(this,
5601 kOSKextLogErrorLevel |
5602 kOSKextLogLoadFlag,
5603 "Kext loading is disabled (attempt to load kext %s).",
5604 getIdentifierCString());
5605 result = kOSKextReturnDisabled;
5606 goto finish;
5607 }
5608
5609 /* If we've pushed the next available load tag to the invalid value,
5610 * we can't load any more kexts.
5611 */
5612 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5613 OSKextLog(this,
5614 kOSKextLogErrorLevel |
5615 kOSKextLogLoadFlag,
5616 "Can't load kext %s - no more load tags to assign.",
5617 getIdentifierCString());
5618 result = kOSKextReturnNoResources;
5619 goto finish;
5620 }
5621
5622 /* This is a bit of a hack, because we shouldn't be handling
5623 * personalities within the load function.
5624 */
5625 if (!declaresExecutable()) {
5626 /* There is a special case where a non-executable kext can be loaded: the
5627 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5628 * load its metadata into the global data structures, if appropriate
5629 */
5630 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5631 boolean_t updated = updateExcludeList(infoDict.get());
5632 if (updated) {
5633 OSKextLog(this,
5634 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5635 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5636 }
5637 }
5638
5639 if (isDriverKit()) {
5640 if (loadTag == 0) {
5641 sLoadedDriverKitKexts->setObject(this);
5642 loadTag = sNextLoadTag++;
5643 }
5644 }
5645 result = kOSReturnSuccess;
5646 goto loaded;
5647 }
5648
5649 /* Are we in safe boot?
5650 */
5651 if (sSafeBoot && !isLoadableInSafeBoot()) {
5652 OSKextLog(this,
5653 kOSKextLogErrorLevel |
5654 kOSKextLogLoadFlag,
5655 "Can't load kext %s - not loadable during safe boot.",
5656 getIdentifierCString());
5657 result = kOSKextReturnBootLevel;
5658 goto finish;
5659 }
5660
5661 OSKextLog(this,
5662 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5663 "Loading kext %s.",
5664 getIdentifierCString());
5665
5666 #if !VM_MAPPED_KEXTS
5667 if (isPrelinked() == false) {
5668 OSKextLog(this,
5669 kOSKextLogErrorLevel |
5670 kOSKextLogLoadFlag,
5671 "Can't load kext %s - not in a kext collection.",
5672 getIdentifierCString());
5673 result = kOSKextReturnDisabled;
5674 goto finish;
5675 }
5676 #endif /* defined(__x86_64__) */
5677
5678 #if CONFIG_KXLD
5679 if (!sKxldContext) {
5680 kern_return_t kxldResult;
5681 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5682 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5683 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5684 if (kxldResult) {
5685 OSKextLog(this,
5686 kOSKextLogErrorLevel |
5687 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5688 "Can't load kext %s - failed to create link context.",
5689 getIdentifierCString());
5690 result = kOSKextReturnNoMemory;
5691 goto finish;
5692 }
5693 }
5694 #endif // CONFIG_KXLD
5695
5696 /* We only need to resolve dependencies once for the whole graph, but
5697 * resolveDependencies will just return if there's no work to do, so it's
5698 * safe to call it more than once.
5699 */
5700 if (!resolveDependencies()) {
5701 // xxx - check resolveDependencies() for log msg
5702 OSKextLog(this,
5703 kOSKextLogErrorLevel |
5704 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5705 "Can't load kext %s - failed to resolve library dependencies.",
5706 getIdentifierCString());
5707 result = kOSKextReturnDependencies;
5708 goto finish;
5709 }
5710
5711 /* If we are excluding just the kext being loaded now (and not its
5712 * dependencies), drop the exclusion level to none so dependencies
5713 * start and/or add their personalities.
5714 */
5715 if (dependenciesStartOpt == kOSKextExcludeKext) {
5716 dependenciesStartOpt = kOSKextExcludeNone;
5717 }
5718
5719 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5720 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5721 }
5722
5723 /* Load the dependencies, recursively.
5724 */
5725 count = getNumDependencies();
5726 for (i = 0; i < count; i++) {
5727 OSKext * dependency = OSDynamicCast(OSKext,
5728 dependencies->getObject(i));
5729 if (dependency == NULL) {
5730 OSKextLog(this,
5731 kOSKextLogErrorLevel |
5732 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5733 "Internal error loading kext %s; dependency disappeared.",
5734 getIdentifierCString());
5735 result = kOSKextReturnInternalError;
5736 goto finish;
5737 }
5738
5739 /* Dependencies must be started accorting to the opt,
5740 * but not given the personality names of the main kext.
5741 */
5742 result = dependency->load(dependenciesStartOpt,
5743 dependenciesStartMatchingOpt,
5744 /* personalityNames */ NULL);
5745 if (result != KERN_SUCCESS) {
5746 OSKextLog(this,
5747 kOSKextLogErrorLevel |
5748 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5749 "Dependency %s of kext %s failed to load.",
5750 dependency->getIdentifierCString(),
5751 getIdentifierCString());
5752
5753 OSKext::removeKext(dependency,
5754 /* terminateService/removePersonalities */ true);
5755 result = kOSKextReturnDependencyLoadError;
5756
5757 goto finish;
5758 }
5759 }
5760
5761 result = loadExecutable();
5762 if (result != KERN_SUCCESS) {
5763 goto finish;
5764 }
5765
5766 pendingPgoHead.next = &pendingPgoHead;
5767 pendingPgoHead.prev = &pendingPgoHead;
5768
5769 // The kernel PRNG is not initialized when the first kext is
5770 // loaded, so use early random
5771 uuid_generate_early_random(instance_uuid);
5772 account = IONew(OSKextAccount, 1);
5773 if (!account) {
5774 result = KERN_MEMORY_ERROR;
5775 goto finish;
5776 }
5777 bzero(account, sizeof(*account));
5778 account->loadTag = kmod_info->id;
5779 account->site.refcount = 0;
5780 account->site.flags = VM_TAG_KMOD;
5781 account->kext = this;
5782 if (gIOSurfaceIdentifier == bundleID) {
5783 vm_tag_alloc(&account->site);
5784 gIOSurfaceTag = account->site.tag;
5785 }
5786
5787 flags.loaded = true;
5788
5789 /* Add the kext to the list of loaded kexts and update the kmod_info
5790 * struct to point to that of the last loaded kext (which is the way
5791 * it's always been done, though I'd rather do them in order now).
5792 */
5793 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5794 sLoadedKexts->setObject(this);
5795
5796 /* Keep the kernel itself out of the kmod list.
5797 */
5798 if (lastLoadedKext->isKernel()) {
5799 lastLoadedKext = NULL;
5800 }
5801
5802 if (lastLoadedKext) {
5803 kmod_info->next = lastLoadedKext->kmod_info;
5804 }
5805
5806 notifyKextLoadObservers(this, kmod_info);
5807
5808 /* Make the global kmod list point at the just-loaded kext. Note that the
5809 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5810 * although we do report it in kextstat these days by using the newer
5811 * OSArray of loaded kexts, which does contain it.
5812 *
5813 * (The OSKext object representing the kernel doesn't even have a kmod_info
5814 * struct, though I suppose we could stick a pointer to it from the
5815 * static struct in OSRuntime.cpp.)
5816 */
5817 kmod = kmod_info;
5818
5819 /* Save the list of loaded kexts in case we panic.
5820 */
5821 OSKext::saveLoadedKextPanicList();
5822
5823 if (isExecutable()) {
5824 OSKext::updateLoadedKextSummaries();
5825 savePanicString(/* isLoading */ true);
5826
5827 #if CONFIG_DTRACE
5828 registerWithDTrace();
5829 #else
5830 jettisonLinkeditSegment();
5831 #endif /* CONFIG_DTRACE */
5832
5833 #if !VM_MAPPED_KEXTS
5834 /* If there is a page (or more) worth of padding after the end
5835 * of the last data section but before the end of the data segment
5836 * then free it in the same manner the LinkeditSegment is freed
5837 */
5838 jettisonDATASegmentPadding();
5839 #endif
5840 }
5841
5842 loaded:
5843 if (isExecutable() && !flags.started) {
5844 if (startOpt == kOSKextExcludeNone) {
5845 result = start();
5846 if (result != kOSReturnSuccess) {
5847 OSKextLog(this,
5848 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5849 "Kext %s start failed (result 0x%x).",
5850 getIdentifierCString(), result);
5851 result = kOSKextReturnStartStopError;
5852 }
5853 }
5854 }
5855
5856 /* If not excluding matching, send the personalities to the kernel.
5857 * This never affects the result of the load operation.
5858 * This is a bit of a hack, because we shouldn't be handling
5859 * personalities within the load function.
5860 */
5861 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5862 result = sendPersonalitiesToCatalog(true, personalityNames);
5863 }
5864
5865 finish:
5866
5867 if (result != kOSReturnSuccess) {
5868 OSKextLog(this,
5869 kOSKextLogErrorLevel |
5870 kOSKextLogLoadFlag,
5871 "Kext %s failed to load (0x%x).",
5872 getIdentifierCString(), (int)result);
5873 } else if (!alreadyLoaded) {
5874 OSKextLog(this,
5875 kOSKextLogProgressLevel |
5876 kOSKextLogLoadFlag,
5877 "Kext %s loaded.",
5878 getIdentifierCString());
5879
5880 queueKextNotification(kKextRequestPredicateLoadNotification,
5881 OSDynamicCast(OSString, bundleID.get()));
5882 }
5883 return result;
5884 }
5885
5886 #if CONFIG_KXLD
5887 /*********************************************************************
5888 *
5889 *********************************************************************/
5890 static char *
5891 strdup(const char * string)
5892 {
5893 char * result = NULL;
5894 size_t size;
5895
5896 if (!string) {
5897 goto finish;
5898 }
5899
5900 size = 1 + strlen(string);
5901 result = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, size,
5902 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5903 if (!result) {
5904 goto finish;
5905 }
5906
5907 memcpy(result, string, size);
5908
5909 finish:
5910 return result;
5911 }
5912 #endif // CONFIG_KXLD
5913
5914 /*********************************************************************
5915 *
5916 *********************************************************************/
5917
5918 kernel_section_t *
5919 OSKext::lookupSection(const char *segname, const char *secname)
5920 {
5921 kernel_section_t * found_section = NULL;
5922 kernel_mach_header_t * mh = NULL;
5923 kernel_segment_command_t * seg = NULL;
5924 kernel_section_t * sec = NULL;
5925
5926 if (!linkedExecutable) {
5927 return NULL;
5928 }
5929
5930 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5931
5932 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5933 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
5934 continue;
5935 }
5936
5937 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5938 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
5939 found_section = sec;
5940 goto out;
5941 }
5942 }
5943 }
5944
5945 out:
5946 return found_section;
5947 }
5948
5949 /*********************************************************************
5950 *
5951 *********************************************************************/
5952
5953 OSReturn
5954 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
5955 {
5956 OSReturn result = kOSKextReturnBadData;
5957 kernel_mach_header_t * mh = NULL;
5958 kernel_segment_command_t * seg = NULL;
5959 kernel_segment_command_t * linkeditSeg = NULL;
5960 kernel_section_t * sec = NULL;
5961 char * linkeditBase = NULL;
5962 bool haveLinkeditBase = false;
5963 char * relocBase = NULL;
5964 bool haveRelocBase = false;
5965 struct dysymtab_command * dysymtab = NULL;
5966 struct linkedit_data_command * segmentSplitInfo = NULL;
5967 struct symtab_command * symtab = NULL;
5968 kernel_nlist_t * sym = NULL;
5969 struct relocation_info * reloc = NULL;
5970 uint32_t i = 0;
5971 int reloc_size;
5972 vm_offset_t new_kextsize;
5973
5974 if (linkedExecutable == NULL || flags.builtin) {
5975 result = kOSReturnSuccess;
5976 goto finish;
5977 }
5978
5979 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5980 if (kernel_mach_header_is_in_fileset(mh)) {
5981 // kexts in filesets are slid as part of collection sliding
5982 result = kOSReturnSuccess;
5983 goto finish;
5984 }
5985
5986 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
5987
5988 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5989 if (!seg->vmaddr) {
5990 continue;
5991 }
5992
5993 seg->vmaddr = ml_static_slide(seg->vmaddr);
5994
5995 #if KASLR_KEXT_DEBUG
5996 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5997 seg->segname,
5998 (unsigned long)ml_static_unslide(seg->vmaddr),
5999 (unsigned long)seg->vmaddr);
6000 #endif
6001
6002 if (!haveRelocBase) {
6003 relocBase = (char *) seg->vmaddr;
6004 haveRelocBase = true;
6005 }
6006 if (!strcmp(seg->segname, "__LINKEDIT")) {
6007 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
6008 haveLinkeditBase = true;
6009 linkeditSeg = seg;
6010 }
6011 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
6012 sec->addr = ml_static_slide(sec->addr);
6013
6014 #if KASLR_KEXT_DEBUG
6015 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
6016 sec->sectname,
6017 (unsigned long)ml_static_unslide(sec->addr),
6018 (unsigned long)sec->addr);
6019 #endif
6020 }
6021 }
6022
6023 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
6024
6025 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
6026
6027 if (symtab != NULL && doCoalescedSlides == false) {
6028 /* Some pseudo-kexts have symbol tables without segments.
6029 * Ignore them. */
6030 if (symtab->nsyms > 0 && haveLinkeditBase) {
6031 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6032 for (i = 0; i < symtab->nsyms; i++) {
6033 if (sym[i].n_type & N_STAB) {
6034 continue;
6035 }
6036 sym[i].n_value = ml_static_slide(sym[i].n_value);
6037
6038 #if KASLR_KEXT_DEBUG
6039 #define MAX_SYMS_TO_LOG 5
6040 if (i < MAX_SYMS_TO_LOG) {
6041 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6042 (unsigned long)ml_static_unslide(sym[i].n_value),
6043 (unsigned long)sym[i].n_value);
6044 }
6045 #endif
6046 }
6047 }
6048 }
6049
6050 if (dysymtab != NULL && doCoalescedSlides == false) {
6051 if (dysymtab->nextrel > 0) {
6052 OSKextLog(this,
6053 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6054 kOSKextLogLinkFlag,
6055 "Sliding kext %s: External relocations found.",
6056 getIdentifierCString());
6057 goto finish;
6058 }
6059
6060 if (dysymtab->nlocrel > 0) {
6061 if (!haveLinkeditBase) {
6062 OSKextLog(this,
6063 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6064 kOSKextLogLinkFlag,
6065 "Sliding kext %s: No linkedit segment.",
6066 getIdentifierCString());
6067 goto finish;
6068 }
6069
6070 if (!haveRelocBase) {
6071 OSKextLog(this,
6072 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6073 kOSKextLogLinkFlag,
6074 #if __x86_64__
6075 "Sliding kext %s: No writable segments.",
6076 #else
6077 "Sliding kext %s: No segments.",
6078 #endif
6079 getIdentifierCString());
6080 goto finish;
6081 }
6082
6083 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6084 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6085
6086 for (i = 0; i < dysymtab->nlocrel; i++) {
6087 if (reloc[i].r_extern != 0
6088 || reloc[i].r_type != 0
6089 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6090 ) {
6091 OSKextLog(this,
6092 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6093 kOSKextLogLinkFlag,
6094 "Sliding kext %s: Unexpected relocation found.",
6095 getIdentifierCString());
6096 goto finish;
6097 }
6098 if (reloc[i].r_pcrel != 0) {
6099 continue;
6100 }
6101 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6102 *relocAddr = ml_static_slide(*relocAddr);
6103
6104 #if KASLR_KEXT_DEBUG
6105 #define MAX_DYSYMS_TO_LOG 5
6106 if (i < MAX_DYSYMS_TO_LOG) {
6107 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6108 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6109 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6110 }
6111 #endif
6112 }
6113
6114 /* We should free these relocations, not just delete the reference to them.
6115 * <rdar://problem/10535549> Free relocations from PIE kexts.
6116 *
6117 * For now, we do not free LINKEDIT for kexts with split segments.
6118 */
6119 new_kextsize = round_page(kmod_info->size - reloc_size);
6120 if (new_kextsize > UINT_MAX) {
6121 OSKextLog(this,
6122 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6123 kOSKextLogLinkFlag,
6124 "Kext %s: new kext size is too large.",
6125 getIdentifierCString());
6126 goto finish;
6127 }
6128 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6129 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6130 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6131 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6132 size_t bytes_remaining = endofkext - endofrelocInfo;
6133 OSSharedPtr<OSData> new_osdata;
6134
6135 /* fix up symbol offsets if they are after the dsymtab local relocs */
6136 if (symtab) {
6137 if (dysymtab->locreloff < symtab->symoff) {
6138 symtab->symoff -= reloc_size;
6139 }
6140 if (dysymtab->locreloff < symtab->stroff) {
6141 symtab->stroff -= reloc_size;
6142 }
6143 }
6144 if (dysymtab->locreloff < dysymtab->extreloff) {
6145 dysymtab->extreloff -= reloc_size;
6146 }
6147
6148 /* move data behind reloc info down to new offset */
6149 if (endofrelocInfo < endofkext) {
6150 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6151 }
6152
6153 /* Create a new OSData for the smaller kext object and reflect
6154 * new linkedit segment size.
6155 */
6156 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6157 linkeditSeg->filesize = linkeditSeg->vmsize;
6158
6159 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6160 if (new_osdata) {
6161 /* Fix up kmod info and linkedExecutable.
6162 */
6163 kmod_info->size = new_kextsize;
6164 #if VM_MAPPED_KEXTS
6165 new_osdata->setDeallocFunction(osdata_kext_free);
6166 #else
6167 new_osdata->setDeallocFunction(osdata_phys_free);
6168 #endif
6169 linkedExecutable->setDeallocFunction(NULL);
6170 linkedExecutable = os::move(new_osdata);
6171
6172 #if VM_MAPPED_KEXTS
6173 kext_free(new_endofkext, (endofkext - new_endofkext));
6174 #else
6175 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6176 #endif
6177 }
6178 }
6179 dysymtab->nlocrel = 0;
6180 dysymtab->locreloff = 0;
6181 }
6182 }
6183
6184 result = kOSReturnSuccess;
6185 finish:
6186 return result;
6187 }
6188
6189 /*********************************************************************
6190 * called only by load()
6191 *********************************************************************/
6192 OSReturn
6193 OSKext::loadExecutable()
6194 {
6195 OSReturn result = kOSReturnError;
6196 OSSharedPtr<OSArray> linkDependencies;
6197 uint32_t num_kmod_refs = 0;
6198 OSData * theExecutable = NULL; // do not release
6199 OSString * versString = NULL; // do not release
6200 const char * versCString = NULL; // do not free
6201 const char * string = NULL; // do not free
6202
6203 #if CONFIG_KXLD
6204 unsigned int i;
6205 uint32_t numDirectDependencies = 0;
6206 kern_return_t kxldResult;
6207 KXLDDependency * kxlddeps = NULL; // must kfree
6208 uint32_t num_kxlddeps = 0;
6209 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6210 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6211 #endif // CONFIG_KXLD
6212
6213 /* We need the version string for a variety of bits below.
6214 */
6215 versString = OSDynamicCast(OSString,
6216 getPropertyForHostArch(kCFBundleVersionKey));
6217 if (!versString) {
6218 goto finish;
6219 }
6220 versCString = versString->getCStringNoCopy();
6221
6222 if (isKernelComponent()) {
6223 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6224 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6225 OSKextLog(this,
6226 kOSKextLogErrorLevel |
6227 kOSKextLogLoadFlag,
6228 "Kernel component %s has incorrect version %s; "
6229 "expected %s.",
6230 getIdentifierCString(),
6231 versCString, KERNEL6_VERSION);
6232 result = kOSKextReturnInternalError;
6233 goto finish;
6234 } else if (strcmp(versCString, osrelease)) {
6235 OSKextLog(this,
6236 kOSKextLogErrorLevel |
6237 kOSKextLogLoadFlag,
6238 "Kernel component %s has incorrect version %s; "
6239 "expected %s.",
6240 getIdentifierCString(),
6241 versCString, osrelease);
6242 result = kOSKextReturnInternalError;
6243 goto finish;
6244 }
6245 }
6246 }
6247
6248 #if defined(__x86_64__) || defined(__i386__)
6249 if (flags.resetSegmentsFromVnode) {
6250 /* Fixup the chains and slide the mach headers */
6251 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6252
6253 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6254 result = kOSKextReturnValidation;
6255 goto finish;
6256 }
6257 }
6258 #endif //(__x86_64__) || defined(__i386__)
6259
6260 if (isPrelinked()) {
6261 goto register_kmod;
6262 }
6263
6264 /* <rdar://problem/21444003> all callers must be entitled */
6265 if (FALSE == IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement)) {
6266 OSKextLog(this,
6267 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6268 "Not entitled to link kext '%s'",
6269 getIdentifierCString());
6270 result = kOSKextReturnNotPrivileged;
6271 goto finish;
6272 }
6273
6274 theExecutable = getExecutable();
6275 if (!theExecutable) {
6276 if (declaresExecutable()) {
6277 OSKextLog(this,
6278 kOSKextLogErrorLevel |
6279 kOSKextLogLoadFlag,
6280 "Can't load kext %s - executable is missing.",
6281 getIdentifierCString());
6282 result = kOSKextReturnValidation;
6283 goto finish;
6284 }
6285 goto register_kmod;
6286 }
6287
6288 if (isInterface()) {
6289 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6290 if (executableCopy) {
6291 setLinkedExecutable(executableCopy.get());
6292 }
6293 goto register_kmod;
6294 }
6295
6296 #if CONFIG_KXLD
6297 numDirectDependencies = getNumDependencies();
6298
6299 if (flags.hasBleedthrough) {
6300 linkDependencies = dependencies;
6301 } else {
6302 linkDependencies = OSArray::withArray(dependencies.get());
6303 if (!linkDependencies) {
6304 OSKextLog(this,
6305 kOSKextLogErrorLevel |
6306 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6307 "Can't allocate link dependencies to load kext %s.",
6308 getIdentifierCString());
6309 goto finish;
6310 }
6311
6312 for (i = 0; i < numDirectDependencies; ++i) {
6313 OSKext * dependencyKext = OSDynamicCast(OSKext,
6314 dependencies->getObject(i));
6315 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
6316 }
6317 }
6318
6319 num_kxlddeps = linkDependencies->getCount();
6320 if (!num_kxlddeps) {
6321 OSKextLog(this,
6322 kOSKextLogErrorLevel |
6323 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6324 "Can't load kext %s - it has no library dependencies.",
6325 getIdentifierCString());
6326 goto finish;
6327 }
6328
6329 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
6330 if (!kxlddeps) {
6331 OSKextLog(this,
6332 kOSKextLogErrorLevel |
6333 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6334 "Can't allocate link context to load kext %s.",
6335 getIdentifierCString());
6336 goto finish;
6337 }
6338 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6339
6340 for (i = 0; i < num_kxlddeps; ++i) {
6341 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6342
6343 if (dependency->isInterface()) {
6344 OSKext *interfaceTargetKext = NULL; //do not release
6345 OSData * interfaceTarget = NULL; //do not release
6346
6347 if (dependency->isKernelComponent()) {
6348 interfaceTargetKext = sKernelKext;
6349 interfaceTarget = sKernelKext->linkedExecutable.get();
6350 } else {
6351 interfaceTargetKext = OSDynamicCast(OSKext,
6352 dependency->dependencies->getObject(0));
6353
6354 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
6355 }
6356
6357 if (!interfaceTarget) {
6358 // panic?
6359 goto finish;
6360 }
6361
6362 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6363 * it will be useful to have them in the debugger.
6364 * strdup() failing isn't critical right here so we don't check that.
6365 */
6366 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6367 kxlddeps[i].kext_size = interfaceTarget->getLength();
6368 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6369
6370 if (dependency->linkedExecutable != NULL) {
6371 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6372 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6373 } else {
6374 kxlddeps[i].interface = (u_char *) NULL;
6375 kxlddeps[i].interface_size = 0;
6376 }
6377 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6378 } else {
6379 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6380 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6381 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6382 }
6383
6384 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6385 }
6386
6387 kxldHeaderPtr = &kxld_header;
6388
6389 #if DEBUG
6390 OSKextLog(this,
6391 kOSKextLogExplicitLevel |
6392 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6393 "Kext %s - calling kxld_link_file:\n"
6394 " kxld_context: %p\n"
6395 " executable: %p executable_length: %d\n"
6396 " user_data: %p\n"
6397 " kxld_dependencies: %p num_dependencies: %d\n"
6398 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6399 getIdentifierCString(), sKxldContext,
6400 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6401 this, kxlddeps, num_kxlddeps,
6402 kxldHeaderPtr, &kmod_info);
6403 #endif
6404
6405 /* After this call, the linkedExecutable instance variable
6406 * should exist.
6407 */
6408 kxldResult = kxld_link_file(sKxldContext,
6409 (u_char *)theExecutable->getBytesNoCopy(),
6410 theExecutable->getLength(),
6411 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6412 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6413
6414 if (kxldResult != KERN_SUCCESS) {
6415 // xxx - add kxldResult here?
6416 OSKextLog(this,
6417 kOSKextLogErrorLevel |
6418 kOSKextLogLoadFlag,
6419 "Can't load kext %s - link failed.",
6420 getIdentifierCString());
6421 result = kOSKextReturnLinkError;
6422 goto finish;
6423 }
6424
6425 /* We've written data & instructions into kernel memory, so flush the data
6426 * cache and invalidate the instruction cache.
6427 * I/D caches are coherent on x86
6428 */
6429 #if !defined(__i386__) && !defined(__x86_64__)
6430 flush_dcache(kmod_info->address, kmod_info->size, false);
6431 invalidate_icache(kmod_info->address, kmod_info->size, false);
6432 #endif
6433
6434 #else // !CONFIG_KXLD
6435 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6436 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6437 result = kOSKextReturnLinkError;
6438 goto finish;
6439 #endif // CONFIG_KXLD
6440
6441 register_kmod:
6442
6443 if (isInterface()) {
6444 /* Whip up a fake kmod_info entry for the interface kext.
6445 */
6446 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
6447 if (!kmod_info) {
6448 result = KERN_MEMORY_ERROR;
6449 goto finish;
6450 }
6451
6452 /* A pseudokext has almost nothing in its kmod_info struct.
6453 */
6454 bzero(kmod_info, sizeof(kmod_info_t));
6455
6456 kmod_info->info_version = KMOD_INFO_VERSION;
6457
6458 /* An interface kext doesn't have a linkedExecutable, so save a
6459 * copy of the UUID out of the original executable via copyUUID()
6460 * while we still have the original executable.
6461 */
6462 interfaceUUID = copyUUID();
6463 }
6464
6465 kmod_info->id = loadTag = sNextLoadTag++;
6466 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
6467
6468 /* Stamp the bundle ID and version from the OSKext over anything
6469 * resident inside the kmod_info.
6470 */
6471 string = getIdentifierCString();
6472 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6473
6474 string = versCString;
6475 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6476
6477 /* Add the dependencies' kmod_info structs as kmod_references.
6478 */
6479 num_kmod_refs = getNumDependencies();
6480 if (num_kmod_refs) {
6481 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
6482 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
6483 if (!kmod_info->reference_list) {
6484 result = KERN_MEMORY_ERROR;
6485 goto finish;
6486 }
6487 bzero(kmod_info->reference_list,
6488 num_kmod_refs * sizeof(kmod_reference_t));
6489 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6490 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6491 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6492 ref->info = refKext->kmod_info;
6493 ref->info->reference_count++;
6494
6495 if (refIndex + 1 < num_kmod_refs) {
6496 ref->next = kmod_info->reference_list + refIndex + 1;
6497 }
6498 }
6499 }
6500
6501 if (kmod_info->hdr_size > UINT32_MAX) {
6502 OSKextLog(this,
6503 kOSKextLogErrorLevel |
6504 kOSKextLogLoadFlag,
6505 #if __LP64__
6506 "Kext %s header size is too large (%lu > UINT32_MAX).",
6507 #else
6508 "Kext %s header size is too large (%u > UINT32_MAX).",
6509 #endif
6510 kmod_info->name,
6511 kmod_info->hdr_size);
6512 result = KERN_FAILURE;
6513 goto finish;
6514 }
6515
6516 if (kmod_info->size > UINT32_MAX) {
6517 OSKextLog(this,
6518 kOSKextLogErrorLevel |
6519 kOSKextLogLoadFlag,
6520 #if __LP64__
6521 "Kext %s size is too large (%lu > UINT32_MAX).",
6522 #else
6523 "Kext %s size is too large (%u > UINT32_MAX).",
6524 #endif
6525 kmod_info->name,
6526 kmod_info->size);
6527 result = KERN_FAILURE;
6528 goto finish;
6529 }
6530
6531 if (!isInterface() && linkedExecutable) {
6532 OSKextLog(this,
6533 kOSKextLogProgressLevel |
6534 kOSKextLogLoadFlag,
6535 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6536 kmod_info->name,
6537 (unsigned)kmod_info->size / PAGE_SIZE,
6538 (unsigned long)ml_static_unslide(kmod_info->address),
6539 (unsigned)kmod_info->id);
6540 }
6541
6542 /* VM protections and wiring for the Aux KC are done at collection loading time */
6543 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6544 /* if prelinked and primary KC, VM protections are already set */
6545 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6546 if (result != KERN_SUCCESS) {
6547 goto finish;
6548 }
6549 }
6550
6551 #if KASAN
6552 if (linkedExecutable) {
6553 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6554 linkedExecutable->getLength(), getIdentifierCString());
6555 }
6556 #else
6557 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6558 OSKextLog(this,
6559 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6560 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6561 getIdentifierCString()
6562 );
6563 result = KERN_FAILURE;
6564 goto finish;
6565 }
6566 #endif
6567
6568 result = kOSReturnSuccess;
6569
6570 finish:
6571
6572 #if CONFIG_KXLD
6573 /* Clear up locally allocated dependency info.
6574 */
6575 for (i = 0; i < num_kxlddeps; ++i) {
6576 size_t size;
6577
6578 if (kxlddeps[i].kext_name) {
6579 size = 1 + strlen(kxlddeps[i].kext_name);
6580 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].kext_name, size);
6581 }
6582 if (kxlddeps[i].interface_name) {
6583 size = 1 + strlen(kxlddeps[i].interface_name);
6584 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].interface_name, size);
6585 }
6586 }
6587 if (kxlddeps) {
6588 kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
6589 }
6590 #endif // CONFIG_KXLD
6591
6592 /* We no longer need the unrelocated executable (which the linker
6593 * has altered anyhow).
6594 */
6595 setExecutable(NULL);
6596
6597 if (result != kOSReturnSuccess) {
6598 OSKextLog(this,
6599 kOSKextLogErrorLevel |
6600 kOSKextLogLoadFlag,
6601 "Failed to load executable for kext %s.",
6602 getIdentifierCString());
6603
6604 if (kmod_info && kmod_info->reference_list) {
6605 kfree(kmod_info->reference_list,
6606 num_kmod_refs * sizeof(kmod_reference_t));
6607 }
6608 if (isInterface()) {
6609 kfree(kmod_info, sizeof(kmod_info_t));
6610 kmod_info = NULL;
6611 }
6612 if (kc_type == KCKindUnknown) {
6613 kmod_info = NULL;
6614 if (linkedExecutable) {
6615 linkedExecutable.reset();
6616 }
6617 }
6618 }
6619
6620 return result;
6621 }
6622
6623 #if VM_MAPPED_KEXTS
6624 /* static */
6625 void
6626 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6627 {
6628 kernel_segment_command_t *linkeditseg = NULL;
6629
6630 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6631 assert(linkeditseg != NULL);
6632
6633 /* BootKC on x86_64 is not vm mapped */
6634 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6635
6636 OSKextLog(/* kext */ NULL,
6637 kOSKextLogProgressLevel |
6638 kOSKextLogGeneralFlag,
6639 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6640 linkeditseg->vmaddr, linkeditseg->vmsize);
6641 }
6642 #endif /* VM_MAPPED_KEXTS */
6643
6644 /*********************************************************************
6645 * The linkedit segment is used by the kext linker for dependency
6646 * resolution, and by dtrace for probe initialization. We can free it
6647 * for non-library kexts, since no kexts depend on non-library kexts
6648 * by definition, once dtrace has been initialized.
6649 *********************************************************************/
6650 void
6651 OSKext::jettisonLinkeditSegment(void)
6652 {
6653 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6654 kernel_segment_command_t * linkedit = NULL;
6655 vm_offset_t start;
6656 vm_size_t linkeditsize, kextsize;
6657 OSSharedPtr<OSData> data;
6658
6659 if (isInFileset()) {
6660 return;
6661 }
6662
6663 #if NO_KEXTD
6664 /* We can free symbol tables for all embedded kexts because we don't
6665 * support runtime kext linking.
6666 */
6667 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6668 #else
6669 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6670 #endif
6671 goto finish;
6672 }
6673
6674 /* Find the linkedit segment. If it's not the last segment, then freeing
6675 * it will fragment the kext into multiple VM regions, which OSKext is not
6676 * designed to handle, so we'll have to skip it.
6677 */
6678 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6679 if (!linkedit) {
6680 goto finish;
6681 }
6682
6683 if (round_page(kmod_info->address + kmod_info->size) !=
6684 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6685 goto finish;
6686 }
6687
6688 /* Create a new OSData for the smaller kext object.
6689 */
6690 linkeditsize = round_page(linkedit->vmsize);
6691 kextsize = kmod_info->size - linkeditsize;
6692 start = linkedit->vmaddr;
6693
6694 if (kextsize > UINT_MAX) {
6695 goto finish;
6696 }
6697 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6698 if (!data) {
6699 goto finish;
6700 }
6701
6702 /* Fix the kmod info and linkedExecutable.
6703 */
6704 kmod_info->size = kextsize;
6705
6706 #if VM_MAPPED_KEXTS
6707 data->setDeallocFunction(osdata_kext_free);
6708 #else
6709 data->setDeallocFunction(osdata_phys_free);
6710 #endif
6711 linkedExecutable->setDeallocFunction(NULL);
6712 linkedExecutable = os::move(data);
6713 flags.jettisonLinkeditSeg = 1;
6714
6715 /* Free the linkedit segment.
6716 */
6717 #if VM_MAPPED_KEXTS
6718 kext_free(start, linkeditsize);
6719 #else
6720 ml_static_mfree(start, linkeditsize);
6721 #endif
6722
6723 finish:
6724 return;
6725 }
6726
6727 /*********************************************************************
6728 * If there are whole pages that are unused betweem the last section
6729 * of the DATA segment and the end of the DATA segment then we can free
6730 * them
6731 *********************************************************************/
6732 void
6733 OSKext::jettisonDATASegmentPadding(void)
6734 {
6735 kernel_mach_header_t * mh;
6736 kernel_segment_command_t * dataSeg;
6737 kernel_section_t * sec, * lastSec;
6738 vm_offset_t dataSegEnd, lastSecEnd;
6739 vm_size_t padSize;
6740
6741 if (flags.builtin) {
6742 return;
6743 }
6744 mh = (kernel_mach_header_t *)kmod_info->address;
6745
6746 if (isInFileset()) {
6747 return;
6748 }
6749
6750 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6751 if (dataSeg == NULL) {
6752 return;
6753 }
6754
6755 lastSec = NULL;
6756 sec = firstsect(dataSeg);
6757 while (sec != NULL) {
6758 lastSec = sec;
6759 sec = nextsect(dataSeg, sec);
6760 }
6761
6762 if (lastSec == NULL) {
6763 return;
6764 }
6765
6766 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6767 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6768 return;
6769 }
6770
6771 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6772 lastSecEnd = round_page(lastSec->addr + lastSec->size);
6773
6774 if (dataSegEnd <= lastSecEnd) {
6775 return;
6776 }
6777
6778 padSize = dataSegEnd - lastSecEnd;
6779
6780 if (padSize >= PAGE_SIZE) {
6781 #if VM_MAPPED_KEXTS
6782 kext_free(lastSecEnd, padSize);
6783 #else
6784 ml_static_mfree(lastSecEnd, padSize);
6785 #endif
6786 }
6787 }
6788
6789 /*********************************************************************
6790 *********************************************************************/
6791 void
6792 OSKext::setLinkedExecutable(OSData * anExecutable)
6793 {
6794 if (linkedExecutable) {
6795 panic("Attempt to set linked executable on kext "
6796 "that already has one (%s).\n",
6797 getIdentifierCString());
6798 }
6799 linkedExecutable.reset(anExecutable, OSRetain);
6800 return;
6801 }
6802
6803 #if CONFIG_DTRACE
6804 /*********************************************************************
6805 * Go through all loaded kexts and tell them to register with dtrace.
6806 * The instance method only registers if necessary.
6807 *********************************************************************/
6808 /* static */
6809 void
6810 OSKext::registerKextsWithDTrace(void)
6811 {
6812 uint32_t count = sLoadedKexts->getCount();
6813 uint32_t i;
6814
6815 IORecursiveLockLock(sKextLock);
6816
6817 for (i = 0; i < count; i++) {
6818 OSKext * thisKext = NULL; // do not release
6819
6820 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6821 if (!thisKext || !thisKext->isExecutable()) {
6822 continue;
6823 }
6824
6825 thisKext->registerWithDTrace();
6826 }
6827
6828 IORecursiveLockUnlock(sKextLock);
6829
6830 return;
6831 }
6832
6833 extern "C" {
6834 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6835 extern int (*dtrace_modunload)(struct kmod_info *);
6836 };
6837
6838 /*********************************************************************
6839 *********************************************************************/
6840 void
6841 OSKext::registerWithDTrace(void)
6842 {
6843 /* Register kext with dtrace. A dtrace_modload failure should not
6844 * prevent a kext from loading, so we ignore the return code.
6845 */
6846 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6847 uint32_t modflag = 0;
6848 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
6849
6850 #if VM_MAPPED_KEXTS
6851 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6852 if (forceInit == kOSBooleanTrue) {
6853 /* Make sure the kext is not from the Boot KC */
6854 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6855 } else {
6856 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6857 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6858 }
6859 }
6860 #endif /* VM_MAPPED_KEXTS */
6861 if (forceInit == kOSBooleanTrue) {
6862 modflag |= KMOD_DTRACE_FORCE_INIT;
6863 }
6864 if (flags.builtin) {
6865 modflag |= KMOD_DTRACE_STATIC_KEXT;
6866 }
6867
6868 (void)(*dtrace_modload)(kmod_info, modflag);
6869 flags.dtraceInitialized = true;
6870 jettisonLinkeditSegment();
6871 }
6872 return;
6873 }
6874 /*********************************************************************
6875 *********************************************************************/
6876 void
6877 OSKext::unregisterWithDTrace(void)
6878 {
6879 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6880 * prevent a kext from loading, so we ignore the return code.
6881 */
6882 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6883 (void)(*dtrace_modunload)(kmod_info);
6884 flags.dtraceInitialized = false;
6885 }
6886 return;
6887 }
6888 #endif /* CONFIG_DTRACE */
6889
6890
6891 /*********************************************************************
6892 * called only by loadExecutable()
6893 *********************************************************************/
6894 #if !VM_MAPPED_KEXTS
6895 #if defined(__arm__) || defined(__arm64__)
6896 static inline kern_return_t
6897 OSKext_protect(
6898 kernel_mach_header_t *kext_mh,
6899 vm_map_t map,
6900 vm_map_offset_t start,
6901 vm_map_offset_t end,
6902 vm_prot_t new_prot,
6903 boolean_t set_max,
6904 kc_kind_t kc_type)
6905 {
6906 #pragma unused(kext_mh,map,kc_type)
6907 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
6908 assert(start <= end);
6909 if (start >= end) {
6910 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6911 } else if (set_max) {
6912 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
6913 } else {
6914 return ml_static_protect(start, end - start, new_prot);
6915 }
6916 }
6917
6918 static inline kern_return_t
6919 OSKext_wire(
6920 kernel_mach_header_t *kext_mh,
6921 vm_map_t map,
6922 vm_map_offset_t start,
6923 vm_map_offset_t end,
6924 vm_prot_t access_type,
6925 boolean_t user_wire,
6926 kc_kind_t kc_type)
6927 {
6928 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6929 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
6930 }
6931 #else
6932 #error Unrecognized architecture
6933 #endif
6934 #else
6935 static inline kern_return_t
6936 OSKext_protect(
6937 kernel_mach_header_t *kext_mh,
6938 vm_map_t map,
6939 vm_map_offset_t start,
6940 vm_map_offset_t end,
6941 vm_prot_t new_prot,
6942 boolean_t set_max,
6943 kc_kind_t kc_type)
6944 {
6945 if (start == end) { // 10538581
6946 return KERN_SUCCESS;
6947 }
6948 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6949 /*
6950 * XXX: This will probably need to be different for AuxKC and
6951 * pageableKC!
6952 */
6953 return ml_static_protect(start, end - start, new_prot);
6954 }
6955 return vm_map_protect(map, start, end, new_prot, set_max);
6956 }
6957
6958 static inline kern_return_t
6959 OSKext_wire(
6960 kernel_mach_header_t *kext_mh,
6961 vm_map_t map,
6962 vm_map_offset_t start,
6963 vm_map_offset_t end,
6964 vm_prot_t access_type,
6965 boolean_t user_wire,
6966 kc_kind_t kc_type)
6967 {
6968 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6969 /* TODO: we may need to hook this for the pageableKC */
6970 return KERN_SUCCESS;
6971 }
6972 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
6973 }
6974 #endif
6975
6976 OSReturn
6977 OSKext::setVMAttributes(bool protect, bool wire)
6978 {
6979 vm_map_t kext_map = NULL;
6980 kernel_segment_command_t * seg = NULL;
6981 vm_map_offset_t start_protect = 0;
6982 vm_map_offset_t start_wire = 0;
6983 vm_map_offset_t end_protect = 0;
6984 vm_map_offset_t end_wire = 0;
6985 OSReturn result = kOSReturnError;
6986
6987 if (isInterface() || !declaresExecutable() || flags.builtin) {
6988 result = kOSReturnSuccess;
6989 goto finish;
6990 }
6991
6992 /* Get the kext's vm map */
6993 kext_map = kext_get_vm_map(kmod_info);
6994 if (!kext_map) {
6995 result = KERN_MEMORY_ERROR;
6996 goto finish;
6997 }
6998
6999 #if !VM_MAPPED_KEXTS
7000 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
7001 /* This is a split kext in a prelinked kernelcache; we'll let the
7002 * platform code take care of protecting it. It is already wired.
7003 */
7004 /* TODO: Should this still allow protections for the first segment
7005 * to go through, in the event that we have a mix of split and
7006 * unsplit kexts?
7007 */
7008 result = KERN_SUCCESS;
7009 goto finish;
7010 }
7011
7012 if (isInFileset() && kc_type != KCKindPageable) {
7013 // kexts in filesets have protections setup as part of collection loading
7014 result = KERN_SUCCESS;
7015 goto finish;
7016 }
7017 #endif
7018
7019 /* Protect the headers as read-only; they do not need to be wired */
7020 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7021 kext_map, kmod_info->address,
7022 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
7023 : KERN_SUCCESS;
7024 if (result != KERN_SUCCESS) {
7025 goto finish;
7026 }
7027
7028 /* Set the VM protections and wire down each of the segments */
7029 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7030 while (seg) {
7031 #if __arm__
7032 /* We build all ARM kexts, so we can ensure they are aligned */
7033 assert((seg->vmaddr & PAGE_MASK) == 0);
7034 assert((seg->vmsize & PAGE_MASK) == 0);
7035 #endif
7036
7037 /*
7038 * For the non page aligned segments, the range calculation for protection
7039 * and wiring differ as follows:
7040 *
7041 * Protection: The non page aligned data at the start or at the end of the
7042 * segment is excluded from the protection. This exclusion is needed to make
7043 * sure OSKext_protect is not called twice on same page, if the page is shared
7044 * between two segments.
7045 *
7046 * Wiring: The non page aligned data at the start or at the end of the
7047 * segment is included in the wiring range, this inclusion is needed to make sure
7048 * all the data of the segment is wired.
7049 */
7050 start_protect = round_page(seg->vmaddr);
7051 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7052
7053 start_wire = trunc_page(seg->vmaddr);
7054 end_wire = round_page(seg->vmaddr + seg->vmsize);
7055
7056 /*
7057 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7058 * across kexts and data from kexts is not page aligned
7059 */
7060 if (protect && (end_protect > start_protect) &&
7061 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7062 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7063 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7064 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7065 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7066 if (result != KERN_SUCCESS) {
7067 OSKextLog(this,
7068 kOSKextLogErrorLevel |
7069 kOSKextLogLoadFlag,
7070 "Kext %s failed to set maximum VM protections "
7071 "for segment %s - 0x%x.",
7072 getIdentifierCString(), seg->segname, (int)result);
7073 goto finish;
7074 }
7075
7076 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7077 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7078 if (result != KERN_SUCCESS) {
7079 OSKextLog(this,
7080 kOSKextLogErrorLevel |
7081 kOSKextLogLoadFlag,
7082 "Kext %s failed to set initial VM protections "
7083 "for segment %s - 0x%x.",
7084 getIdentifierCString(), seg->segname, (int)result);
7085 goto finish;
7086 }
7087 }
7088
7089 if (segmentShouldBeWired(seg) && wire) {
7090 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7091 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7092 if (result != KERN_SUCCESS) {
7093 goto finish;
7094 }
7095 }
7096
7097 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7098 }
7099
7100 finish:
7101 return result;
7102 }
7103
7104 /*********************************************************************
7105 *********************************************************************/
7106 boolean_t
7107 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7108 {
7109 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7110 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7111 }
7112
7113 /*********************************************************************
7114 *********************************************************************/
7115 OSReturn
7116 OSKext::validateKextMapping(bool startFlag)
7117 {
7118 OSReturn result = kOSReturnError;
7119 const char * whichOp = startFlag ? "start" : "stop";
7120 kern_return_t kern_result = 0;
7121 vm_map_t kext_map = NULL;
7122 kernel_segment_command_t * seg = NULL;
7123 mach_vm_address_t address = 0;
7124 mach_vm_size_t size = 0;
7125 uint32_t depth = 0;
7126 uint64_t kext_segbase = 0;
7127 uint64_t kext_segsize = 0;
7128 mach_msg_type_number_t count;
7129 vm_region_submap_short_info_data_64_t info;
7130 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7131
7132 if (flags.builtin) {
7133 return kOSReturnSuccess;
7134 }
7135
7136 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7137 bzero(&info, sizeof(info));
7138
7139 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7140 // xxx - sufficient?
7141
7142 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7143 */
7144 if (!kmod_info) {
7145 OSKextLog(this,
7146 kOSKextLogErrorLevel |
7147 kOSKextLogLoadFlag,
7148 "Kext %s - NULL kmod_info pointer.",
7149 getIdentifierCString());
7150 result = kOSKextReturnBadData;
7151 goto finish;
7152 }
7153
7154 if (startFlag) {
7155 address = (mach_vm_address_t)kmod_info->start;
7156 } else {
7157 address = (mach_vm_address_t)kmod_info->stop;
7158 }
7159
7160 if (!address) {
7161 OSKextLog(this,
7162 kOSKextLogErrorLevel |
7163 kOSKextLogLoadFlag,
7164 "Kext %s - NULL module %s pointer.",
7165 getIdentifierCString(), whichOp);
7166 result = kOSKextReturnBadData;
7167 goto finish;
7168 }
7169
7170 kext_map = kext_get_vm_map(kmod_info);
7171 depth = (kernel_map == kext_map) ? 1 : 2;
7172 if (isInFileset()) {
7173 #if defined(HAS_APPLE_PAC)
7174 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7175 #endif /* defined(HAS_APPLE_PAC) */
7176 }
7177
7178 /* Verify that the start/stop function lies within the kext's address range.
7179 */
7180 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7181 isInFileset()) {
7182 /* This will likely be how we deal with split kexts; walk the segments to
7183 * check that the function lies inside one of the segments of this kext.
7184 */
7185 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7186 seg != NULL;
7187 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7188 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7189 kext_segbase = seg->vmaddr;
7190 kext_segsize = seg->vmsize;
7191 break;
7192 }
7193 }
7194
7195 if (!seg) {
7196 OSKextLog(this,
7197 kOSKextLogErrorLevel |
7198 kOSKextLogLoadFlag,
7199 "Kext %s module %s pointer is outside of kext range "
7200 "(%s %p - kext starts at %p).",
7201 getIdentifierCString(),
7202 whichOp,
7203 whichOp,
7204 (void *)(((uintptr_t)address) - kext_slide),
7205 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7206 result = kOSKextReturnBadData;
7207 goto finish;
7208 }
7209
7210 seg = NULL;
7211 } else {
7212 if (address < kmod_info->address + kmod_info->hdr_size ||
7213 kmod_info->address + kmod_info->size <= address) {
7214 OSKextLog(this,
7215 kOSKextLogErrorLevel |
7216 kOSKextLogLoadFlag,
7217 "Kext %s module %s pointer is outside of kext range "
7218 "(%s %p - kext at %p-%p).",
7219 getIdentifierCString(),
7220 whichOp,
7221 whichOp,
7222 (void *)(((uintptr_t)address) - kext_slide),
7223 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7224 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7225 result = kOSKextReturnBadData;
7226 goto finish;
7227 }
7228 }
7229
7230 /* Only do these checks before calling the start function;
7231 * If anything goes wrong with the mapping while the kext is running,
7232 * we'll likely have panicked well before any attempt to stop the kext.
7233 */
7234 if (startFlag) {
7235 if (!isInFileset() || kc_type != KCKindPrimary) {
7236 /*
7237 * Verify that the start/stop function is executable.
7238 */
7239 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7240 (vm_region_recurse_info_t)&info, &count);
7241 if (kern_result != KERN_SUCCESS) {
7242 OSKextLog(this,
7243 kOSKextLogErrorLevel |
7244 kOSKextLogLoadFlag,
7245 "Kext %s - bad %s pointer %p.",
7246 getIdentifierCString(),
7247 whichOp, (void *)ml_static_unslide(address));
7248 result = kOSKextReturnBadData;
7249 goto finish;
7250 }
7251 } else {
7252 /*
7253 * Since kexts loaded from the primary KC are held in memory
7254 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7255 * discover that memory's protection flags. Instead, we need to
7256 * get that information from the kernel pmap itself. Above, we
7257 * (potentially) saved the size of the segment in which the address
7258 * in question was located. If we have a non-zero size, verify
7259 * that all pages in the (address, address + kext_segsize) range
7260 * are marked executable. If we somehow did not record the size
7261 * (or the base) just verify the single page that includes the address.
7262 */
7263 if (kext_segbase == 0 || kext_segsize == 0) {
7264 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7265 kext_segsize = PAGE_SIZE;
7266 }
7267 }
7268
7269 #if VM_MAPPED_KEXTS
7270 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7271 ((isInFileset() && kc_type == KCKindPrimary) &&
7272 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
7273 OSKextLog(this,
7274 kOSKextLogErrorLevel |
7275 kOSKextLogLoadFlag,
7276 "Kext %s - memory region containing module %s function "
7277 "is not executable.",
7278 getIdentifierCString(), whichOp);
7279 result = kOSKextReturnBadData;
7280 goto finish;
7281 }
7282 #endif
7283
7284 /* Verify that the kext's segments are backed by physical memory.
7285 */
7286 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7287 while (seg) {
7288 if (!verifySegmentMapping(seg)) {
7289 result = kOSKextReturnBadData;
7290 goto finish;
7291 }
7292
7293 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7294 }
7295 }
7296
7297 result = kOSReturnSuccess;
7298 finish:
7299 return result;
7300 }
7301
7302 /*********************************************************************
7303 *********************************************************************/
7304 boolean_t
7305 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7306 {
7307 mach_vm_address_t address = 0;
7308
7309 if (seg->vmsize > UINT32_MAX) {
7310 return false;
7311 }
7312
7313 if (!segmentShouldBeWired(seg)) {
7314 return true;
7315 }
7316
7317 for (address = seg->vmaddr;
7318 address < round_page(seg->vmaddr + seg->vmsize);
7319 address += PAGE_SIZE) {
7320 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7321 OSKextLog(this,
7322 kOSKextLogErrorLevel |
7323 kOSKextLogLoadFlag,
7324 "Kext %s - page %p is not backed by physical memory.",
7325 getIdentifierCString(),
7326 (void *)address);
7327 return false;
7328 }
7329 }
7330
7331 return true;
7332 }
7333
7334 /*********************************************************************
7335 *********************************************************************/
7336 static void
7337 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7338 {
7339 uint64_t stamp = 0;
7340 firehose_tracepoint_id_u trace_id;
7341 struct firehose_trace_uuid_info_s uuid_info_s;
7342 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7343 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
7344 OSSharedPtr<OSData> uuid_data;
7345
7346 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7347 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
7348
7349 uuid_data = aKext->copyTextUUID();
7350 if (uuid_data) {
7351 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
7352 }
7353
7354 uuid_info->ftui_size = size;
7355 if (aKext->isDriverKit()) {
7356 uuid_info->ftui_address = address;
7357 } else {
7358 uuid_info->ftui_address = ml_static_unslide(address);
7359 }
7360 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7361 return;
7362 }
7363
7364 void
7365 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7366 {
7367 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7368 }
7369
7370 /*********************************************************************
7371 *********************************************************************/
7372 OSReturn
7373 OSKext::start(bool startDependenciesFlag)
7374 {
7375 OSReturn result = kOSReturnError;
7376 kern_return_t (* startfunc)(kmod_info_t *, void *);
7377 unsigned int i, count;
7378 void * kmodStartData = NULL;
7379
7380 if (isStarted() || isInterface() || isKernelComponent()) {
7381 result = kOSReturnSuccess;
7382 goto finish;
7383 }
7384
7385 if (!isLoaded()) {
7386 OSKextLog(this,
7387 kOSKextLogErrorLevel |
7388 kOSKextLogLoadFlag,
7389 "Attempt to start nonloaded kext %s.",
7390 getIdentifierCString());
7391 result = kOSKextReturnInvalidArgument;
7392 goto finish;
7393 }
7394
7395 if (!sLoadEnabled) {
7396 OSKextLog(this,
7397 kOSKextLogErrorLevel |
7398 kOSKextLogLoadFlag,
7399 "Kext loading is disabled (attempt to start kext %s).",
7400 getIdentifierCString());
7401 result = kOSKextReturnDisabled;
7402 goto finish;
7403 }
7404
7405 result = validateKextMapping(/* start? */ true);
7406 if (result != kOSReturnSuccess) {
7407 goto finish;
7408 }
7409
7410 startfunc = kmod_info->start;
7411
7412 count = getNumDependencies();
7413 for (i = 0; i < count; i++) {
7414 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7415 if (dependency == NULL) {
7416 OSKextLog(this,
7417 kOSKextLogErrorLevel |
7418 kOSKextLogLoadFlag,
7419 "Kext %s start - internal error, dependency disappeared.",
7420 getIdentifierCString());
7421 goto finish;
7422 }
7423 if (!dependency->isStarted()) {
7424 if (startDependenciesFlag) {
7425 OSReturn dependencyResult =
7426 dependency->start(startDependenciesFlag);
7427 if (dependencyResult != KERN_SUCCESS) {
7428 OSKextLog(this,
7429 kOSKextLogErrorLevel |
7430 kOSKextLogLoadFlag,
7431 "Kext %s start - dependency %s failed to start (error 0x%x).",
7432 getIdentifierCString(),
7433 dependency->getIdentifierCString(),
7434 dependencyResult);
7435 goto finish;
7436 }
7437 } else {
7438 OSKextLog(this,
7439 kOSKextLogErrorLevel |
7440 kOSKextLogLoadFlag,
7441 "Not starting %s - dependency %s not started yet.",
7442 getIdentifierCString(),
7443 dependency->getIdentifierCString());
7444 result = kOSKextReturnStartStopError; // xxx - make new return?
7445 goto finish;
7446 }
7447 }
7448 }
7449
7450 OSKextLog(this,
7451 kOSKextLogDetailLevel |
7452 kOSKextLogLoadFlag,
7453 "Kext %s calling module start function.",
7454 getIdentifierCString());
7455
7456 flags.starting = 1;
7457
7458 // Drop a log message so logd can grab the needed information to decode this kext
7459 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7460 result = OSRuntimeInitializeCPP(this);
7461 if (result == KERN_SUCCESS) {
7462 result = startfunc(kmod_info, kmodStartData);
7463 }
7464
7465 flags.starting = 0;
7466
7467 /* On success overlap the setting of started/starting. On failure just
7468 * clear starting.
7469 */
7470 if (result == KERN_SUCCESS) {
7471 flags.started = 1;
7472
7473 // xxx - log start error from kernel?
7474 OSKextLog(this,
7475 kOSKextLogProgressLevel |
7476 kOSKextLogLoadFlag,
7477 "Kext %s is now started.",
7478 getIdentifierCString());
7479 } else {
7480 invokeOrCancelRequestCallbacks(
7481 /* result not actually used */ kOSKextReturnStartStopError,
7482 /* invokeFlag */ false);
7483 OSKextLog(this,
7484 kOSKextLogWarningLevel |
7485 kOSKextLogLoadFlag,
7486 "Kext %s did not start (return code 0x%x).",
7487 getIdentifierCString(), result);
7488 }
7489
7490 finish:
7491 return result;
7492 }
7493
7494 /*********************************************************************
7495 *********************************************************************/
7496 /* static */
7497 bool
7498 OSKext::canUnloadKextWithIdentifier(
7499 OSString * kextIdentifier,
7500 bool checkClassesFlag)
7501 {
7502 bool result = false;
7503 OSKext * aKext = NULL; // do not release
7504
7505 IORecursiveLockLock(sKextLock);
7506
7507 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7508
7509 if (!aKext) {
7510 goto finish; // can't unload what's not loaded
7511 }
7512
7513 if (aKext->isLoaded()) {
7514 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7515 goto finish;
7516 }
7517 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7518 goto finish;
7519 }
7520 }
7521
7522 result = true;
7523
7524 finish:
7525 IORecursiveLockUnlock(sKextLock);
7526 return result;
7527 }
7528
7529 /*********************************************************************
7530 *********************************************************************/
7531 OSReturn
7532 OSKext::stop(void)
7533 {
7534 OSReturn result = kOSReturnError;
7535 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7536
7537 if (!isStarted() || isInterface()) {
7538 result = kOSReturnSuccess;
7539 goto finish;
7540 }
7541
7542 if (!isLoaded()) {
7543 OSKextLog(this,
7544 kOSKextLogErrorLevel |
7545 kOSKextLogLoadFlag,
7546 "Attempt to stop nonloaded kext %s.",
7547 getIdentifierCString());
7548 result = kOSKextReturnInvalidArgument;
7549 goto finish;
7550 }
7551
7552 /* Refuse to stop if we have clients or instances. It is up to
7553 * the caller to make sure those aren't true.
7554 */
7555 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7556 OSKextLog(this,
7557 kOSKextLogErrorLevel |
7558 kOSKextLogLoadFlag,
7559 "Kext %s - C++ instances; can't stop.",
7560 getIdentifierCString());
7561 result = kOSKextReturnInUse;
7562 goto finish;
7563 }
7564
7565 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7566 OSKextLog(this,
7567 kOSKextLogErrorLevel |
7568 kOSKextLogLoadFlag,
7569 "Kext %s - has references (linkage or tracking object); "
7570 "can't stop.",
7571 getIdentifierCString());
7572 result = kOSKextReturnInUse;
7573 goto finish;
7574 }
7575
7576 /* Note: If validateKextMapping fails on the stop & unload path,
7577 * we are in serious trouble and a kernel panic is likely whether
7578 * we stop & unload the kext or not.
7579 */
7580 result = validateKextMapping(/* start? */ false);
7581 if (result != kOSReturnSuccess) {
7582 goto finish;
7583 }
7584
7585 stopfunc = kmod_info->stop;
7586 if (stopfunc) {
7587 OSKextLog(this,
7588 kOSKextLogDetailLevel |
7589 kOSKextLogLoadFlag,
7590 "Kext %s calling module stop function.",
7591 getIdentifierCString());
7592
7593 flags.stopping = 1;
7594
7595 result = stopfunc(kmod_info, /* userData */ NULL);
7596 if (result == KERN_SUCCESS) {
7597 result = OSRuntimeFinalizeCPP(this);
7598 }
7599
7600 flags.stopping = 0;
7601
7602 if (result == KERN_SUCCESS) {
7603 flags.started = 0;
7604
7605 OSKextLog(this,
7606 kOSKextLogDetailLevel |
7607 kOSKextLogLoadFlag,
7608 "Kext %s is now stopped and ready to unload.",
7609 getIdentifierCString());
7610 } else {
7611 OSKextLog(this,
7612 kOSKextLogErrorLevel |
7613 kOSKextLogLoadFlag,
7614 "Kext %s did not stop (return code 0x%x).",
7615 getIdentifierCString(), result);
7616 result = kOSKextReturnStartStopError;
7617 }
7618 }
7619
7620 finish:
7621 // Drop a log message so logd can update this kext's metadata
7622 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7623 return result;
7624 }
7625
7626 /*********************************************************************
7627 *********************************************************************/
7628 OSReturn
7629 OSKext::unload(void)
7630 {
7631 OSReturn result = kOSReturnError;
7632 unsigned int index;
7633 uint32_t num_kmod_refs = 0;
7634 OSKextAccount * freeAccount;
7635 bool in_fileset = false;
7636
7637 if (!sUnloadEnabled) {
7638 OSKextLog(this,
7639 kOSKextLogErrorLevel |
7640 kOSKextLogLoadFlag,
7641 "Kext unloading is disabled (%s).",
7642 this->getIdentifierCString());
7643
7644 result = kOSKextReturnDisabled;
7645 goto finish;
7646 }
7647
7648 // cache this result so we don't need to access the kmod_info after
7649 // it's been potentially free'd
7650 in_fileset = isInFileset();
7651
7652 /* Refuse to unload if we have clients or instances. It is up to
7653 * the caller to make sure those aren't true.
7654 */
7655 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7656 // xxx - Don't log under errors? this is more of an info thing
7657 OSKextLog(this,
7658 kOSKextLogErrorLevel |
7659 kOSKextLogKextBookkeepingFlag,
7660 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7661 getIdentifierCString());
7662 result = kOSKextReturnInUse;
7663 goto finish;
7664 }
7665
7666 if (isDriverKit()) {
7667 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7668 if (index != (unsigned int)-1) {
7669 sLoadedDriverKitKexts->removeObject(index);
7670 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7671 loadTag = 0;
7672 }
7673 }
7674
7675 if (!isLoaded()) {
7676 result = kOSReturnSuccess;
7677 goto finish;
7678 }
7679
7680 if (isKernelComponent()) {
7681 result = kOSKextReturnInvalidArgument;
7682 goto finish;
7683 }
7684
7685 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
7686 OSKextLog(this,
7687 kOSKextLogErrorLevel |
7688 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7689 "Can't unload kext %s; classes have instances:",
7690 getIdentifierCString());
7691 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7692 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7693 result = kOSKextReturnInUse;
7694 goto finish;
7695 }
7696
7697 /* Note that the kext is unloading before running any code that
7698 * might be in the kext (request callbacks, module stop function).
7699 * We will deny certain requests made against a kext in the process
7700 * of unloading.
7701 */
7702 flags.unloading = 1;
7703
7704 /* Update the string describing the last kext to unload in case we panic.
7705 */
7706 savePanicString(/* isLoading */ false);
7707
7708 if (isStarted()) {
7709 result = stop();
7710 if (result != KERN_SUCCESS) {
7711 OSKextLog(this,
7712 kOSKextLogErrorLevel |
7713 kOSKextLogLoadFlag,
7714 "Kext %s can't unload - module stop returned 0x%x.",
7715 getIdentifierCString(), (unsigned)result);
7716 result = kOSKextReturnStartStopError;
7717 goto finish;
7718 }
7719 }
7720
7721 OSKextLog(this,
7722 kOSKextLogProgressLevel |
7723 kOSKextLogLoadFlag,
7724 "Kext %s unloading.",
7725 getIdentifierCString());
7726
7727 {
7728 struct list_head *p;
7729 struct list_head *prev;
7730 struct list_head *next;
7731 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7732 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7733 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7734 prev = p->prev;
7735 next = p->next;
7736 prev->next = next;
7737 next->prev = prev;
7738 p->prev = p;
7739 p->next = p;
7740 IORecursiveLockWakeup(sKextLock, s, false);
7741 }
7742 }
7743
7744
7745 /* Even if we don't call the stop function, we want to be sure we
7746 * have no OSMetaClass references before unloading the kext executable
7747 * from memory. OSMetaClasses may have pointers into the kext executable
7748 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7749 */
7750 if (metaClasses) {
7751 metaClasses->flushCollection();
7752 }
7753 (void) OSRuntimeFinalizeCPP(this);
7754
7755 /* Remove the kext from the list of loaded kexts, patch the gap
7756 * in the kmod_info_t linked list, and reset "kmod" to point to the
7757 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7758 */
7759 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7760 if (index != (unsigned int)-1) {
7761 sLoadedKexts->removeObject(index);
7762
7763 OSKext * nextKext = OSDynamicCast(OSKext,
7764 sLoadedKexts->getObject(index));
7765
7766 if (nextKext) {
7767 if (index > 0) {
7768 OSKext * gapKext = OSDynamicCast(OSKext,
7769 sLoadedKexts->getObject(index - 1));
7770
7771 nextKext->kmod_info->next = gapKext->kmod_info;
7772 } else { /* index == 0 */
7773 nextKext->kmod_info->next = NULL;
7774 }
7775 }
7776
7777 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7778 if (lastKext && !lastKext->isKernel()) {
7779 kmod = lastKext->kmod_info;
7780 } else {
7781 kmod = NULL; // clear the global kmod variable
7782 }
7783 }
7784
7785 /* Clear out the kmod references that we're keeping for compatibility
7786 * with current panic backtrace code & kgmacros.
7787 * xxx - will want to update those bits sometime and remove this.
7788 */
7789 num_kmod_refs = getNumDependencies();
7790 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7791 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7792 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7793 ref->info->reference_count--;
7794 }
7795 kfree(kmod_info->reference_list,
7796 num_kmod_refs * sizeof(kmod_reference_t));
7797 }
7798
7799 #if CONFIG_DTRACE
7800 unregisterWithDTrace();
7801 #endif /* CONFIG_DTRACE */
7802
7803 notifyKextUnloadObservers(this);
7804
7805 freeAccount = NULL;
7806 IOSimpleLockLock(sKextAccountsLock);
7807 account->kext = NULL;
7808 if (account->site.tag) {
7809 account->site.flags |= VM_TAG_UNLOAD;
7810 } else {
7811 freeAccount = account;
7812 }
7813 IOSimpleLockUnlock(sKextAccountsLock);
7814 if (freeAccount) {
7815 IODelete(freeAccount, OSKextAccount, 1);
7816 }
7817
7818 /* Unwire and free the linked executable.
7819 */
7820 if (linkedExecutable) {
7821 #if KASAN
7822 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
7823 #endif
7824
7825 #if VM_MAPPED_KEXTS
7826 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
7827 kernel_segment_command_t *seg = NULL;
7828 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7829
7830 if (!kext_map) {
7831 OSKextLog(this,
7832 kOSKextLogErrorLevel |
7833 kOSKextLogLoadFlag,
7834 "Failed to free kext %s; couldn't find the kext map.",
7835 getIdentifierCString());
7836 result = kOSKextReturnInternalError;
7837 goto finish;
7838 }
7839
7840 OSKextLog(this,
7841 kOSKextLogProgressLevel |
7842 kOSKextLogLoadFlag,
7843 "Kext %s unwiring and unmapping linked executable.",
7844 getIdentifierCString());
7845
7846 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7847 while (seg) {
7848 if (segmentShouldBeWired(seg)) {
7849 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7850 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7851
7852 result = vm_map_unwire(kext_map, start_wire,
7853 end_wire, FALSE);
7854 if (result != KERN_SUCCESS) {
7855 OSKextLog(this,
7856 kOSKextLogErrorLevel |
7857 kOSKextLogLoadFlag,
7858 "Failed to unwire kext %s.",
7859 getIdentifierCString());
7860 result = kOSKextReturnInternalError;
7861 goto finish;
7862 }
7863 }
7864
7865 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7866 }
7867 #if defined(__x86_64__) || defined(__i386__)
7868 if (in_fileset && flags.resetSegmentsFromVnode) {
7869 IORecursiveLockLock(sKextLock);
7870 resetKCFileSetSegments();
7871 IORecursiveLockUnlock(sKextLock);
7872 }
7873 #endif // (__x86_64__) || defined(__i386__)
7874 }
7875 #endif /* VM_MAPPED_KEXTS */
7876 if (flags.resetSegmentsFromImmutableCopy) {
7877 result = resetMutableSegments();
7878 if (result != kOSReturnSuccess) {
7879 OSKextLog(this,
7880 kOSKextLogErrorLevel |
7881 kOSKextLogLoadFlag,
7882 "Failed to reset kext %s.",
7883 getIdentifierCString());
7884 result = kOSKextReturnInternalError;
7885 goto finish;
7886 }
7887 }
7888 if (kc_type == KCKindUnknown) {
7889 linkedExecutable.reset();
7890 }
7891 }
7892
7893 /* An interface kext has a fake kmod_info that was allocated,
7894 * so we have to free it.
7895 */
7896 if (isInterface()) {
7897 kfree(kmod_info, sizeof(kmod_info_t));
7898 kmod_info = NULL;
7899 }
7900
7901 if (!in_fileset) {
7902 kmod_info = NULL;
7903 }
7904
7905 flags.loaded = false;
7906 flushDependencies();
7907
7908 /* save a copy of the bundle ID for us to check when deciding to
7909 * rebuild the kernel cache file. If a kext was already in the kernel
7910 * cache and unloaded then later loaded we do not need to rebuild the
7911 * kernel cache. 9055303
7912 */
7913 if (isPrelinked()) {
7914 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
7915 IORecursiveLockLock(sKextLock);
7916 if (sUnloadedPrelinkedKexts) {
7917 sUnloadedPrelinkedKexts->setObject(bundleID.get());
7918 }
7919 IORecursiveLockUnlock(sKextLock);
7920 }
7921 }
7922
7923 OSKextLog(this,
7924 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
7925 "Kext %s unloaded.", getIdentifierCString());
7926
7927 queueKextNotification(kKextRequestPredicateUnloadNotification,
7928 OSDynamicCast(OSString, bundleID.get()));
7929
7930 finish:
7931 OSKext::saveLoadedKextPanicList();
7932 OSKext::updateLoadedKextSummaries();
7933
7934 flags.unloading = 0;
7935 return result;
7936 }
7937
7938 /*********************************************************************
7939 * Assumes sKextLock is held.
7940 *********************************************************************/
7941 /* static */
7942 OSReturn
7943 OSKext::queueKextNotification(
7944 const char * notificationName,
7945 OSString * kextIdentifier)
7946 {
7947 OSReturn result = kOSReturnError;
7948 OSSharedPtr<OSDictionary> loadRequest;
7949
7950 if (!kextIdentifier) {
7951 result = kOSKextReturnInvalidArgument;
7952 goto finish;
7953 }
7954
7955 /* Create a new request unless one is already sitting
7956 * in sKernelRequests for this bundle identifier
7957 */
7958 result = _OSKextCreateRequest(notificationName, loadRequest);
7959 if (result != kOSReturnSuccess) {
7960 goto finish;
7961 }
7962 if (!_OSKextSetRequestArgument(loadRequest.get(),
7963 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
7964 result = kOSKextReturnNoMemory;
7965 goto finish;
7966 }
7967 if (!sKernelRequests->setObject(loadRequest.get())) {
7968 result = kOSKextReturnNoMemory;
7969 goto finish;
7970 }
7971
7972 /* We might want to only queue the notification if the IOKit daemon is active,
7973 * but that wouldn't work for embedded. Note that we don't care if
7974 * the ping immediately succeeds here so don't do anything with the
7975 * result of this call.
7976 */
7977 OSKext::pingIOKitDaemon();
7978
7979 result = kOSReturnSuccess;
7980
7981 finish:
7982 return result;
7983 }
7984
7985
7986 #if CONFIG_KXLD
7987 /*********************************************************************
7988 *********************************************************************/
7989 static void
7990 _OSKextConsiderDestroyingLinkContext(
7991 __unused thread_call_param_t p0,
7992 __unused thread_call_param_t p1)
7993 {
7994 /* Take multiple locks in the correct order.
7995 */
7996 IORecursiveLockLock(sKextLock);
7997 IORecursiveLockLock(sKextInnerLock);
7998
7999 /* The first time we destroy the kxldContext is in the first
8000 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
8001 * before calling this function. Thereafter any call to this function
8002 * will actually destroy the context.
8003 */
8004 if (sConsiderUnloadsCalled && sKxldContext) {
8005 kxld_destroy_context(sKxldContext);
8006 sKxldContext = NULL;
8007 }
8008
8009 /* Free the thread_call that was allocated to execute this function.
8010 */
8011 if (sDestroyLinkContextThread) {
8012 if (!thread_call_free(sDestroyLinkContextThread)) {
8013 OSKextLog(/* kext */ NULL,
8014 kOSKextLogErrorLevel |
8015 kOSKextLogGeneralFlag,
8016 "thread_call_free() failed for kext link context.");
8017 }
8018 sDestroyLinkContextThread = NULL;
8019 }
8020
8021 IORecursiveLockUnlock(sKextInnerLock);
8022 IORecursiveLockUnlock(sKextLock);
8023
8024 return;
8025 }
8026
8027 /*********************************************************************
8028 * Destroying the kxldContext requires checking variables under both
8029 * sKextInnerLock and sKextLock, so we do it on a separate thread
8030 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8031 * call relationship.
8032 *
8033 * This function must be invoked with sKextInnerLock held.
8034 * Do not call any function that takes sKextLock here!
8035 *********************************************************************/
8036 /* static */
8037 void
8038 OSKext::considerDestroyingLinkContext(void)
8039 {
8040 IORecursiveLockLock(sKextInnerLock);
8041
8042 /* If we have already queued a thread to destroy the link context,
8043 * don't bother resetting; that thread will take care of it.
8044 */
8045 if (sDestroyLinkContextThread) {
8046 goto finish;
8047 }
8048
8049 /* The function to be invoked in the thread will deallocate
8050 * this thread_call, so don't share it around.
8051 */
8052 sDestroyLinkContextThread = thread_call_allocate(
8053 &_OSKextConsiderDestroyingLinkContext, NULL);
8054 if (!sDestroyLinkContextThread) {
8055 OSKextLog(/* kext */ NULL,
8056 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8057 "Can't create thread to destroy kext link context.");
8058 goto finish;
8059 }
8060
8061 thread_call_enter(sDestroyLinkContextThread);
8062
8063 finish:
8064 IORecursiveLockUnlock(sKextInnerLock);
8065 return;
8066 }
8067
8068 #else // !CONFIG_KXLD
8069
8070 /* static */
8071 void
8072 OSKext::considerDestroyingLinkContext(void)
8073 {
8074 return;
8075 }
8076
8077 #endif // CONFIG_KXLD
8078
8079 #if PRAGMA_MARK
8080 #pragma mark Autounload
8081 #endif
8082 /*********************************************************************
8083 * This is a static method because the kext will be deallocated if it
8084 * does unload!
8085 *********************************************************************/
8086 /* static */
8087 OSReturn
8088 OSKext::autounloadKext(OSKext * aKext)
8089 {
8090 OSReturn result = kOSKextReturnInUse;
8091
8092 #if NO_KEXTD
8093 /*
8094 * Do not unload prelinked kexts on platforms that do not have an
8095 * IOKit daemon as there is no way to reload the kext or restart
8096 * matching.
8097 */
8098 if (aKext->isPrelinked()) {
8099 goto finish;
8100 }
8101 #endif /* defined(__x86_64__) */
8102
8103 /* Check for external references to this kext (usu. dependents),
8104 * instances of defined classes (or classes derived from them),
8105 * outstanding requests.
8106 */
8107 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8108 !aKext->flags.autounloadEnabled ||
8109 aKext->isKernelComponent()) {
8110 goto finish;
8111 }
8112
8113 /* Skip a delay-autounload kext, once.
8114 */
8115 if (aKext->flags.delayAutounload) {
8116 OSKextLog(aKext,
8117 kOSKextLogProgressLevel |
8118 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8119 "Kext %s has delayed autounload set; skipping and clearing flag.",
8120 aKext->getIdentifierCString());
8121 aKext->flags.delayAutounload = 0;
8122 goto finish;
8123 }
8124
8125 if (aKext->hasOSMetaClassInstances() ||
8126 aKext->countRequestCallbacks()) {
8127 goto finish;
8128 }
8129
8130 result = OSKext::removeKext(aKext);
8131
8132 finish:
8133 return result;
8134 }
8135
8136 /*********************************************************************
8137 *********************************************************************/
8138 void
8139 _OSKextConsiderUnloads(
8140 __unused thread_call_param_t p0,
8141 __unused thread_call_param_t p1)
8142 {
8143 bool didUnload = false;
8144 unsigned int count, i;
8145
8146 /* Take multiple locks in the correct order
8147 * (note also sKextSummaries lock further down).
8148 */
8149 IORecursiveLockLock(sKextLock);
8150 IORecursiveLockLock(sKextInnerLock);
8151
8152 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8153
8154 /* If the system is powering down, don't try to unload anything.
8155 */
8156 if (sSystemSleep) {
8157 goto finish;
8158 }
8159
8160 OSKextLog(/* kext */ NULL,
8161 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8162 "Checking for unused kexts to autounload.");
8163
8164 /*****
8165 * Remove any request callbacks marked as stale,
8166 * and mark as stale any currently in flight.
8167 */
8168 count = sRequestCallbackRecords->getCount();
8169 if (count) {
8170 i = count - 1;
8171 do {
8172 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8173 sRequestCallbackRecords->getObject(i));
8174 OSBoolean * stale = OSDynamicCast(OSBoolean,
8175 callbackRecord->getObject(kKextRequestStaleKey));
8176
8177 if (stale == kOSBooleanTrue) {
8178 OSKext::invokeRequestCallback(callbackRecord,
8179 kOSKextReturnTimeout);
8180 } else {
8181 callbackRecord->setObject(kKextRequestStaleKey,
8182 kOSBooleanTrue);
8183 }
8184 } while (i--);
8185 }
8186
8187 /*****
8188 * Make multiple passes through the array of loaded kexts until
8189 * we don't unload any. This handles unwinding of dependency
8190 * chains. We have to go *backwards* through the array because
8191 * kexts are removed from it when unloaded, and we cannot make
8192 * a copy or we'll mess up the retain counts we rely on to
8193 * check whether a kext will unload. If only we could have
8194 * nonretaining collections like CF has....
8195 */
8196 do {
8197 didUnload = false;
8198
8199 count = sLoadedKexts->getCount();
8200 if (count) {
8201 i = count - 1;
8202 do {
8203 OSKext * thisKext = OSDynamicCast(OSKext,
8204 sLoadedKexts->getObject(i));
8205 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8206 } while (i--);
8207 }
8208 } while (didUnload);
8209
8210 finish:
8211 sConsiderUnloadsPending = false;
8212 sConsiderUnloadsExecuted = true;
8213
8214 (void) OSKext::considerRebuildOfPrelinkedKernel();
8215
8216 IORecursiveLockUnlock(sKextInnerLock);
8217 IORecursiveLockUnlock(sKextLock);
8218
8219 return;
8220 }
8221
8222 /*********************************************************************
8223 * Do not call any function that takes sKextLock here!
8224 *********************************************************************/
8225 void
8226 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8227 {
8228 AbsoluteTime when;
8229
8230 IORecursiveLockLock(sKextInnerLock);
8231
8232 if (!sUnloadCallout) {
8233 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8234 }
8235
8236 /* we only reset delay value for unloading if we already have something
8237 * pending. rescheduleOnlyFlag should not start the count down.
8238 */
8239 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8240 goto finish;
8241 }
8242
8243 thread_call_cancel(sUnloadCallout);
8244 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8245 #if !NO_KEXTD
8246 && sIOKitDaemonActive
8247 #endif
8248 ) {
8249 clock_interval_to_deadline(sConsiderUnloadDelay,
8250 1000 * 1000 * 1000, &when);
8251
8252 OSKextLog(/* kext */ NULL,
8253 kOSKextLogProgressLevel |
8254 kOSKextLogLoadFlag,
8255 "%scheduling %sscan for unused kexts in %lu seconds.",
8256 sConsiderUnloadsPending ? "Res" : "S",
8257 sConsiderUnloadsCalled ? "" : "initial ",
8258 (unsigned long)sConsiderUnloadDelay);
8259
8260 sConsiderUnloadsPending = true;
8261 thread_call_enter_delayed(sUnloadCallout, when);
8262 }
8263
8264 finish:
8265 /* The kxld context should be reused throughout boot. We mark the end of
8266 * period as the first time considerUnloads() is called, and we destroy
8267 * the first kxld context in that function. Afterwards, it will be
8268 * destroyed in flushNonloadedKexts.
8269 */
8270 if (!sConsiderUnloadsCalled) {
8271 sConsiderUnloadsCalled = true;
8272 OSKext::considerDestroyingLinkContext();
8273 }
8274
8275 IORecursiveLockUnlock(sKextInnerLock);
8276 return;
8277 }
8278
8279 /*********************************************************************
8280 * Do not call any function that takes sKextLock here!
8281 *********************************************************************/
8282 extern "C" {
8283 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
8284 IOReturn
8285 OSKextSystemSleepOrWake(UInt32 messageType)
8286 {
8287 IORecursiveLockLock(sKextInnerLock);
8288
8289 /* If the system is going to sleep, cancel the reaper thread timer,
8290 * and note that we're in a sleep state in case it just fired but hasn't
8291 * taken the lock yet. If we are coming back from sleep, just
8292 * clear the sleep flag; IOService's normal operation will cause
8293 * unloads to be considered soon enough.
8294 */
8295 if (messageType == kIOMessageSystemWillSleep) {
8296 if (sUnloadCallout) {
8297 thread_call_cancel(sUnloadCallout);
8298 }
8299 sSystemSleep = true;
8300 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8301 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8302 sSystemSleep = false;
8303 clock_get_uptime(&sLastWakeTime);
8304 }
8305 IORecursiveLockUnlock(sKextInnerLock);
8306
8307 return kIOReturnSuccess;
8308 }
8309 };
8310
8311
8312 #if PRAGMA_MARK
8313 #pragma mark Prelinked Kernel
8314 #endif
8315
8316 #ifdef CONFIG_KXLD
8317 /*********************************************************************
8318 * Do not access sConsiderUnloads... variables other than
8319 * sConsiderUnloadsExecuted in this function. They are guarded by a
8320 * different lock.
8321 *********************************************************************/
8322 /* static */
8323 void
8324 OSKext::considerRebuildOfPrelinkedKernel(void)
8325 {
8326 static bool requestedPrelink = false;
8327 OSReturn checkResult = kOSReturnError;
8328 OSSharedPtr<OSDictionary> prelinkRequest;
8329 OSSharedPtr<OSCollectionIterator> kextIterator;
8330 const OSSymbol * thisID = NULL; // do not release
8331 bool doRebuild = false;
8332 AbsoluteTime my_abstime;
8333 UInt64 my_ns;
8334 SInt32 delta_secs;
8335
8336 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8337 if (requestedPrelink || !sPrelinkBoot) {
8338 return;
8339 }
8340
8341 /* no direct return from this point */
8342 IORecursiveLockLock(sKextLock);
8343
8344 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8345 * and any new startup kexts loaded.
8346 */
8347 if (!sConsiderUnloadsExecuted ||
8348 !sDeferredLoadSucceeded) {
8349 goto finish;
8350 }
8351
8352 /* we really only care about boot / system start up related kexts so bail
8353 * if we're here after REBUILD_MAX_TIME.
8354 */
8355 if (!_OSKextInPrelinkRebuildWindow()) {
8356 OSKextLog(/* kext */ NULL,
8357 kOSKextLogArchiveFlag,
8358 "%s prebuild rebuild has expired",
8359 __FUNCTION__);
8360 requestedPrelink = true;
8361 goto finish;
8362 }
8363
8364 /* we do not want to trigger a rebuild if we get here too close to waking
8365 * up. (see radar 10233768)
8366 */
8367 IORecursiveLockLock(sKextInnerLock);
8368
8369 clock_get_uptime(&my_abstime);
8370 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8371 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8372 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8373 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8374 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8375 }
8376 IORecursiveLockUnlock(sKextInnerLock);
8377
8378 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8379 /* too close to time of last wake from sleep */
8380 goto finish;
8381 }
8382 requestedPrelink = true;
8383
8384 /* Now it's time to see if we have a reason to rebuild. We may have done
8385 * some loads and unloads but the kernel cache didn't actually change.
8386 * We will rebuild if any kext is not marked prelinked AND is not in our
8387 * list of prelinked kexts that got unloaded. (see radar 9055303)
8388 */
8389 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
8390 if (!kextIterator) {
8391 goto finish;
8392 }
8393
8394 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
8395 OSKext * thisKext; // do not release
8396
8397 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8398 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8399 continue;
8400 }
8401
8402 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
8403 continue;
8404 }
8405 /* kext is loaded and was not in current kernel cache so let's rebuild
8406 */
8407 doRebuild = true;
8408 OSKextLog(/* kext */ NULL,
8409 kOSKextLogArchiveFlag,
8410 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8411 thisKext->bundleID->getCStringNoCopy());
8412 break;
8413 }
8414 sUnloadedPrelinkedKexts->flushCollection();
8415
8416 if (!doRebuild) {
8417 goto finish;
8418 }
8419
8420 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
8421 prelinkRequest);
8422 if (checkResult != kOSReturnSuccess) {
8423 goto finish;
8424 }
8425
8426 if (!sKernelRequests->setObject(prelinkRequest.get())) {
8427 goto finish;
8428 }
8429
8430 OSKext::pingIOKitDaemon();
8431
8432 finish:
8433 IORecursiveLockUnlock(sKextLock);
8434
8435 return;
8436 }
8437
8438 #else /* !CONFIG_KXLD */
8439
8440 void
8441 OSKext::considerRebuildOfPrelinkedKernel(void)
8442 {
8443 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8444 return;
8445 }
8446
8447 #endif /* CONFIG_KXLD */
8448
8449 #if PRAGMA_MARK
8450 #pragma mark Dependencies
8451 #endif
8452 /*********************************************************************
8453 *********************************************************************/
8454 bool
8455 OSKext::resolveDependencies(
8456 OSArray * loopStack)
8457 {
8458 bool result = false;
8459 OSSharedPtr<OSArray> localLoopStack;
8460 bool addedToLoopStack = false;
8461 OSDictionary * libraries = NULL; // do not release
8462 OSSharedPtr<OSCollectionIterator> libraryIterator;
8463 OSString * libraryID = NULL; // do not release
8464 OSKext * libraryKext = NULL; // do not release
8465 bool hasRawKernelDependency = false;
8466 bool hasKernelDependency = false;
8467 bool hasKPIDependency = false;
8468 bool hasPrivateKPIDependency = false;
8469 unsigned int count;
8470
8471 #if CONFIG_KXLD
8472 OSString * infoString = NULL; // do not release
8473 OSString * readableString = NULL; // do not release
8474 #endif // CONFIG_KXLD
8475
8476 /* A kernel component will automatically have this flag set,
8477 * and a loaded kext should also have it set (as should all its
8478 * loaded dependencies).
8479 */
8480 if (flags.hasAllDependencies) {
8481 result = true;
8482 goto finish;
8483 }
8484
8485 /* Check for loops in the dependency graph.
8486 */
8487 if (loopStack) {
8488 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8489 OSKextLog(this,
8490 kOSKextLogErrorLevel |
8491 kOSKextLogDependenciesFlag,
8492 "Kext %s has a dependency loop; can't resolve dependencies.",
8493 getIdentifierCString());
8494 goto finish;
8495 }
8496 } else {
8497 OSKextLog(this,
8498 kOSKextLogStepLevel |
8499 kOSKextLogDependenciesFlag,
8500 "Kext %s resolving dependencies.",
8501 getIdentifierCString());
8502
8503 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8504 if (!localLoopStack) {
8505 OSKextLog(this,
8506 kOSKextLogErrorLevel |
8507 kOSKextLogDependenciesFlag,
8508 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8509 getIdentifierCString());
8510 goto finish;
8511 }
8512 loopStack = localLoopStack.get();
8513 }
8514 if (!loopStack->setObject(this)) {
8515 OSKextLog(this,
8516 kOSKextLogErrorLevel |
8517 kOSKextLogDependenciesFlag,
8518 "Kext %s - internal error resolving dependencies.",
8519 getIdentifierCString());
8520 goto finish;
8521 }
8522 addedToLoopStack = true;
8523
8524 /* Purge any existing kexts in the dependency list and start over.
8525 */
8526 flushDependencies();
8527 if (dependencies) {
8528 OSKextLog(this,
8529 kOSKextLogErrorLevel |
8530 kOSKextLogDependenciesFlag,
8531 "Kext %s - internal error resolving dependencies.",
8532 getIdentifierCString());
8533 }
8534
8535 libraries = OSDynamicCast(OSDictionary,
8536 getPropertyForHostArch(kOSBundleLibrariesKey));
8537 if (libraries == NULL || libraries->getCount() == 0) {
8538 OSKextLog(this,
8539 kOSKextLogErrorLevel |
8540 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8541 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8542 getIdentifierCString(), kOSBundleLibrariesKey);
8543 goto finish;
8544 }
8545
8546 /* Make a new array to hold the dependencies (flush freed the old one).
8547 */
8548 dependencies = OSArray::withCapacity(libraries->getCount());
8549 if (!dependencies) {
8550 OSKextLog(this,
8551 kOSKextLogErrorLevel |
8552 kOSKextLogDependenciesFlag,
8553 "Kext %s - can't allocate dependencies array.",
8554 getIdentifierCString());
8555 goto finish;
8556 }
8557
8558 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8559 // xxx - compat: if none were declared.
8560
8561 libraryIterator = OSCollectionIterator::withCollection(libraries);
8562 if (!libraryIterator) {
8563 OSKextLog(this,
8564 kOSKextLogErrorLevel |
8565 kOSKextLogDependenciesFlag,
8566 "Kext %s - can't allocate dependencies iterator.",
8567 getIdentifierCString());
8568 goto finish;
8569 }
8570
8571 while ((libraryID = OSDynamicCast(OSString,
8572 libraryIterator->getNextObject()))) {
8573 const char * library_id = libraryID->getCStringNoCopy();
8574
8575 OSString * libraryVersion = OSDynamicCast(OSString,
8576 libraries->getObject(libraryID));
8577 if (libraryVersion == NULL) {
8578 OSKextLog(this,
8579 kOSKextLogErrorLevel |
8580 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8581 "Kext %s - illegal type in OSBundleLibraries.",
8582 getIdentifierCString());
8583 goto finish;
8584 }
8585
8586 OSKextVersion libraryVers =
8587 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8588 if (libraryVers == -1) {
8589 OSKextLog(this,
8590 kOSKextLogErrorLevel |
8591 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8592 "Kext %s - invalid library version %s.",
8593 getIdentifierCString(),
8594 libraryVersion->getCStringNoCopy());
8595 goto finish;
8596 }
8597
8598 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8599 if (libraryKext == NULL) {
8600 OSKextLog(this,
8601 kOSKextLogErrorLevel |
8602 kOSKextLogDependenciesFlag,
8603 "Kext %s - library kext %s not found.",
8604 getIdentifierCString(), library_id);
8605 goto finish;
8606 }
8607
8608 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8609 OSKextLog(this,
8610 kOSKextLogErrorLevel |
8611 kOSKextLogDependenciesFlag,
8612 "Kext %s - library kext %s not compatible "
8613 "with requested version %s.",
8614 getIdentifierCString(), library_id,
8615 libraryVersion->getCStringNoCopy());
8616 goto finish;
8617 }
8618
8619 /* If a nonprelinked library somehow got into the mix for a
8620 * prelinked kext, at any point in the chain, we must fail
8621 * because the prelinked relocs for the library will be all wrong.
8622 */
8623 if (this->isPrelinked() &&
8624 libraryKext->declaresExecutable() &&
8625 !libraryKext->isPrelinked()) {
8626 OSKextLog(this,
8627 kOSKextLogErrorLevel |
8628 kOSKextLogDependenciesFlag,
8629 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8630 getIdentifierCString(), library_id,
8631 libraryVersion->getCStringNoCopy());
8632 goto finish;
8633 }
8634
8635 if (!libraryKext->resolveDependencies(loopStack)) {
8636 goto finish;
8637 }
8638
8639 /* Add the library directly only if it has an executable to link.
8640 * Otherwise it's just used to collect other dependencies, so put
8641 * *its* dependencies on the list for this kext.
8642 */
8643 // xxx - We are losing info here; would like to make fake entries or
8644 // xxx - keep these in the dependency graph for loaded kexts.
8645 // xxx - I really want to make kernel components not a special case!
8646 if (libraryKext->declaresExecutable() ||
8647 libraryKext->isInterface()) {
8648 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8649 dependencies->setObject(libraryKext);
8650
8651 OSKextLog(this,
8652 kOSKextLogDetailLevel |
8653 kOSKextLogDependenciesFlag,
8654 "Kext %s added dependency %s.",
8655 getIdentifierCString(),
8656 libraryKext->getIdentifierCString());
8657 }
8658 } else {
8659 int numLibDependencies = libraryKext->getNumDependencies();
8660 OSArray * libraryDependencies = libraryKext->getDependencies();
8661 int index;
8662
8663 if (numLibDependencies) {
8664 // xxx - this msg level should be 1 lower than the per-kext one
8665 OSKextLog(this,
8666 kOSKextLogDetailLevel |
8667 kOSKextLogDependenciesFlag,
8668 "Kext %s pulling %d dependencies from codeless library %s.",
8669 getIdentifierCString(),
8670 numLibDependencies,
8671 libraryKext->getIdentifierCString());
8672 }
8673 for (index = 0; index < numLibDependencies; index++) {
8674 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8675 libraryDependencies->getObject(index));
8676 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8677 dependencies->setObject(thisLibDependency);
8678 OSKextLog(this,
8679 kOSKextLogDetailLevel |
8680 kOSKextLogDependenciesFlag,
8681 "Kext %s added dependency %s from codeless library %s.",
8682 getIdentifierCString(),
8683 thisLibDependency->getIdentifierCString(),
8684 libraryKext->getIdentifierCString());
8685 }
8686 }
8687 }
8688
8689 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8690 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8691 hasRawKernelDependency = true;
8692 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8693 hasKernelDependency = true;
8694 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8695 hasKPIDependency = true;
8696 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8697 hasPrivateKPIDependency = true;
8698 }
8699 }
8700 }
8701
8702 if (hasRawKernelDependency) {
8703 OSKextLog(this,
8704 kOSKextLogErrorLevel |
8705 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8706 "Error - kext %s declares a dependency on %s, which is not permitted.",
8707 getIdentifierCString(), KERNEL_LIB);
8708 goto finish;
8709 }
8710 #if __LP64__
8711 if (hasKernelDependency) {
8712 OSKextLog(this,
8713 kOSKextLogErrorLevel |
8714 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8715 "Error - kext %s declares %s dependencies. "
8716 "Only %s* dependencies are supported for 64-bit kexts.",
8717 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8718 goto finish;
8719 }
8720 if (!hasKPIDependency) {
8721 OSKextLog(this,
8722 kOSKextLogWarningLevel |
8723 kOSKextLogDependenciesFlag,
8724 "Warning - kext %s declares no %s* dependencies. "
8725 "If it uses any KPIs, the link may fail with undefined symbols.",
8726 getIdentifierCString(), KPI_LIB_PREFIX);
8727 }
8728 #else /* __LP64__ */
8729 // xxx - will change to flatly disallow "kernel" dependencies at some point
8730 // xxx - is it invalid to do both "com.apple.kernel" and any
8731 // xxx - "com.apple.kernel.*"?
8732
8733 if (hasKernelDependency && hasKPIDependency) {
8734 OSKextLog(this,
8735 kOSKextLogWarningLevel |
8736 kOSKextLogDependenciesFlag,
8737 "Warning - kext %s has immediate dependencies on both "
8738 "%s* and %s* components; use only one style.",
8739 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8740 }
8741
8742 if (!hasKernelDependency && !hasKPIDependency) {
8743 // xxx - do we want to use validation flag for these too?
8744 OSKextLog(this,
8745 kOSKextLogWarningLevel |
8746 kOSKextLogDependenciesFlag,
8747 "Warning - %s declares no kernel dependencies; using %s.",
8748 getIdentifierCString(), KERNEL6_LIB);
8749 OSKext * kernelKext = OSDynamicCast(OSKext,
8750 sKextsByID->getObject(KERNEL6_LIB));
8751 if (kernelKext) {
8752 dependencies->setObject(kernelKext);
8753 } else {
8754 OSKextLog(this,
8755 kOSKextLogErrorLevel |
8756 kOSKextLogDependenciesFlag,
8757 "Error - Library %s not found for %s.",
8758 KERNEL6_LIB, getIdentifierCString());
8759 }
8760 }
8761
8762 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8763 * its indirect dependencies to simulate old-style linking. XXX - Should
8764 * check for duplicates.
8765 */
8766 if (!hasKPIDependency) {
8767 unsigned int i;
8768
8769 flags.hasBleedthrough = true;
8770
8771 count = getNumDependencies();
8772
8773 /* We add to the dependencies array in this loop, but do not iterate
8774 * past its original count.
8775 */
8776 for (i = 0; i < count; i++) {
8777 OSKext * dependencyKext = OSDynamicCast(OSKext,
8778 dependencies->getObject(i));
8779 dependencyKext->addBleedthroughDependencies(dependencies.get());
8780 }
8781 }
8782 #endif /* __LP64__ */
8783
8784 #if CONFIG_KXLD
8785 /*
8786 * If we're not dynamically linking kexts, then we don't need to check
8787 * copyright strings. The linker in user space has already done this.
8788 */
8789 if (hasPrivateKPIDependency) {
8790 bool hasApplePrefix = false;
8791 bool infoCopyrightIsValid = false;
8792 bool readableCopyrightIsValid = false;
8793
8794 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8795 APPLE_KEXT_PREFIX);
8796
8797 infoString = OSDynamicCast(OSString,
8798 getPropertyForHostArch("CFBundleGetInfoString"));
8799 if (infoString) {
8800 infoCopyrightIsValid =
8801 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8802 }
8803
8804 readableString = OSDynamicCast(OSString,
8805 getPropertyForHostArch("NSHumanReadableCopyright"));
8806 if (readableString) {
8807 readableCopyrightIsValid =
8808 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8809 }
8810
8811 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8812 OSKextLog(this,
8813 kOSKextLogErrorLevel |
8814 kOSKextLogDependenciesFlag,
8815 "Error - kext %s declares a dependency on %s. "
8816 "Only Apple kexts may declare a dependency on %s.",
8817 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8818 goto finish;
8819 }
8820 }
8821 #endif // CONFIG_KXLD
8822
8823 result = true;
8824 flags.hasAllDependencies = 1;
8825
8826 finish:
8827
8828 if (addedToLoopStack) {
8829 count = loopStack->getCount();
8830 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8831 loopStack->removeObject(count - 1);
8832 } else {
8833 OSKextLog(this,
8834 kOSKextLogErrorLevel |
8835 kOSKextLogDependenciesFlag,
8836 "Kext %s - internal error resolving dependencies.",
8837 getIdentifierCString());
8838 }
8839 }
8840
8841 if (result && localLoopStack) {
8842 OSKextLog(this,
8843 kOSKextLogStepLevel |
8844 kOSKextLogDependenciesFlag,
8845 "Kext %s successfully resolved dependencies.",
8846 getIdentifierCString());
8847 }
8848
8849 return result;
8850 }
8851
8852 /*********************************************************************
8853 *********************************************************************/
8854 bool
8855 OSKext::addBleedthroughDependencies(OSArray * anArray)
8856 {
8857 bool result = false;
8858 unsigned int dependencyIndex, dependencyCount;
8859
8860 dependencyCount = getNumDependencies();
8861
8862 for (dependencyIndex = 0;
8863 dependencyIndex < dependencyCount;
8864 dependencyIndex++) {
8865 OSKext * dependency = OSDynamicCast(OSKext,
8866 dependencies->getObject(dependencyIndex));
8867 if (!dependency) {
8868 OSKextLog(this,
8869 kOSKextLogErrorLevel |
8870 kOSKextLogDependenciesFlag,
8871 "Kext %s - internal error propagating compatibility dependencies.",
8872 getIdentifierCString());
8873 goto finish;
8874 }
8875 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8876 anArray->setObject(dependency);
8877 }
8878 dependency->addBleedthroughDependencies(anArray);
8879 }
8880
8881 result = true;
8882
8883 finish:
8884 return result;
8885 }
8886
8887 /*********************************************************************
8888 *********************************************************************/
8889 bool
8890 OSKext::flushDependencies(bool forceFlag)
8891 {
8892 bool result = false;
8893
8894 /* Only clear the dependencies if the kext isn't loaded;
8895 * we need the info for loaded kexts to track references.
8896 */
8897 if (!isLoaded() || forceFlag) {
8898 if (dependencies) {
8899 // xxx - check level
8900 OSKextLog(this,
8901 kOSKextLogProgressLevel |
8902 kOSKextLogDependenciesFlag,
8903 "Kext %s flushing dependencies.",
8904 getIdentifierCString());
8905 dependencies.reset();
8906 }
8907 if (!isKernelComponent()) {
8908 flags.hasAllDependencies = 0;
8909 }
8910 result = true;
8911 }
8912
8913 return result;
8914 }
8915
8916 /*********************************************************************
8917 *********************************************************************/
8918 uint32_t
8919 OSKext::getNumDependencies(void)
8920 {
8921 if (!dependencies) {
8922 return 0;
8923 }
8924 return dependencies->getCount();
8925 }
8926
8927 /*********************************************************************
8928 *********************************************************************/
8929 OSArray *
8930 OSKext::getDependencies(void)
8931 {
8932 return dependencies.get();
8933 }
8934
8935 bool
8936 OSKext::hasDependency(const OSSymbol * depID)
8937 {
8938 bool result __block;
8939
8940 if (depID == getIdentifier()) {
8941 return true;
8942 }
8943 if (!dependencies) {
8944 return false;
8945 }
8946 result = false;
8947 dependencies->iterateObjects(^bool (OSObject * obj) {
8948 OSKext * kext;
8949 kext = OSDynamicCast(OSKext, obj);
8950 if (!kext) {
8951 return false;
8952 }
8953 result = (depID == kext->getIdentifier());
8954 return result;
8955 });
8956 return result;
8957 }
8958
8959 #if PRAGMA_MARK
8960 #pragma mark OSMetaClass Support
8961 #endif
8962 /*********************************************************************
8963 *********************************************************************/
8964 OSReturn
8965 OSKext::addClass(
8966 OSMetaClass * aClass,
8967 uint32_t numClasses)
8968 {
8969 OSReturn result = kOSMetaClassNoInsKModSet;
8970
8971 if (!metaClasses) {
8972 metaClasses = OSSet::withCapacity(numClasses);
8973 if (!metaClasses) {
8974 goto finish;
8975 }
8976 }
8977
8978 if (metaClasses->containsObject(aClass)) {
8979 OSKextLog(this,
8980 kOSKextLogWarningLevel |
8981 kOSKextLogLoadFlag,
8982 "Notice - kext %s has already registered class %s.",
8983 getIdentifierCString(),
8984 aClass->getClassName());
8985 result = kOSReturnSuccess;
8986 goto finish;
8987 }
8988
8989 if (!metaClasses->setObject(aClass)) {
8990 goto finish;
8991 } else {
8992 OSKextLog(this,
8993 kOSKextLogDetailLevel |
8994 kOSKextLogLoadFlag,
8995 "Kext %s registered class %s.",
8996 getIdentifierCString(),
8997 aClass->getClassName());
8998 }
8999
9000 if (!flags.autounloadEnabled) {
9001 const OSMetaClass * metaScan = NULL; // do not release
9002
9003 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
9004 if (metaScan == OSTypeID(IOService)) {
9005 OSKextLog(this,
9006 kOSKextLogProgressLevel |
9007 kOSKextLogLoadFlag,
9008 "Kext %s has IOService subclass %s; enabling autounload.",
9009 getIdentifierCString(),
9010 aClass->getClassName());
9011
9012 flags.autounloadEnabled = (0 == flags.unloadUnsupported);
9013 break;
9014 }
9015 }
9016 }
9017
9018 notifyAddClassObservers(this, aClass, flags);
9019
9020 result = kOSReturnSuccess;
9021
9022 finish:
9023 if (result != kOSReturnSuccess) {
9024 OSKextLog(this,
9025 kOSKextLogErrorLevel |
9026 kOSKextLogLoadFlag,
9027 "Kext %s failed to register class %s.",
9028 getIdentifierCString(),
9029 aClass->getClassName());
9030 }
9031
9032 return result;
9033 }
9034
9035 /*********************************************************************
9036 *********************************************************************/
9037 OSReturn
9038 OSKext::removeClass(
9039 OSMetaClass * aClass)
9040 {
9041 OSReturn result = kOSMetaClassNoKModSet;
9042
9043 if (!metaClasses) {
9044 goto finish;
9045 }
9046
9047 if (!metaClasses->containsObject(aClass)) {
9048 OSKextLog(this,
9049 kOSKextLogWarningLevel |
9050 kOSKextLogLoadFlag,
9051 "Notice - kext %s asked to unregister unknown class %s.",
9052 getIdentifierCString(),
9053 aClass->getClassName());
9054 result = kOSReturnSuccess;
9055 goto finish;
9056 }
9057
9058 OSKextLog(this,
9059 kOSKextLogDetailLevel |
9060 kOSKextLogLoadFlag,
9061 "Kext %s unregistering class %s.",
9062 getIdentifierCString(),
9063 aClass->getClassName());
9064
9065 metaClasses->removeObject(aClass);
9066
9067 notifyRemoveClassObservers(this, aClass, flags);
9068
9069 result = kOSReturnSuccess;
9070
9071 finish:
9072 if (result != kOSReturnSuccess) {
9073 OSKextLog(this,
9074 kOSKextLogErrorLevel |
9075 kOSKextLogLoadFlag,
9076 "Failed to unregister kext %s class %s.",
9077 getIdentifierCString(),
9078 aClass->getClassName());
9079 }
9080 return result;
9081 }
9082
9083 /*********************************************************************
9084 *********************************************************************/
9085 OSSet *
9086 OSKext::getMetaClasses(void)
9087 {
9088 return metaClasses.get();
9089 }
9090
9091 /*********************************************************************
9092 *********************************************************************/
9093 bool
9094 OSKext::hasOSMetaClassInstances(void)
9095 {
9096 bool result = false;
9097 OSSharedPtr<OSCollectionIterator> classIterator;
9098 OSMetaClass * checkClass = NULL; // do not release
9099
9100 if (!metaClasses) {
9101 goto finish;
9102 }
9103
9104 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9105 if (!classIterator) {
9106 // xxx - log alloc failure?
9107 goto finish;
9108 }
9109 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9110 if (checkClass->getInstanceCount()) {
9111 result = true;
9112 goto finish;
9113 }
9114 }
9115
9116 finish:
9117 return result;
9118 }
9119
9120 /*********************************************************************
9121 *********************************************************************/
9122 /* static */
9123 void
9124 OSKext::reportOSMetaClassInstances(
9125 const char * kextIdentifier,
9126 OSKextLogSpec msgLogSpec)
9127 {
9128 OSSharedPtr<OSKext> theKext;
9129
9130 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9131 if (!theKext) {
9132 goto finish;
9133 }
9134
9135 theKext->reportOSMetaClassInstances(msgLogSpec);
9136 finish:
9137 return;
9138 }
9139
9140 /*********************************************************************
9141 *********************************************************************/
9142 void
9143 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9144 {
9145 OSSharedPtr<OSCollectionIterator> classIterator;
9146 OSMetaClass * checkClass = NULL; // do not release
9147
9148 if (!metaClasses) {
9149 goto finish;
9150 }
9151
9152 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9153 if (!classIterator) {
9154 goto finish;
9155 }
9156 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9157 if (checkClass->getInstanceCount()) {
9158 OSKextLog(this,
9159 msgLogSpec,
9160 " Kext %s class %s has %d instance%s.",
9161 getIdentifierCString(),
9162 checkClass->getClassName(),
9163 checkClass->getInstanceCount(),
9164 checkClass->getInstanceCount() == 1 ? "" : "s");
9165 }
9166 }
9167
9168 finish:
9169 return;
9170 }
9171
9172 #if PRAGMA_MARK
9173 #pragma mark User-Space Requests
9174 #endif
9175
9176 static kern_return_t
9177 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9178 {
9179 OSReturn result = kOSReturnSuccess;
9180 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9181 OSDictionary * request = NULL; //do not release
9182 IOUserServerCheckInToken * token = NULL; //do not release
9183 OSString * requestPredicate = NULL; //do not release
9184 OSSharedPtr<OSNumber> portNameNumber;
9185 mach_port_name_t portName = 0;
9186 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9187 if (!request) {
9188 OSKextLog(/* kext */ NULL,
9189 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9190 "Elements of request should be of type OSDictionary");
9191 result = kOSKextReturnInternalError;
9192 goto finish;
9193 }
9194 requestPredicate = _OSKextGetRequestPredicate(request);
9195 if (!requestPredicate) {
9196 OSKextLog(/* kext */ NULL,
9197 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9198 "Failed to get request predicate");
9199 result = kOSKextReturnInternalError;
9200 goto finish;
9201 }
9202 // is this a dext launch?
9203 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9204 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9205 if (!token) {
9206 OSKextLog(/* kext */ NULL,
9207 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9208 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9209 result = kOSKextReturnInternalError;
9210 goto finish;
9211 }
9212 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9213 if (portName == 0 || portName == MACH_PORT_DEAD) {
9214 OSKextLog(/* kext */ NULL,
9215 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9216 "Could not create send right for object.");
9217 result = kOSKextReturnInternalError;
9218 goto finish;
9219 }
9220 // Store the mach port name as a OSNumber
9221 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9222 if (!portNameNumber) {
9223 OSKextLog(/* kext */ NULL,
9224 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9225 "Could not create OSNumber object.");
9226 result = kOSKextReturnNoMemory;
9227 goto finish;
9228 }
9229 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9230 OSKextLog(/* kext */ NULL,
9231 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9232 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9233 result = kOSKextReturnNoMemory;
9234 goto finish;
9235 }
9236 }
9237 finish:
9238 if (result != kOSReturnSuccess) {
9239 break;
9240 }
9241 }
9242 return result;
9243 }
9244
9245 /*********************************************************************
9246 * XXX - this function is a big ugly mess
9247 *********************************************************************/
9248 /* static */
9249 OSReturn
9250 OSKext::handleRequest(
9251 host_priv_t hostPriv,
9252 OSKextLogSpec clientLogFilter,
9253 char * requestBuffer,
9254 uint32_t requestLength,
9255 char ** responseOut,
9256 uint32_t * responseLengthOut,
9257 char ** logInfoOut,
9258 uint32_t * logInfoLengthOut)
9259 {
9260 OSReturn result = kOSReturnError;
9261 kern_return_t kmem_result = KERN_FAILURE;
9262
9263 char * response = NULL; // returned by reference
9264 uint32_t responseLength = 0;
9265
9266 bool taskCanManageAllKCs = false;
9267 bool taskOnlyManagesBootKC = false;
9268
9269 OSSharedPtr<OSObject> parsedXML;
9270 OSDictionary * requestDict = NULL; // do not release
9271 OSSharedPtr<OSString> errorString;
9272
9273 OSSharedPtr<OSObject> responseObject;
9274
9275 OSSharedPtr<OSSerialize> serializer;
9276
9277 OSSharedPtr<OSArray> logInfoArray;
9278
9279 OSString * predicate = NULL; // do not release
9280 OSString * kextIdentifier = NULL; // do not release
9281 OSArray * kextIdentifiers = NULL; // do not release
9282 OSKext * theKext = NULL; // do not release
9283 OSBoolean * boolArg = NULL; // do not release
9284
9285 IORecursiveLockLock(sKextLock);
9286
9287 if (responseOut) {
9288 *responseOut = NULL;
9289 *responseLengthOut = 0;
9290 }
9291 if (logInfoOut) {
9292 *logInfoOut = NULL;
9293 *logInfoLengthOut = 0;
9294 }
9295
9296 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9297
9298 /* XML must be nul-terminated.
9299 */
9300 if (requestBuffer[requestLength - 1] != '\0') {
9301 OSKextLog(/* kext */ NULL,
9302 kOSKextLogErrorLevel |
9303 kOSKextLogIPCFlag,
9304 "Invalid request from user space (not nul-terminated).");
9305 result = kOSKextReturnBadData;
9306 goto finish;
9307 }
9308 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
9309 if (parsedXML) {
9310 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
9311 }
9312 if (!requestDict) {
9313 const char * errorCString = "(unknown error)";
9314
9315 if (errorString && errorString->getCStringNoCopy()) {
9316 errorCString = errorString->getCStringNoCopy();
9317 } else if (parsedXML) {
9318 errorCString = "not a dictionary";
9319 }
9320 OSKextLog(/* kext */ NULL,
9321 kOSKextLogErrorLevel |
9322 kOSKextLogIPCFlag,
9323 "Error unserializing request from user space: %s.",
9324 errorCString);
9325 result = kOSKextReturnSerialization;
9326 goto finish;
9327 }
9328
9329 predicate = _OSKextGetRequestPredicate(requestDict);
9330 if (!predicate) {
9331 OSKextLog(/* kext */ NULL,
9332 kOSKextLogErrorLevel |
9333 kOSKextLogIPCFlag,
9334 "Recieved kext request from user space with no predicate.");
9335 result = kOSKextReturnInvalidArgument;
9336 goto finish;
9337 }
9338
9339 OSKextLog(/* kext */ NULL,
9340 kOSKextLogDebugLevel |
9341 kOSKextLogIPCFlag,
9342 "Received '%s' request from user space.",
9343 predicate->getCStringNoCopy());
9344
9345 /*
9346 * All management of file sets requires an entitlement
9347 */
9348 result = kOSKextReturnNotPrivileged;
9349 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9350 predicate->isEqualTo(kKextRequestPredicateStart) ||
9351 predicate->isEqualTo(kKextRequestPredicateStop) ||
9352 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9353 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9354 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9355 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9356 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9357 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9358 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9359 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9360 if (hostPriv == HOST_PRIV_NULL) {
9361 OSKextLog(/* kext */ NULL,
9362 kOSKextLogErrorLevel |
9363 kOSKextLogIPCFlag,
9364 "Access Failure - must be root user.");
9365 goto finish;
9366 }
9367 taskCanManageAllKCs = IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement) == TRUE;
9368 taskOnlyManagesBootKC = IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9369
9370 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9371 OSKextLog(/* kext */ NULL,
9372 kOSKextLogErrorLevel |
9373 kOSKextLogIPCFlag,
9374 "Access Failure - client not entitled to manage file sets.");
9375 goto finish;
9376 }
9377
9378 /*
9379 * The OnlyBootKC entitlement restricts the
9380 * collection-management entitlement to only managing kexts in
9381 * the BootKC. All other predicates that alter global state or
9382 * add new KCs are disallowed.
9383 */
9384 if (taskOnlyManagesBootKC &&
9385 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9386 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9387 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9388 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9389 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9390 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9391 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9392 OSKextLog(/* kext */ NULL,
9393 kOSKextLogErrorLevel |
9394 kOSKextLogIPCFlag,
9395 "Access Failure - client not entitled to manage non-primary KCs");
9396 goto finish;
9397 }
9398
9399 /*
9400 * If we get here, then the process either has the full KC
9401 * management entitlement, or it has the BootKC-only
9402 * entitlement and the request is about the BootKC.
9403 */
9404 }
9405
9406 /* Get common args in anticipation of use.
9407 */
9408 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9409 requestDict, kKextRequestArgumentBundleIdentifierKey));
9410 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9411 requestDict, kKextRequestArgumentBundleIdentifierKey));
9412 if (kextIdentifier) {
9413 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9414 }
9415 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9416 requestDict, kKextRequestArgumentValueKey));
9417
9418 if (taskOnlyManagesBootKC &&
9419 theKext &&
9420 theKext->isInFileset() &&
9421 theKext->kc_type != KCKindPrimary) {
9422 OSKextLog(/* kext */ NULL,
9423 kOSKextLogErrorLevel |
9424 kOSKextLogIPCFlag,
9425 "Access Failure - client not entitled to manage kext in non-primary KC");
9426 result = kOSKextReturnNotPrivileged;
9427 goto finish;
9428 }
9429
9430 result = kOSKextReturnInvalidArgument;
9431
9432 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9433 if (!kextIdentifier) {
9434 OSKextLog(/* kext */ NULL,
9435 kOSKextLogErrorLevel |
9436 kOSKextLogIPCFlag,
9437 "Invalid arguments to kext start request.");
9438 } else if (!theKext) {
9439 OSKextLog(/* kext */ NULL,
9440 kOSKextLogErrorLevel |
9441 kOSKextLogIPCFlag,
9442 "Kext %s not found for start request.",
9443 kextIdentifier->getCStringNoCopy());
9444 result = kOSKextReturnNotFound;
9445 } else {
9446 result = theKext->start();
9447 }
9448 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9449 if (!kextIdentifier) {
9450 OSKextLog(/* kext */ NULL,
9451 kOSKextLogErrorLevel |
9452 kOSKextLogIPCFlag,
9453 "Invalid arguments to kext stop request.");
9454 } else if (!theKext) {
9455 OSKextLog(/* kext */ NULL,
9456 kOSKextLogErrorLevel |
9457 kOSKextLogIPCFlag,
9458 "Kext %s not found for stop request.",
9459 kextIdentifier->getCStringNoCopy());
9460 result = kOSKextReturnNotFound;
9461 } else {
9462 result = theKext->stop();
9463 }
9464 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9465 result = OSKext::setMissingAuxKCBundles(requestDict);
9466 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9467 if (!kextIdentifier) {
9468 OSKextLog(/* kext */ NULL,
9469 kOSKextLogErrorLevel |
9470 kOSKextLogIPCFlag,
9471 "Invalid arguments to AuxKC Bundle Available request.");
9472 } else {
9473 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9474 }
9475 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9476 if (!kextIdentifier) {
9477 OSKextLog(/* kext */ NULL,
9478 kOSKextLogErrorLevel |
9479 kOSKextLogIPCFlag,
9480 "Invalid arguments to kext load from KC request.");
9481 } else if (!theKext) {
9482 OSKextLog(/* kext */ NULL,
9483 kOSKextLogErrorLevel |
9484 kOSKextLogIPCFlag,
9485 "Kext %s not found for load from KC request.",
9486 kextIdentifier->getCStringNoCopy());
9487 result = kOSKextReturnNotFound;
9488 } else if (!theKext->isInFileset()) {
9489 OSKextLog(/* kext */ NULL,
9490 kOSKextLogErrorLevel |
9491 kOSKextLogIPCFlag,
9492 "Kext %s does not exist in a KC: refusing to load.",
9493 kextIdentifier->getCStringNoCopy());
9494 result = kOSKextReturnNotLoadable;
9495 } else {
9496 result = OSKext::loadKextFromKC(theKext, requestDict);
9497 }
9498 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9499 if (!kextIdentifier) {
9500 OSKextLog(/* kext */ NULL,
9501 kOSKextLogErrorLevel |
9502 kOSKextLogIPCFlag,
9503 "Invalid arguments to codeless kext load interface (missing identifier).");
9504 } else {
9505 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9506 }
9507 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9508 if (!kextIdentifier) {
9509 OSKextLog(/* kext */ NULL,
9510 kOSKextLogErrorLevel |
9511 kOSKextLogIPCFlag,
9512 "Invalid arguments to kext unload request.");
9513 } else if (!theKext) {
9514 OSKextLog(/* kext */ NULL,
9515 kOSKextLogErrorLevel |
9516 kOSKextLogIPCFlag,
9517 "Kext %s not found for unload request.",
9518 kextIdentifier->getCStringNoCopy());
9519 result = kOSKextReturnNotFound;
9520 } else {
9521 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9522 _OSKextGetRequestArgument(requestDict,
9523 kKextRequestArgumentTerminateIOServicesKey));
9524 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9525 }
9526 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9527 result = OSKext::dispatchResource(requestDict);
9528 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9529 OSNumber *lookupNum = NULL;
9530 lookupNum = OSDynamicCast(OSNumber,
9531 _OSKextGetRequestArgument(requestDict,
9532 kKextRequestArgumentLookupAddressKey));
9533
9534 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9535 if (responseObject) {
9536 result = kOSReturnSuccess;
9537 } else {
9538 goto finish;
9539 }
9540 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
9541 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9542 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9543 OSBoolean * delayAutounloadBool = NULL;
9544 OSObject * infoKeysRaw = NULL;
9545 OSArray * infoKeys = NULL;
9546 uint32_t infoKeysCount = 0;
9547
9548 delayAutounloadBool = OSDynamicCast(OSBoolean,
9549 _OSKextGetRequestArgument(requestDict,
9550 kKextRequestArgumentDelayAutounloadKey));
9551
9552 /* If asked to delay autounload, reset the timer if it's currently set.
9553 * (That is, don't schedule an unload if one isn't already pending.
9554 */
9555 if (delayAutounloadBool == kOSBooleanTrue) {
9556 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9557 }
9558
9559 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9560 kKextRequestArgumentInfoKeysKey);
9561 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9562 if (infoKeysRaw && !infoKeys) {
9563 OSKextLog(/* kext */ NULL,
9564 kOSKextLogErrorLevel |
9565 kOSKextLogIPCFlag,
9566 "Invalid arguments to kext info request.");
9567 goto finish;
9568 }
9569
9570 if (infoKeys) {
9571 infoKeysCount = infoKeys->getCount();
9572 for (uint32_t i = 0; i < infoKeysCount; i++) {
9573 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9574 OSKextLog(/* kext */ NULL,
9575 kOSKextLogErrorLevel |
9576 kOSKextLogIPCFlag,
9577 "Invalid arguments to kext info request.");
9578 goto finish;
9579 }
9580 }
9581 }
9582
9583 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9584 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9585 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9586 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
9587 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9588 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
9589 }
9590
9591 if (!responseObject) {
9592 result = kOSKextReturnInternalError;
9593 } else {
9594 OSKextLog(/* kext */ NULL,
9595 kOSKextLogDebugLevel |
9596 kOSKextLogIPCFlag,
9597 "Returning loaded kext info.");
9598 result = kOSReturnSuccess;
9599 }
9600 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9601 /* Hand the current sKernelRequests array to the caller
9602 * (who must release it), and make a new one.
9603 */
9604 responseObject = os::move(sKernelRequests);
9605 sKernelRequests = OSArray::withCapacity(0);
9606 sPostedKextLoadIdentifiers->flushCollection();
9607 OSKextLog(/* kext */ NULL,
9608 kOSKextLogDebugLevel |
9609 kOSKextLogIPCFlag,
9610 "Returning kernel requests.");
9611 result = kOSReturnSuccess;
9612 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9613 /* Return the set of all requested bundle identifiers */
9614 responseObject = sAllKextLoadIdentifiers;
9615 OSKextLog(/* kext */ NULL,
9616 kOSKextLogDebugLevel |
9617 kOSKextLogIPCFlag,
9618 "Returning load requests.");
9619 result = kOSReturnSuccess;
9620 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9621 printf("KextLog: Loading FileSet KC(s)\n");
9622 result = OSKext::loadFileSetKexts(requestDict);
9623 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9624 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9625 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
9626 } else {
9627 OSKextLog(/* kext */ NULL,
9628 kOSKextLogDebugLevel |
9629 kOSKextLogIPCFlag,
9630 "Received '%s' invalid request from user space.",
9631 predicate->getCStringNoCopy());
9632 goto finish;
9633 }
9634
9635 /**********
9636 * Now we have handle the request, or not. Gather up the response & logging
9637 * info to ship to user space.
9638 *********/
9639
9640 /* Note: Nothing in OSKext is supposed to retain requestDict,
9641 * but you never know....
9642 */
9643 if (requestDict->getRetainCount() > 1) {
9644 OSKextLog(/* kext */ NULL,
9645 kOSKextLogWarningLevel |
9646 kOSKextLogIPCFlag,
9647 "Request from user space still retained by a kext; "
9648 "probable memory leak.");
9649 }
9650
9651 if (responseOut && responseObject) {
9652 serializer = OSSerialize::withCapacity(0);
9653 if (!serializer) {
9654 result = kOSKextReturnNoMemory;
9655 goto finish;
9656 }
9657 /*
9658 * Before serializing the kernel requests, patch the dext launch requests so
9659 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9660 * IOUserServerCheckInToken kernel object.
9661 */
9662 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9663 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9664 task_t calling_task = current_task();
9665 if (!requests) {
9666 OSKextLog(/* kext */ NULL,
9667 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9668 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9669 result = kOSKextReturnInternalError;
9670 goto finish;
9671 }
9672 result = patchDextLaunchRequests(calling_task, requests);
9673 if (result != kOSReturnSuccess) {
9674 OSKextLog(/* kext */ NULL,
9675 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9676 "Failed to patch dext launch requests.");
9677 goto finish;
9678 }
9679 }
9680
9681 if (!responseObject->serialize(serializer.get())) {
9682 OSKextLog(/* kext */ NULL,
9683 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9684 "Failed to serialize response to request from user space.");
9685 result = kOSKextReturnSerialization;
9686 goto finish;
9687 }
9688
9689 response = (char *)serializer->text();
9690 responseLength = serializer->getLength();
9691 }
9692
9693 if (responseOut && response) {
9694 char * buffer;
9695
9696 /* This kmem_alloc sets the return value of the function.
9697 */
9698 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9699 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
9700 if (kmem_result != KERN_SUCCESS) {
9701 OSKextLog(/* kext */ NULL,
9702 kOSKextLogErrorLevel |
9703 kOSKextLogIPCFlag,
9704 "Failed to copy response to request from user space.");
9705 result = kmem_result;
9706 goto finish;
9707 } else {
9708 /* 11981737 - clear uninitialized data in last page */
9709 bzero((void *)(buffer + responseLength),
9710 (round_page(responseLength) - responseLength));
9711 memcpy(buffer, response, responseLength);
9712 *responseOut = buffer;
9713 *responseLengthOut = responseLength;
9714 }
9715 }
9716
9717 finish:
9718
9719 /* Gather up the collected log messages for user space. Any messages
9720 * messages past this call will not make it up as log messages but
9721 * will be in the system log. Note that we ignore the return of the
9722 * serialize; it has no bearing on the operation at hand even if we
9723 * fail to get the log messages.
9724 */
9725 logInfoArray = OSKext::clearUserSpaceLogFilter();
9726
9727 if (logInfoArray && logInfoOut && logInfoLengthOut) {
9728 (void)OSKext::serializeLogInfo(logInfoArray.get(),
9729 logInfoOut, logInfoLengthOut);
9730 }
9731
9732 IORecursiveLockUnlock(sKextLock);
9733
9734 return result;
9735 }
9736
9737 #if PRAGMA_MARK
9738 #pragma mark Linked Kext Collection Support
9739 #endif
9740
9741 static int
9742 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9743 {
9744 for (int i = 0; i < segCount; i++) {
9745 vm_offset_t segStart = segAddrs[i];
9746 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9747
9748 if (theAddr >= segStart && theAddr < segEnd) {
9749 return i;
9750 }
9751 }
9752 return -1;
9753 }
9754
9755 static void
9756 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
9757 kernel_segment_command_t *kextTextSeg,
9758 OSData *kaslrOffsets)
9759 {
9760 static const char *plk_segNames[] = {
9761 "__TEXT",
9762 "__TEXT_EXEC",
9763 "__DATA",
9764 "__DATA_CONST",
9765 "__LINKEDIT",
9766 "__PRELINK_TEXT",
9767 "__PLK_TEXT_EXEC",
9768 "__PRELINK_DATA",
9769 "__PLK_DATA_CONST",
9770 "__PLK_LLVM_COV",
9771 "__PLK_LINKEDIT",
9772 "__PRELINK_INFO"
9773 };
9774 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9775
9776 unsigned long plk_segSizes[num_plk_seg];
9777 vm_offset_t plk_segAddrs[num_plk_seg];
9778
9779 for (size_t i = 0; i < num_plk_seg; i++) {
9780 plk_segSizes[i] = 0;
9781 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9782 }
9783
9784 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9785
9786 int slidKextAddrCount = 0;
9787 int badSlideAddr = 0;
9788 int badSlideTarget = 0;
9789
9790 struct kaslrPackedOffsets {
9791 uint32_t count; /* number of offsets */
9792 uint32_t offsetsArray[]; /* offsets to slide */
9793 };
9794 const struct kaslrPackedOffsets *myOffsets = NULL;
9795 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9796
9797 for (uint32_t j = 0; j < myOffsets->count; j++) {
9798 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9799 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9800 int slideAddrSegIndex = -1;
9801 int addrToSlideSegIndex = -1;
9802
9803 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9804 if (slideAddrSegIndex >= 0) {
9805 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9806 if (addrToSlideSegIndex < 0) {
9807 badSlideTarget++;
9808 continue;
9809 }
9810 } else {
9811 badSlideAddr++;
9812 continue;
9813 }
9814
9815 slidKextAddrCount++;
9816 *slideAddr = ml_static_slide(*slideAddr);
9817 } // for ...
9818 }
9819
9820
9821
9822 /********************************************************************
9823 * addKextsFromKextCollection
9824 *
9825 * Input: MachO header of kext collection. The MachO is assumed to
9826 * have a section named 'info_seg_name,info_sect_name' that
9827 * contains a serialized XML info dictionary. This dictionary
9828 * contains a UUID, possibly a set of relocations (for older
9829 * kxld-built binaries), and an array of kext personalities.
9830 *
9831 ********************************************************************/
9832 bool
9833 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9834 OSDictionary *infoDict, const char *text_seg_name,
9835 OSData **kcUUID, kc_kind_t type)
9836 {
9837 bool result = false;
9838
9839 OSArray *kextArray = NULL; // do not release
9840 OSData *infoDictKCUUID = NULL; // do not release
9841 OSData *kaslrOffsets = NULL; // do not release
9842
9843 IORegistryEntry *registryRoot = NULL; // do not release
9844 OSSharedPtr<OSNumber> kcKextCount;
9845
9846 /* extract the KC UUID from the dictionary */
9847 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9848 if (infoDictKCUUID) {
9849 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9850 panic("kcUUID length is %d, expected %lu",
9851 infoDictKCUUID->getLength(), sizeof(uuid_t));
9852 }
9853 }
9854
9855 /* locate the array of kext dictionaries */
9856 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9857 if (!kextArray) {
9858 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9859 "The given KC has no kext info dictionaries");
9860 goto finish;
9861 }
9862
9863 /*
9864 * old-style KASLR offsets may be present in the info dictionary. If
9865 * we find them, use them and eventually slide them.
9866 */
9867 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9868
9869 /*
9870 * Before processing any kexts, locate the special kext bundle which
9871 * contains a list of kexts that we are to prevent from loading.
9872 */
9873 createExcludeListFromPrelinkInfo(kextArray);
9874
9875 /*
9876 * Create OSKext objects for each kext we find in the array of kext
9877 * info plist dictionaries.
9878 */
9879 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9880 OSDictionary *kextDict = NULL;
9881 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9882 if (!kextDict) {
9883 OSKextLog(/* kext */ NULL,
9884 kOSKextLogErrorLevel |
9885 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9886 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9887 continue;
9888 }
9889
9890 /*
9891 * Create the kext for the entry, then release it, because the
9892 * kext system keeps a reference around until the kext is
9893 * explicitly removed. Any creation/registration failures are
9894 * already logged for us.
9895 */
9896 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9897 }
9898
9899 /*
9900 * slide old-style kxld relocations
9901 * NOTE: this is still used on embedded KCs built with kcgen
9902 * TODO: Remove this once we use the new kext linker everywhere!
9903 */
9904 if (kaslrOffsets && vm_kernel_slide > 0) {
9905 kernel_segment_command_t *text_segment = NULL;
9906 text_segment = getsegbynamefromheader(mh, text_seg_name);
9907 if (!text_segment) {
9908 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9909 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9910 goto finish;
9911 }
9912
9913 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9914 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9915 setAllVMAttributes();
9916 }
9917
9918 /* Store the number of prelinked kexts in the registry so we can tell
9919 * when the system has been started from a prelinked kernel.
9920 */
9921 registryRoot = IORegistryEntry::getRegistryRoot();
9922 assert(registryRoot);
9923
9924 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
9925 assert(kcKextCount);
9926 if (kcKextCount) {
9927 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
9928 OSNumber *num;
9929 num = OSDynamicCast(OSNumber, prop.get());
9930 if (num) {
9931 kcKextCount->addValue(num->unsigned64BitValue());
9932 }
9933 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
9934 }
9935
9936 OSKextLog(/* kext */ NULL,
9937 kOSKextLogProgressLevel |
9938 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
9939 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9940 "%u prelinked kexts", infoDict->getCount());
9941
9942
9943 if (kcUUID && infoDictKCUUID) {
9944 *kcUUID = OSData::withData(infoDictKCUUID).detach();
9945 }
9946
9947 result = true;
9948
9949 finish:
9950 return result;
9951 }
9952
9953 bool
9954 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9955 OSDictionary *infoDict, const char *text_seg_name,
9956 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
9957 {
9958 OSData *result = NULL;
9959 bool success = addKextsFromKextCollection(mh,
9960 infoDict,
9961 text_seg_name,
9962 &result,
9963 type);
9964 if (success) {
9965 kcUUID.reset(result, OSNoRetain);
9966 }
9967 return success;
9968 }
9969
9970 static OSSharedPtr<OSObject> deferredAuxKCXML;
9971 bool
9972 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
9973 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
9974 {
9975 if (type != KCKindAuxiliary) {
9976 return false;
9977 }
9978
9979 kernel_mach_header_t *_mh;
9980 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
9981 if (!_mh || _mh != mh) {
9982 return false;
9983 }
9984
9985 if (deferredAuxKCXML) {
9986 /* only allow this to be called once */
9987 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9988 "An Aux KC has already been registered for deferred processing.");
9989 return false;
9990 }
9991
9992 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
9993 if (!infoDict) {
9994 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9995 "The Aux KC has info dictionary");
9996 return false;
9997 }
9998
9999 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
10000 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
10001 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
10002 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
10003 return false;
10004 }
10005
10006 /*
10007 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
10008 * sysctl can return the UUID to user space which will check this
10009 * value for errors.
10010 */
10011 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
10012 kcUUID->getLength());
10013 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
10014 auxkc_uuid_valid = TRUE;
10015
10016 deferredAuxKCXML = parsedXML;
10017
10018 return true;
10019 }
10020
10021 OSSharedPtr<OSObject>
10022 OSKext::consumeDeferredKextCollection(kc_kind_t type)
10023 {
10024 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
10025 return NULL;
10026 }
10027
10028 return os::move(deferredAuxKCXML);
10029 }
10030
10031 #if PRAGMA_MARK
10032 #pragma mark Profile-Guided-Optimization Support
10033 #endif
10034
10035 // #include <InstrProfiling.h>
10036 extern "C" {
10037 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10038 const char *DataEnd,
10039 const char *CountersBegin,
10040 const char *CountersEnd,
10041 const char *NamesBegin,
10042 const char *NamesEnd);
10043 int __llvm_profile_write_buffer_internal(char *Buffer,
10044 const char *DataBegin,
10045 const char *DataEnd,
10046 const char *CountersBegin,
10047 const char *CountersEnd,
10048 const char *NamesBegin,
10049 const char *NamesEnd);
10050 }
10051
10052
10053 static
10054 void
10055 OSKextPgoMetadataPut(char *pBuffer,
10056 size_t *position,
10057 size_t bufferSize,
10058 uint32_t *num_pairs,
10059 const char *key,
10060 const char *value)
10061 {
10062 size_t strlen_key = strlen(key);
10063 size_t strlen_value = strlen(value);
10064 size_t len = strlen(key) + 1 + strlen(value) + 1;
10065 char *pos = pBuffer + *position;
10066 *position += len;
10067 if (pBuffer && bufferSize && *position <= bufferSize) {
10068 memcpy(pos, key, strlen_key); pos += strlen_key;
10069 *(pos++) = '=';
10070 memcpy(pos, value, strlen_value); pos += strlen_value;
10071 *(pos++) = 0;
10072 if (num_pairs) {
10073 (*num_pairs)++;
10074 }
10075 }
10076 }
10077
10078
10079 static
10080 void
10081 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10082 {
10083 *position += strlen(key) + 1 + value_max + 1;
10084 }
10085
10086
10087 static
10088 void
10089 OSKextPgoMetadataPutAll(OSKext *kext,
10090 uuid_t instance_uuid,
10091 char *pBuffer,
10092 size_t *position,
10093 size_t bufferSize,
10094 uint32_t *num_pairs)
10095 {
10096 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10097 //log_10 2^16 ≈ 4.82
10098 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10099 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10100
10101 if (!pBuffer) {
10102 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10103 OSKextPgoMetadataPutMax(position, "UUID", 36);
10104 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10105 } else {
10106 uuid_string_t instance_uuid_string;
10107 uuid_unparse(instance_uuid, instance_uuid_string);
10108 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10109 "INSTANCE", instance_uuid_string);
10110
10111 OSSharedPtr<OSData> uuid_data;
10112 uuid_t uuid;
10113 uuid_string_t uuid_string;
10114 uuid_data = kext->copyUUID();
10115 if (uuid_data) {
10116 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10117 uuid_unparse(uuid, uuid_string);
10118 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10119 "UUID", uuid_string);
10120 }
10121
10122 clock_sec_t secs;
10123 clock_usec_t usecs;
10124 clock_get_calendar_microtime(&secs, &usecs);
10125 assert(usecs < 1000000);
10126 char timestamp[max_timestamp_string_size + 1];
10127 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10128 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10129 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10130 "TIMESTAMP", timestamp);
10131 }
10132
10133 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10134 "NAME", kext->getIdentifierCString());
10135
10136 char versionCString[kOSKextVersionMaxLength];
10137 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10138 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10139 "VERSION", versionCString);
10140 }
10141
10142 static
10143 size_t
10144 OSKextPgoMetadataSize(OSKext *kext)
10145 {
10146 size_t position = 0;
10147 uuid_t fakeuuid = {};
10148 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10149 return position;
10150 }
10151
10152 int
10153 OSKextGrabPgoDataLocked(OSKext *kext,
10154 bool metadata,
10155 uuid_t instance_uuid,
10156 uint64_t *pSize,
10157 char *pBuffer,
10158 uint64_t bufferSize)
10159 {
10160 int err = 0;
10161
10162 kernel_section_t *sect_prf_data = NULL;
10163 kernel_section_t *sect_prf_name = NULL;
10164 kernel_section_t *sect_prf_cnts = NULL;
10165 uint64_t size;
10166 size_t metadata_size = 0;
10167 size_t offset_to_pairs = 0;
10168
10169 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10170 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10171 if (!sect_prf_name) {
10172 // kextcache sometimes truncates the section name to 15 chars
10173 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10174 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10175 }
10176 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10177
10178 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10179 err = ENOTSUP;
10180 goto out;
10181 }
10182
10183 size = __llvm_profile_get_size_for_buffer_internal(
10184 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10185 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10186 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10187
10188 if (metadata) {
10189 metadata_size = OSKextPgoMetadataSize(kext);
10190 size += metadata_size;
10191 size += sizeof(pgo_metadata_footer);
10192 }
10193
10194
10195 if (pSize) {
10196 *pSize = size;
10197 }
10198
10199 if (pBuffer && bufferSize) {
10200 if (bufferSize < size) {
10201 err = ERANGE;
10202 goto out;
10203 }
10204
10205 err = __llvm_profile_write_buffer_internal(
10206 pBuffer,
10207 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10208 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10209 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10210
10211 if (err) {
10212 err = EIO;
10213 goto out;
10214 }
10215
10216 if (metadata) {
10217 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10218 if (offset_to_pairs > UINT32_MAX) {
10219 err = E2BIG;
10220 goto out;
10221 }
10222
10223 char *end_of_buffer = pBuffer + size;
10224 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10225 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10226
10227 size_t metadata_position = 0;
10228 uint32_t num_pairs = 0;
10229 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10230 while (metadata_position < metadata_size) {
10231 metadata_buffer[metadata_position++] = 0;
10232 }
10233
10234 struct pgo_metadata_footer footer;
10235 footer.magic = htonl(0x6d657461);
10236 footer.number_of_pairs = htonl( num_pairs );
10237 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
10238 memcpy(footerp, &footer, sizeof(footer));
10239 }
10240 }
10241
10242 out:
10243 return err;
10244 }
10245
10246
10247 int
10248 OSKextGrabPgoData(uuid_t uuid,
10249 uint64_t *pSize,
10250 char *pBuffer,
10251 uint64_t bufferSize,
10252 int wait_for_unload,
10253 int metadata)
10254 {
10255 int err = 0;
10256 OSSharedPtr<OSKext> kext;
10257
10258
10259 IORecursiveLockLock(sKextLock);
10260
10261 kext = OSKext::lookupKextWithUUID(uuid);
10262 if (!kext) {
10263 err = ENOENT;
10264 goto out;
10265 }
10266
10267 if (wait_for_unload) {
10268 OSKextGrabPgoStruct s;
10269
10270 s.metadata = metadata;
10271 s.pSize = pSize;
10272 s.pBuffer = pBuffer;
10273 s.bufferSize = bufferSize;
10274 s.err = EINTR;
10275
10276 struct list_head *prev = &kext->pendingPgoHead;
10277 struct list_head *next = kext->pendingPgoHead.next;
10278
10279 s.list_head.prev = prev;
10280 s.list_head.next = next;
10281
10282 prev->next = &s.list_head;
10283 next->prev = &s.list_head;
10284
10285 kext.reset();
10286
10287 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
10288
10289 prev = s.list_head.prev;
10290 next = s.list_head.next;
10291
10292 prev->next = next;
10293 next->prev = prev;
10294
10295 err = s.err;
10296 } else {
10297 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
10298 }
10299
10300 out:
10301
10302 IORecursiveLockUnlock(sKextLock);
10303
10304 return err;
10305 }
10306
10307 void
10308 OSKextResetPgoCountersLock()
10309 {
10310 IORecursiveLockLock(sKextLock);
10311 }
10312
10313 void
10314 OSKextResetPgoCountersUnlock()
10315 {
10316 IORecursiveLockUnlock(sKextLock);
10317 }
10318
10319
10320 extern unsigned int not_in_kdp;
10321
10322 void
10323 OSKextResetPgoCounters()
10324 {
10325 assert(!not_in_kdp);
10326 uint32_t count = sLoadedKexts->getCount();
10327 for (uint32_t i = 0; i < count; i++) {
10328 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10329 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10330 if (!sect_prf_cnts) {
10331 continue;
10332 }
10333 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10334 }
10335 }
10336
10337 OSSharedPtr<OSDictionary>
10338 OSKext::copyLoadedKextInfoByUUID(
10339 OSArray * kextIdentifiers,
10340 OSArray * infoKeys)
10341 {
10342 OSSharedPtr<OSDictionary> result;
10343 OSSharedPtr<OSDictionary> kextInfo;
10344 uint32_t max_count, i, j;
10345 uint32_t idCount = 0;
10346 uint32_t idIndex = 0;
10347 IORecursiveLockLock(sKextLock);
10348 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
10349 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
10350
10351 #if CONFIG_MACF
10352 /* Is the calling process allowed to query kext info? */
10353 if (current_task() != kernel_task) {
10354 int macCheckResult = 0;
10355 kauth_cred_t cred = NULL;
10356
10357 cred = kauth_cred_get_with_ref();
10358 macCheckResult = mac_kext_check_query(cred);
10359 kauth_cred_unref(&cred);
10360
10361 if (macCheckResult != 0) {
10362 OSKextLog(/* kext */ NULL,
10363 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10364 "Failed to query kext info (MAC policy error 0x%x).",
10365 macCheckResult);
10366 goto finish;
10367 }
10368 }
10369 #endif
10370
10371 /* Empty list of UUIDs is equivalent to no list (get all).
10372 */
10373 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10374 kextIdentifiers = NULL;
10375 } else if (kextIdentifiers) {
10376 idCount = kextIdentifiers->getCount();
10377 }
10378
10379 /* Same for keys.
10380 */
10381 if (infoKeys && !infoKeys->getCount()) {
10382 infoKeys = NULL;
10383 }
10384
10385 max_count = count[0] + count[1];
10386 result = OSDictionary::withCapacity(max_count);
10387 if (!result) {
10388 goto finish;
10389 }
10390
10391 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10392 for (i = 0; i < count[j]; i++) {
10393 OSKext *thisKext = NULL; // do not release
10394 Boolean includeThis = true;
10395 uuid_t thisKextUUID;
10396 uuid_t thisKextTextUUID;
10397 OSSharedPtr<OSData> uuid_data;
10398 uuid_string_t uuid_key;
10399
10400 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10401 if (!thisKext) {
10402 continue;
10403 }
10404
10405 uuid_data = thisKext->copyUUID();
10406 if (!uuid_data) {
10407 continue;
10408 }
10409
10410 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
10411
10412 uuid_unparse(thisKextUUID, uuid_key);
10413
10414 uuid_data = thisKext->copyTextUUID();
10415 if (!uuid_data) {
10416 continue;
10417 }
10418 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
10419
10420 /* Skip current kext if we have a list of UUIDs and
10421 * it isn't in the list.
10422 */
10423 if (kextIdentifiers) {
10424 includeThis = false;
10425
10426 for (idIndex = 0; idIndex < idCount; idIndex++) {
10427 const OSString* wantedUUID = OSDynamicCast(OSString,
10428 kextIdentifiers->getObject(idIndex));
10429
10430 uuid_t uuid;
10431 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10432
10433 if ((0 == uuid_compare(uuid, thisKextUUID))
10434 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10435 includeThis = true;
10436 /* Only need to find the first kext if multiple match,
10437 * ie. asking for the kernel uuid does not need to find
10438 * interface kexts or builtin static kexts.
10439 */
10440 kextIdentifiers->removeObject(idIndex);
10441 uuid_unparse(uuid, uuid_key);
10442 break;
10443 }
10444 }
10445 }
10446
10447 if (!includeThis) {
10448 continue;
10449 }
10450
10451 kextInfo = thisKext->copyInfo(infoKeys);
10452 if (kextInfo) {
10453 result->setObject(uuid_key, kextInfo.get());
10454 }
10455
10456 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10457 goto finish;
10458 }
10459 }
10460 }
10461
10462 finish:
10463 IORecursiveLockUnlock(sKextLock);
10464
10465 return result;
10466 }
10467
10468 /*********************************************************************
10469 *********************************************************************/
10470 /* static */
10471 OSSharedPtr<OSDictionary>
10472 OSKext::copyKextCollectionInfo(
10473 OSDictionary *requestDict,
10474 OSArray *infoKeys)
10475 {
10476 OSSharedPtr<OSDictionary> result;
10477 OSString *collectionType = NULL;
10478 OSObject *rawLoadedState = NULL;
10479 OSString *loadedState = NULL;
10480
10481 kc_kind_t kc_request_kind = KCKindUnknown;
10482 bool onlyLoaded = false;
10483 bool onlyUnloaded = false;
10484
10485 #if CONFIG_MACF
10486 /* Is the calling process allowed to query kext info? */
10487 if (current_task() != kernel_task) {
10488 int macCheckResult = 0;
10489 kauth_cred_t cred = NULL;
10490
10491 cred = kauth_cred_get_with_ref();
10492 macCheckResult = mac_kext_check_query(cred);
10493 kauth_cred_unref(&cred);
10494
10495 if (macCheckResult != 0) {
10496 OSKextLog(/* kext */ NULL,
10497 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10498 "Failed to query kext info (MAC policy error 0x%x).",
10499 macCheckResult);
10500 goto finish;
10501 }
10502 }
10503 #endif
10504
10505 if (infoKeys && !infoKeys->getCount()) {
10506 infoKeys = NULL;
10507 }
10508
10509 collectionType = OSDynamicCast(OSString,
10510 _OSKextGetRequestArgument(requestDict,
10511 kKextRequestArgumentCollectionTypeKey));
10512 if (!collectionType) {
10513 OSKextLog(/* kext */ NULL,
10514 kOSKextLogErrorLevel |
10515 kOSKextLogIPCFlag,
10516 "Invalid '%s' argument to kext collection info request.",
10517 kKextRequestArgumentCollectionTypeKey);
10518 goto finish;
10519 }
10520 if (collectionType->isEqualTo(kKCTypePrimary)) {
10521 kc_request_kind = KCKindPrimary;
10522 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10523 kc_request_kind = KCKindPageable;
10524 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10525 kc_request_kind = KCKindAuxiliary;
10526 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10527 kc_request_kind = KCKindNone;
10528 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10529 OSKextLog(/* kext */ NULL,
10530 kOSKextLogErrorLevel |
10531 kOSKextLogIPCFlag,
10532 "Invalid '%s' argument value '%s' to kext collection info request.",
10533 kKextRequestArgumentCollectionTypeKey,
10534 collectionType->getCStringNoCopy());
10535 goto finish;
10536 }
10537
10538 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10539 kKextRequestArgumentLoadedStateKey);
10540 if (rawLoadedState) {
10541 loadedState = OSDynamicCast(OSString, rawLoadedState);
10542 if (!loadedState) {
10543 OSKextLog(/* kext */ NULL,
10544 kOSKextLogErrorLevel |
10545 kOSKextLogIPCFlag,
10546 "Invalid '%s' argument to kext collection info request.",
10547 kKextRequestArgumentLoadedStateKey);
10548 goto finish;
10549 }
10550 }
10551 if (loadedState) {
10552 if (loadedState->isEqualTo("Loaded")) {
10553 onlyLoaded = true;
10554 } else if (loadedState->isEqualTo("Unloaded")) {
10555 onlyUnloaded = true;
10556 } else if (!loadedState->isEqualTo("Any")) {
10557 OSKextLog(/* kext */ NULL,
10558 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10559 "Invalid '%s' argument value '%s' for '%s' collection info",
10560 kKextRequestArgumentLoadedStateKey,
10561 loadedState->getCStringNoCopy(),
10562 collectionType->getCStringNoCopy());
10563 goto finish;
10564 }
10565 }
10566
10567 result = OSDictionary::withCapacity(sKextsByID->getCount());
10568 if (!result) {
10569 goto finish;
10570 }
10571
10572 IORecursiveLockLock(sKextLock);
10573 { // start block scope
10574 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10575 {
10576 OSKext *thisKext = NULL; // do not release
10577 OSSharedPtr<OSDictionary> kextInfo;
10578
10579 (void)thisKextID;
10580
10581 thisKext = OSDynamicCast(OSKext, obj);
10582 if (!thisKext) {
10583 return false;;
10584 }
10585
10586 /*
10587 * skip the kext if it came from the wrong collection type
10588 * (and the caller requested a specific type)
10589 */
10590 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10591 return false;
10592 }
10593
10594 /*
10595 * respect the caller's desire to find only loaded or
10596 * unloaded kexts
10597 */
10598 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10599 return false;
10600 }
10601 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10602 return false;
10603 }
10604
10605 kextInfo = thisKext->copyInfo(infoKeys);
10606 if (kextInfo) {
10607 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10608 }
10609 return false;
10610 });
10611 } // end block scope
10612 IORecursiveLockUnlock(sKextLock);
10613
10614 finish:
10615 return result;
10616 }
10617
10618 /*********************************************************************
10619 *********************************************************************/
10620 /* static */
10621 OSSharedPtr<OSDictionary>
10622 OSKext::copyLoadedKextInfo(
10623 OSArray * kextIdentifiers,
10624 OSArray * infoKeys)
10625 {
10626 OSSharedPtr<OSDictionary> result;
10627 uint32_t idCount = 0;
10628 bool onlyLoaded;
10629
10630 IORecursiveLockLock(sKextLock);
10631
10632 #if CONFIG_MACF
10633 /* Is the calling process allowed to query kext info? */
10634 if (current_task() != kernel_task) {
10635 int macCheckResult = 0;
10636 kauth_cred_t cred = NULL;
10637
10638 cred = kauth_cred_get_with_ref();
10639 macCheckResult = mac_kext_check_query(cred);
10640 kauth_cred_unref(&cred);
10641
10642 if (macCheckResult != 0) {
10643 OSKextLog(/* kext */ NULL,
10644 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10645 "Failed to query kext info (MAC policy error 0x%x).",
10646 macCheckResult);
10647 goto finish;
10648 }
10649 }
10650 #endif
10651
10652 /* Empty list of bundle ids is equivalent to no list (get all).
10653 */
10654 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10655 kextIdentifiers = NULL;
10656 } else if (kextIdentifiers) {
10657 idCount = kextIdentifiers->getCount();
10658 }
10659
10660 /* Same for keys.
10661 */
10662 if (infoKeys && !infoKeys->getCount()) {
10663 infoKeys = NULL;
10664 }
10665
10666 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10667
10668 result = OSDictionary::withCapacity(128);
10669 if (!result) {
10670 goto finish;
10671 }
10672
10673 #if 0
10674 OSKextLog(/* kext */ NULL,
10675 kOSKextLogErrorLevel |
10676 kOSKextLogGeneralFlag,
10677 "kaslr: vm_kernel_slide 0x%lx \n",
10678 vm_kernel_slide);
10679 OSKextLog(/* kext */ NULL,
10680 kOSKextLogErrorLevel |
10681 kOSKextLogGeneralFlag,
10682 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10683 vm_kernel_stext, vm_kernel_etext);
10684 OSKextLog(/* kext */ NULL,
10685 kOSKextLogErrorLevel |
10686 kOSKextLogGeneralFlag,
10687 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10688 vm_kernel_base, vm_kernel_top);
10689 OSKextLog(/* kext */ NULL,
10690 kOSKextLogErrorLevel |
10691 kOSKextLogGeneralFlag,
10692 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10693 vm_kext_base, vm_kext_top);
10694 OSKextLog(/* kext */ NULL,
10695 kOSKextLogErrorLevel |
10696 kOSKextLogGeneralFlag,
10697 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10698 vm_prelink_stext, vm_prelink_etext);
10699 OSKextLog(/* kext */ NULL,
10700 kOSKextLogErrorLevel |
10701 kOSKextLogGeneralFlag,
10702 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10703 vm_prelink_sinfo, vm_prelink_einfo);
10704 OSKextLog(/* kext */ NULL,
10705 kOSKextLogErrorLevel |
10706 kOSKextLogGeneralFlag,
10707 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10708 vm_slinkedit, vm_elinkedit);
10709 #endif
10710 { // start block scope
10711 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10712 {
10713 OSKext * thisKext = NULL; // do not release
10714 Boolean includeThis = true;
10715 OSSharedPtr<OSDictionary> kextInfo;
10716
10717 thisKext = OSDynamicCast(OSKext, obj);
10718 if (!thisKext) {
10719 return false;;
10720 }
10721
10722 /* Skip current kext if not yet started and caller didn't request all.
10723 */
10724 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10725 return false;;
10726 }
10727
10728 /* Skip current kext if we have a list of bundle IDs and
10729 * it isn't in the list.
10730 */
10731 if (kextIdentifiers) {
10732 includeThis = false;
10733
10734 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10735 const OSString * thisRequestID = OSDynamicCast(OSString,
10736 kextIdentifiers->getObject(idIndex));
10737 if (thisKextID->isEqualTo(thisRequestID)) {
10738 includeThis = true;
10739 break;
10740 }
10741 }
10742 }
10743
10744 if (!includeThis) {
10745 return false;
10746 }
10747
10748 kextInfo = thisKext->copyInfo(infoKeys);
10749 if (kextInfo) {
10750 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10751 }
10752 return false;
10753 });
10754 } // end block scope
10755
10756 finish:
10757 IORecursiveLockUnlock(sKextLock);
10758
10759 return result;
10760 }
10761
10762 /*********************************************************************
10763 * Any info that needs to do allocations must goto finish on alloc
10764 * failure. Info that is just a lookup should just not set the object
10765 * if the info does not exist.
10766 *********************************************************************/
10767 #define _OSKextLoadInfoDictCapacity (12)
10768
10769 OSSharedPtr<OSDictionary>
10770 OSKext::copyInfo(OSArray * infoKeys)
10771 {
10772 OSSharedPtr<OSDictionary> result;
10773 bool success = false;
10774 OSSharedPtr<OSData> headerData;
10775 OSSharedPtr<OSData> logData;
10776 OSSharedPtr<OSNumber> cpuTypeNumber;
10777 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10778 OSString * versionString = NULL; // do not release
10779 OSString * bundleType = NULL; // do not release
10780 uint32_t executablePathCStringSize = 0;
10781 char * executablePathCString = NULL; // must kfree
10782 OSSharedPtr<OSString> executablePathString;
10783 OSSharedPtr<OSData> uuid;
10784 OSSharedPtr<OSArray> dependencyLoadTags;
10785 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10786 OSSharedPtr<OSArray> metaClassInfo;
10787 OSSharedPtr<OSDictionary> metaClassDict;
10788 OSMetaClass * thisMetaClass = NULL; // do not release
10789 OSSharedPtr<OSString> metaClassName;
10790 OSSharedPtr<OSString> superclassName;
10791 kc_format_t kcformat;
10792 uint32_t count, i;
10793
10794 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10795 if (!result) {
10796 goto finish;
10797 }
10798
10799
10800 /* Empty keys means no keys, but NULL is quicker to check.
10801 */
10802 if (infoKeys && !infoKeys->getCount()) {
10803 infoKeys = NULL;
10804 }
10805
10806 if (!PE_get_primary_kc_format(&kcformat)) {
10807 goto finish;
10808 }
10809
10810 /* Headers, CPU type, and CPU subtype.
10811 */
10812 if (!infoKeys ||
10813 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10814 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10815 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10816 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10817 if (linkedExecutable && !isInterface()) {
10818 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10819 linkedExecutable->getBytesNoCopy();
10820
10821 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10822 // do not return macho header info on shipping embedded - 19095897
10823 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10824 kernel_mach_header_t * temp_kext_mach_hdr;
10825 struct load_command * lcp;
10826
10827 headerData = OSData::withBytes(kext_mach_hdr,
10828 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10829 if (!headerData) {
10830 goto finish;
10831 }
10832
10833 // unslide any vmaddrs we return to userspace - 10726716
10834 temp_kext_mach_hdr = (kernel_mach_header_t *)
10835 headerData->getBytesNoCopy();
10836 if (temp_kext_mach_hdr == NULL) {
10837 goto finish;
10838 }
10839
10840 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10841 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10842 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10843 kernel_segment_command_t * segp;
10844 kernel_section_t * secp;
10845
10846 segp = (kernel_segment_command_t *) lcp;
10847 // 10543468 - if we jettisoned __LINKEDIT clear size info
10848 if (flags.jettisonLinkeditSeg) {
10849 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10850 segp->vmsize = 0;
10851 segp->fileoff = 0;
10852 segp->filesize = 0;
10853 }
10854 }
10855
10856 #if __arm__ || __arm64__
10857 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10858 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10859 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10860 segp->vmaddr = gVirtBase;
10861 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10862 secp->size = 0; // paranoia :)
10863 secp->addr = gVirtBase;
10864 }
10865 }
10866 #endif
10867
10868 #if 0
10869 OSKextLog(/* kext */ NULL,
10870 kOSKextLogErrorLevel |
10871 kOSKextLogGeneralFlag,
10872 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10873 __FUNCTION__, segp->segname, segp->vmaddr,
10874 VM_KERNEL_UNSLIDE(segp->vmaddr),
10875 segp->vmsize, segp->nsects);
10876 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10877 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10878 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10879 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10880 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10881 OSKextLog(/* kext */ NULL,
10882 kOSKextLogErrorLevel |
10883 kOSKextLogGeneralFlag,
10884 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10885 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10886 }
10887 #endif
10888 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10889
10890 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10891 secp->addr = ml_static_unslide(secp->addr);
10892 }
10893 }
10894 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10895 }
10896 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
10897 }
10898 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10899
10900 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10901 osLogDataHeaderRef *header;
10902 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10903
10904 void *os_log_data = NULL;
10905 void *cstring_data = NULL;
10906 unsigned long os_log_size = 0;
10907 unsigned long cstring_size = 0;
10908 uint32_t os_log_offset = 0;
10909 uint32_t cstring_offset = 0;
10910 bool res;
10911
10912 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
10913 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
10914 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
10915 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
10916
10917 header = (osLogDataHeaderRef *) headerBytes;
10918 header->version = OS_LOG_HDR_VERSION;
10919 header->sect_count = NUM_OS_LOG_SECTIONS;
10920 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
10921 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
10922 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
10923 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
10924
10925
10926 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10927 if (!logData) {
10928 goto finish;
10929 }
10930 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10931 if (!res) {
10932 goto finish;
10933 }
10934 if (os_log_data) {
10935 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
10936 if (!res) {
10937 goto finish;
10938 }
10939 }
10940 if (cstring_data) {
10941 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
10942 if (!res) {
10943 goto finish;
10944 }
10945 }
10946 result->setObject(kOSBundleLogStringsKey, logData.get());
10947 }
10948
10949 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
10950 cpuTypeNumber = OSNumber::withNumber(
10951 (uint64_t) kext_mach_hdr->cputype,
10952 8 * sizeof(kext_mach_hdr->cputype));
10953 if (!cpuTypeNumber) {
10954 goto finish;
10955 }
10956 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
10957 }
10958
10959 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10960 cpuSubtypeNumber = OSNumber::withNumber(
10961 (uint64_t) kext_mach_hdr->cpusubtype,
10962 8 * sizeof(kext_mach_hdr->cpusubtype));
10963 if (!cpuSubtypeNumber) {
10964 goto finish;
10965 }
10966 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
10967 }
10968 } else {
10969 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10970 osLogDataHeaderRef *header;
10971 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10972 bool res;
10973
10974 header = (osLogDataHeaderRef *) headerBytes;
10975 header->version = OS_LOG_HDR_VERSION;
10976 header->sect_count = NUM_OS_LOG_SECTIONS;
10977 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
10978 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
10979 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
10980 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
10981
10982 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10983 if (!logData) {
10984 goto finish;
10985 }
10986 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10987 if (!res) {
10988 goto finish;
10989 }
10990 result->setObject(kOSBundleLogStringsKey, logData.get());
10991 }
10992 }
10993 }
10994
10995 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10996 */
10997 result->setObject(kCFBundleIdentifierKey, bundleID.get());
10998
10999 /* CFBundlePackageType
11000 */
11001 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
11002 if (bundleType) {
11003 result->setObject(kCFBundlePackageTypeKey, bundleType);
11004 }
11005
11006 /* CFBundleVersion.
11007 */
11008 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
11009 versionString = OSDynamicCast(OSString,
11010 getPropertyForHostArch(kCFBundleVersionKey));
11011 if (versionString) {
11012 result->setObject(kCFBundleVersionKey, versionString);
11013 }
11014 }
11015
11016 /* OSBundleCompatibleVersion.
11017 */
11018 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
11019 versionString = OSDynamicCast(OSString,
11020 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
11021 if (versionString) {
11022 result->setObject(kOSBundleCompatibleVersionKey, versionString);
11023 }
11024 }
11025
11026 /* Path.
11027 */
11028 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
11029 if (path) {
11030 result->setObject(kOSBundlePathKey, path.get());
11031 }
11032 }
11033
11034
11035 /* OSBundleExecutablePath.
11036 */
11037 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
11038 if (path && executableRelPath) {
11039 uint32_t pathLength = path->getLength(); // gets incremented below
11040
11041 // +1 for slash, +1 for \0
11042 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11043
11044 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11045 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
11046 if (!executablePathCString) {
11047 goto finish;
11048 }
11049 strlcpy(executablePathCString, path->getCStringNoCopy(),
11050 executablePathCStringSize);
11051 executablePathCString[pathLength++] = '/';
11052 executablePathCString[pathLength++] = '\0';
11053 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11054 executablePathCStringSize);
11055
11056 executablePathString = OSString::withCString(executablePathCString);
11057
11058 if (!executablePathString) {
11059 goto finish;
11060 }
11061
11062 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11063 } else if (flags.builtin) {
11064 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
11065 } else if (isDriverKit()) {
11066 if (path) {
11067 // +1 for slash, +1 for \0
11068 uint32_t pathLength = path->getLength();
11069 executablePathCStringSize = pathLength + 2;
11070
11071 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11072 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
11073 if (!executablePathCString) {
11074 goto finish;
11075 }
11076 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11077 executablePathCString[pathLength++] = '/';
11078 executablePathCString[pathLength++] = '\0';
11079
11080 executablePathString = OSString::withCString(executablePathCString);
11081
11082 if (!executablePathString) {
11083 goto finish;
11084 }
11085
11086 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11087 }
11088 }
11089 }
11090
11091 /* UUID, if the kext has one.
11092 */
11093 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11094 uuid = copyUUID();
11095 if (uuid) {
11096 result->setObject(kOSBundleUUIDKey, uuid.get());
11097 }
11098 }
11099 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11100 uuid = copyTextUUID();
11101 if (uuid) {
11102 result->setObject(kOSBundleTextUUIDKey, uuid.get());
11103 }
11104 }
11105
11106 /*
11107 * Info.plist digest
11108 */
11109 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11110 OSData *digest;
11111 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11112 if (digest) {
11113 result->setObject(kOSKextInfoPlistDigestKey, digest);
11114 }
11115 }
11116
11117 /*
11118 * Collection type
11119 */
11120 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11121 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
11122 }
11123
11124 /*
11125 * Collection availability
11126 */
11127 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11128 result->setObject(kOSKextAuxKCAvailabilityKey,
11129 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11130 }
11131
11132 /*
11133 * Allows user load
11134 */
11135 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11136 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11137 if (allowUserLoad) {
11138 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11139 }
11140 }
11141
11142 /*
11143 * Bundle Dependencies (OSBundleLibraries)
11144 */
11145 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11146 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11147 if (libraries) {
11148 result->setObject(kOSBundleLibrariesKey, libraries);
11149 }
11150 }
11151
11152 /*****
11153 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11154 */
11155 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11156 result->setObject(kOSKernelResourceKey,
11157 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11158 }
11159
11160 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11161 result->setObject(kOSBundleIsInterfaceKey,
11162 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11163 }
11164
11165 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11166 result->setObject(kOSBundlePrelinkedKey,
11167 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
11168 }
11169
11170 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11171 result->setObject(kOSBundleStartedKey,
11172 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11173 }
11174
11175 /* LoadTag (Index).
11176 */
11177 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
11178 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
11179 /* numBits */ 8 * sizeof(loadTag));
11180 if (!scratchNumber) {
11181 goto finish;
11182 }
11183 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
11184 }
11185
11186 /* LoadAddress, LoadSize.
11187 */
11188 if (!infoKeys ||
11189 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11190 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11191 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11192 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11193 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11194 bool is_dext = isDriverKit();
11195 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
11196 /* These go to userspace via serialization, so we don't want any doubts
11197 * about their size.
11198 */
11199 uint64_t loadAddress = 0;
11200 uint32_t loadSize = 0;
11201 uint32_t wiredSize = 0;
11202 uint64_t execLoadAddress = 0;
11203 uint32_t execLoadSize = 0;
11204
11205 /* Interfaces always report 0 load address & size.
11206 * Just the way they roll.
11207 *
11208 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11209 * xxx - shouldn't have one!
11210 */
11211
11212 if (flags.builtin || linkedExecutable) {
11213 kernel_mach_header_t *mh = NULL;
11214 kernel_segment_command_t *seg = NULL;
11215
11216 if (flags.builtin) {
11217 loadAddress = kmod_info->address;
11218 loadSize = (uint32_t)kmod_info->size;
11219 } else {
11220 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11221 loadSize = linkedExecutable->getLength();
11222 }
11223 mh = (kernel_mach_header_t *)loadAddress;
11224 loadAddress = ml_static_unslide(loadAddress);
11225
11226 /* Walk through the kext, looking for the first executable
11227 * segment in case we were asked for its size/address.
11228 */
11229 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11230 if (seg->initprot & VM_PROT_EXECUTE) {
11231 execLoadAddress = ml_static_unslide(seg->vmaddr);
11232 execLoadSize = (uint32_t)seg->vmsize;
11233 break;
11234 }
11235 }
11236
11237 /* If we have a kmod_info struct, calculated the wired size
11238 * from that. Otherwise it's the full load size.
11239 */
11240 if (kmod_info) {
11241 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
11242 } else {
11243 wiredSize = loadSize;
11244 }
11245 } else if (is_dext) {
11246 /*
11247 * DriverKit userspace executables do not have a kernel linkedExecutable,
11248 * so we "fake" their address range with the LoadTag.
11249 */
11250 if (loadTag) {
11251 loadAddress = execLoadAddress = loadTag;
11252 loadSize = execLoadSize = 1;
11253 }
11254 }
11255
11256 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
11257 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11258 (unsigned long long)(loadAddress),
11259 /* numBits */ 8 * sizeof(loadAddress));
11260 if (!scratchNumber) {
11261 goto finish;
11262 }
11263 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
11264 }
11265 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11266 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11267 && loadAddress && loadSize) {
11268 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11269 if (!baseAddress) {
11270 goto finish;
11271 }
11272
11273 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11274 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11275 /* numBits */ 8 * sizeof(loadAddress));
11276 if (!scratchNumber) {
11277 goto finish;
11278 }
11279 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11280 }
11281 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11282 && (this == sKernelKext) && gBuiltinKmodsCount) {
11283 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
11284 }
11285 }
11286
11287 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
11288 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11289 (unsigned long long)(execLoadAddress),
11290 /* numBits */ 8 * sizeof(execLoadAddress));
11291 if (!scratchNumber) {
11292 goto finish;
11293 }
11294 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
11295 }
11296 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
11297 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11298 (unsigned long long)(loadSize),
11299 /* numBits */ 8 * sizeof(loadSize));
11300 if (!scratchNumber) {
11301 goto finish;
11302 }
11303 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
11304 }
11305 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
11306 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11307 (unsigned long long)(execLoadSize),
11308 /* numBits */ 8 * sizeof(execLoadSize));
11309 if (!scratchNumber) {
11310 goto finish;
11311 }
11312 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
11313 }
11314 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11315 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11316 (unsigned long long)(wiredSize),
11317 /* numBits */ 8 * sizeof(wiredSize));
11318 if (!scratchNumber) {
11319 goto finish;
11320 }
11321 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
11322 }
11323 }
11324 }
11325
11326 /* OSBundleDependencies. In descending order for
11327 * easy compatibility with kextstat(8).
11328 */
11329 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11330 if ((count = getNumDependencies())) {
11331 dependencyLoadTags = OSArray::withCapacity(count);
11332 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
11333
11334 i = count - 1;
11335 do {
11336 OSKext * dependency = OSDynamicCast(OSKext,
11337 dependencies->getObject(i));
11338
11339 if (!dependency) {
11340 continue;
11341 }
11342 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11343 (unsigned long long)dependency->getLoadTag(),
11344 /* numBits*/ 8 * sizeof(loadTag));
11345 if (!scratchNumber) {
11346 goto finish;
11347 }
11348 dependencyLoadTags->setObject(scratchNumber.get());
11349 } while (i--);
11350 }
11351 }
11352
11353 /* OSBundleMetaClasses.
11354 */
11355 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11356 if (metaClasses && metaClasses->getCount()) {
11357 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
11358 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11359 if (!metaClassIterator || !metaClassInfo) {
11360 goto finish;
11361 }
11362 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
11363
11364 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11365 metaClassIterator->getNextObject()))) {
11366 metaClassDict = OSDictionary::withCapacity(3);
11367 if (!metaClassDict) {
11368 goto finish;
11369 }
11370
11371 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11372 if (thisMetaClass->getSuperClass()) {
11373 superclassName = OSString::withCString(
11374 thisMetaClass->getSuperClass()->getClassName());
11375 }
11376 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
11377 8 * sizeof(unsigned int));
11378
11379 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11380 * of course.
11381 */
11382 if (!metaClassDict || !metaClassName || !scratchNumber) {
11383 goto finish;
11384 }
11385
11386 metaClassInfo->setObject(metaClassDict.get());
11387 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
11388 if (superclassName) {
11389 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
11390 }
11391 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
11392 }
11393 }
11394 }
11395
11396 /* OSBundleRetainCount.
11397 */
11398 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
11399 {
11400 int kextRetainCount = getRetainCount() - 1;
11401 if (isLoaded()) {
11402 kextRetainCount--;
11403 }
11404 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11405 (int)kextRetainCount,
11406 /* numBits*/ 8 * sizeof(int));
11407 if (scratchNumber) {
11408 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
11409 }
11410 }
11411 }
11412
11413 success = true;
11414
11415 finish:
11416 if (executablePathCString) {
11417 kheap_free(KHEAP_TEMP, executablePathCString, executablePathCStringSize);
11418 }
11419 if (!success) {
11420 result.reset();
11421 }
11422 return result;
11423 }
11424
11425 /*********************************************************************
11426 *********************************************************************/
11427 /* static */
11428 bool
11429 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11430 {
11431 bool ok;
11432 OSSharedPtr<OSKext> kext;
11433
11434 IORecursiveLockLock(sKextLock);
11435 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
11436 IORecursiveLockUnlock(sKextLock);
11437
11438 if (!kext || !kext->path || !kext->userExecutableRelPath) {
11439 return false;
11440 }
11441 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11442 kext->path->getCStringNoCopy(),
11443 kext->userExecutableRelPath->getCStringNoCopy());
11444 ok = true;
11445
11446 return ok;
11447 }
11448
11449 /*********************************************************************
11450 *********************************************************************/
11451 /* static */
11452 OSReturn
11453 OSKext::requestResource(
11454 const char * kextIdentifierCString,
11455 const char * resourceNameCString,
11456 OSKextRequestResourceCallback callback,
11457 void * context,
11458 OSKextRequestTag * requestTagOut)
11459 {
11460 OSReturn result = kOSReturnError;
11461 OSSharedPtr<OSKext> callbackKext; // looked up
11462
11463 OSKextRequestTag requestTag = -1;
11464 OSSharedPtr<OSNumber> requestTagNum;
11465 OSSharedPtr<OSDictionary> requestDict;
11466 OSSharedPtr<OSString> kextIdentifier;
11467 OSSharedPtr<OSString> resourceName;
11468
11469 OSSharedPtr<OSDictionary> callbackRecord;
11470 OSSharedPtr<OSData> callbackWrapper;
11471
11472 OSSharedPtr<OSData> contextWrapper;
11473
11474 IORecursiveLockLock(sKextLock);
11475
11476 if (requestTagOut) {
11477 *requestTagOut = kOSKextRequestTagInvalid;
11478 }
11479
11480 /* If requests to user space are disabled, don't go any further */
11481 if (!sKernelRequestsEnabled) {
11482 OSKextLog(/* kext */ NULL,
11483 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11484 "Can't request resource %s for %s - requests to user space are disabled.",
11485 resourceNameCString,
11486 kextIdentifierCString);
11487 result = kOSKextReturnDisabled;
11488 goto finish;
11489 }
11490
11491 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11492 result = kOSKextReturnInvalidArgument;
11493 goto finish;
11494 }
11495
11496 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11497 if (!callbackKext) {
11498 OSKextLog(/* kext */ NULL,
11499 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11500 "Resource request has bad callback address.");
11501 result = kOSKextReturnInvalidArgument;
11502 goto finish;
11503 }
11504 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11505 OSKextLog(/* kext */ NULL,
11506 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11507 "Resource request callback is in a kext that is not started.");
11508 result = kOSKextReturnInvalidArgument;
11509 goto finish;
11510 }
11511
11512 /* Do not allow any new requests to be made on a kext that is unloading.
11513 */
11514 if (callbackKext->flags.stopping) {
11515 result = kOSKextReturnStopping;
11516 goto finish;
11517 }
11518
11519 /* If we're wrapped the next available request tag around to the negative
11520 * numbers, we can't service any more requests.
11521 */
11522 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11523 OSKextLog(/* kext */ NULL,
11524 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11525 "No more request tags available; restart required.");
11526 result = kOSKextReturnNoResources;
11527 goto finish;
11528 }
11529 requestTag = sNextRequestTag++;
11530
11531 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
11532 requestDict);
11533 if (result != kOSReturnSuccess) {
11534 goto finish;
11535 }
11536
11537 kextIdentifier = OSString::withCString(kextIdentifierCString);
11538 resourceName = OSString::withCString(resourceNameCString);
11539 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11540 8 * sizeof(requestTag));
11541 if (!kextIdentifier ||
11542 !resourceName ||
11543 !requestTagNum ||
11544 !_OSKextSetRequestArgument(requestDict.get(),
11545 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11546 !_OSKextSetRequestArgument(requestDict.get(),
11547 kKextRequestArgumentNameKey, resourceName.get()) ||
11548 !_OSKextSetRequestArgument(requestDict.get(),
11549 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
11550 result = kOSKextReturnNoMemory;
11551 goto finish;
11552 }
11553
11554 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
11555 if (!callbackRecord) {
11556 result = kOSKextReturnNoMemory;
11557 goto finish;
11558 }
11559 // we validate callback address at call time
11560 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
11561 if (context) {
11562 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
11563 }
11564 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11565 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
11566 result = kOSKextReturnNoMemory;
11567 goto finish;
11568 }
11569
11570 if (context) {
11571 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11572 kKextRequestArgumentContextKey, contextWrapper.get())) {
11573 result = kOSKextReturnNoMemory;
11574 goto finish;
11575 }
11576 }
11577
11578 /* Only post the requests after all the other potential failure points
11579 * have been passed.
11580 */
11581 if (!sKernelRequests->setObject(requestDict.get()) ||
11582 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
11583 result = kOSKextReturnNoMemory;
11584 goto finish;
11585 }
11586
11587 OSKext::pingIOKitDaemon();
11588
11589 result = kOSReturnSuccess;
11590 if (requestTagOut) {
11591 *requestTagOut = requestTag;
11592 }
11593
11594 finish:
11595
11596 /* If we didn't succeed, yank the request & callback
11597 * from their holding arrays.
11598 */
11599 if (result != kOSReturnSuccess) {
11600 unsigned int index;
11601
11602 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
11603 if (index != (unsigned int)-1) {
11604 sKernelRequests->removeObject(index);
11605 }
11606 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
11607 if (index != (unsigned int)-1) {
11608 sRequestCallbackRecords->removeObject(index);
11609 }
11610 }
11611
11612 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11613
11614 IORecursiveLockUnlock(sKextLock);
11615
11616 return result;
11617 }
11618
11619 OSReturn
11620 OSKext::requestDaemonLaunch(
11621 OSString *kextIdentifier,
11622 OSString *serverName,
11623 OSNumber *serverTag,
11624 OSSharedPtr<IOUserServerCheckInToken> &checkInToken)
11625 {
11626 OSReturn result;
11627 IOUserServerCheckInToken * checkInTokenRaw = NULL;
11628
11629 result = requestDaemonLaunch(kextIdentifier, serverName,
11630 serverTag, &checkInTokenRaw);
11631
11632 if (kOSReturnSuccess == result) {
11633 checkInToken.reset(checkInTokenRaw, OSNoRetain);
11634 }
11635
11636 return result;
11637 }
11638
11639 OSReturn
11640 OSKext::requestDaemonLaunch(
11641 OSString *kextIdentifier,
11642 OSString *serverName,
11643 OSNumber *serverTag,
11644 IOUserServerCheckInToken ** checkInToken)
11645 {
11646 OSReturn result = kOSReturnError;
11647 OSSharedPtr<OSDictionary> requestDict;
11648 OSSharedPtr<IOUserServerCheckInToken> token;
11649
11650 if (!kextIdentifier || !serverName || !serverTag) {
11651 result = kOSKextReturnInvalidArgument;
11652 goto finish;
11653 }
11654
11655 IORecursiveLockLock(sKextLock);
11656
11657 OSKextLog(/* kext */ NULL,
11658 kOSKextLogDebugLevel |
11659 kOSKextLogGeneralFlag,
11660 "Requesting daemon launch for %s with serverName %s and tag %llu",
11661 kextIdentifier->getCStringNoCopy(),
11662 serverName->getCStringNoCopy(),
11663 serverTag->unsigned64BitValue()
11664 );
11665
11666 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
11667 if (result != kOSReturnSuccess) {
11668 goto finish;
11669 }
11670
11671 token.reset(IOUserServerCheckInToken::create(), OSNoRetain);
11672 if (!token) {
11673 result = kOSKextReturnNoMemory;
11674 goto finish;
11675 }
11676
11677 if (!_OSKextSetRequestArgument(requestDict.get(),
11678 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
11679 !_OSKextSetRequestArgument(requestDict.get(),
11680 kKextRequestArgumentDriverExtensionServerName, serverName) ||
11681 !_OSKextSetRequestArgument(requestDict.get(),
11682 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11683 !_OSKextSetRequestArgument(requestDict.get(),
11684 kKextRequestArgumentCheckInToken, token.get())) {
11685 result = kOSKextReturnNoMemory;
11686 goto finish;
11687 }
11688
11689 /* Only post the requests after all the other potential failure points
11690 * have been passed.
11691 */
11692 if (!sKernelRequests->setObject(requestDict.get())) {
11693 result = kOSKextReturnNoMemory;
11694 goto finish;
11695 }
11696 *checkInToken = token.detach();
11697 OSKext::pingIOKitDaemon();
11698
11699 result = kOSReturnSuccess;
11700 finish:
11701 IORecursiveLockUnlock(sKextLock);
11702 return result;
11703 }
11704
11705 /*********************************************************************
11706 * Assumes sKextLock is held.
11707 *********************************************************************/
11708 /* static */
11709 OSReturn
11710 OSKext::dequeueCallbackForRequestTag(
11711 OSKextRequestTag requestTag,
11712 OSSharedPtr<OSDictionary> &callbackRecordOut)
11713 {
11714 OSDictionary * callbackRecordOutRaw = NULL;
11715 OSReturn result;
11716
11717 result = dequeueCallbackForRequestTag(requestTag,
11718 &callbackRecordOutRaw);
11719
11720 if (kOSReturnSuccess == result) {
11721 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11722 }
11723
11724 return result;
11725 }
11726 OSReturn
11727 OSKext::dequeueCallbackForRequestTag(
11728 OSKextRequestTag requestTag,
11729 OSDictionary ** callbackRecordOut)
11730 {
11731 OSReturn result = kOSReturnError;
11732 OSSharedPtr<OSNumber> requestTagNum;
11733
11734 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11735 8 * sizeof(requestTag));
11736 if (!requestTagNum) {
11737 goto finish;
11738 }
11739
11740 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11741 callbackRecordOut);
11742
11743 finish:
11744 return result;
11745 }
11746
11747 /*********************************************************************
11748 * Assumes sKextLock is held.
11749 *********************************************************************/
11750 /* static */
11751 OSReturn
11752 OSKext::dequeueCallbackForRequestTag(
11753 OSNumber * requestTagNum,
11754 OSSharedPtr<OSDictionary> &callbackRecordOut)
11755 {
11756 OSDictionary * callbackRecordOutRaw = NULL;
11757 OSReturn result;
11758
11759 result = dequeueCallbackForRequestTag(requestTagNum,
11760 &callbackRecordOutRaw);
11761
11762 if (kOSReturnSuccess == result) {
11763 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11764 }
11765
11766 return result;
11767 }
11768 OSReturn
11769 OSKext::dequeueCallbackForRequestTag(
11770 OSNumber * requestTagNum,
11771 OSDictionary ** callbackRecordOut)
11772 {
11773 OSReturn result = kOSKextReturnInvalidArgument;
11774 OSDictionary * callbackRecord = NULL; // retain if matched!
11775 OSNumber * callbackTagNum = NULL; // do not release
11776 unsigned int count, i;
11777
11778 result = kOSReturnError;
11779 count = sRequestCallbackRecords->getCount();
11780 for (i = 0; i < count; i++) {
11781 callbackRecord = OSDynamicCast(OSDictionary,
11782 sRequestCallbackRecords->getObject(i));
11783 if (!callbackRecord) {
11784 goto finish;
11785 }
11786
11787 /* If we don't find a tag, we basically have a leak here. Maybe
11788 * we should just remove it.
11789 */
11790 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11791 callbackRecord, kKextRequestArgumentRequestTagKey));
11792 if (!callbackTagNum) {
11793 goto finish;
11794 }
11795
11796 /* We could be even more paranoid and check that all the incoming
11797 * args match what's in the callback record.
11798 */
11799 if (callbackTagNum->isEqualTo(requestTagNum)) {
11800 if (callbackRecordOut) {
11801 *callbackRecordOut = callbackRecord;
11802 callbackRecord->retain();
11803 }
11804 sRequestCallbackRecords->removeObject(i);
11805 result = kOSReturnSuccess;
11806 goto finish;
11807 }
11808 }
11809 result = kOSKextReturnNotFound;
11810
11811 finish:
11812 return result;
11813 }
11814
11815
11816 /*********************************************************************
11817 * Busy timeout triage
11818 *********************************************************************/
11819 /* static */
11820 bool
11821 OSKext::pendingIOKitDaemonRequests(void)
11822 {
11823 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11824 }
11825
11826 /*********************************************************************
11827 * Acquires and releases sKextLock
11828 *
11829 * This function is designed to be called exactly once on boot by
11830 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11831 * kext and dext personalities, and then attempts to map a System
11832 * (pageable) KC and an Auxiliary (aux) KC.
11833 *
11834 * Even if the pageable or aux KC fail to load - this function will
11835 * not allow a second call. This avoids security issues where
11836 * kernelmanagerd has been compromised or the pageable kc has been
11837 * tampered with and the attacker attempts to re-load a malicious
11838 * variant.
11839 *
11840 * Return: if a KC fails to load the return value will contain:
11841 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11842 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11843 * Similarly, if the aux kc load fails, the return value will
11844 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11845 * compose with each other and with kOSKextReturnKCLoadFailure.
11846 *********************************************************************/
11847 /* static */
11848 OSReturn
11849 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11850 {
11851 static bool daemon_ready = false;
11852
11853 OSReturn ret = kOSKextReturnInvalidArgument;
11854 OSReturn kcerr = 0;
11855 bool start_matching = false;
11856
11857 bool allow_fileset_load = !daemon_ready;
11858 #if !(defined(__x86_64__) || defined(__i386__))
11859 /* never allow KCs full of kexts on non-x86 machines */
11860 allow_fileset_load = false;
11861 #endif
11862
11863 /*
11864 * Change with 70582300
11865 */
11866 #if 0 || !defined(VM_MAPPED_KEXTS)
11867 /*
11868 * On platforms that don't support the SystemKC or a file-backed
11869 * AuxKC, the kext receipt for 3rd party kexts loaded by the booter
11870 * needs to be queried before we load any codeless kexts or release
11871 * any 3rd party kexts to run. On platforms that support a file-backed
11872 * AuxKC, this process is done via the kext audit mechanism.
11873 */
11874
11875 printf("KextLog: waiting for kext receipt to be queried.\n");
11876 while (!IOServiceWaitForMatchingResource(kOSKextReceiptQueried, UINT64_MAX)) {
11877 IOSleep(30);
11878 }
11879 #endif /* !VM_MAPPED_KEXTS */
11880
11881 /*
11882 * Get the args from the request. Right now we need the file
11883 * name for the pageable and the aux kext collection file sets.
11884 */
11885 OSDictionary * requestArgs = NULL; // do not release
11886 OSString * pageable_filepath = NULL; // do not release
11887 OSString * aux_filepath = NULL; // do not release
11888 OSArray * codeless_kexts = NULL; // do not release
11889
11890 kernel_mach_header_t *akc_mh = NULL;
11891
11892 requestArgs = OSDynamicCast(OSDictionary,
11893 requestDict->getObject(kKextRequestArgumentsKey));
11894
11895 if (requestArgs == NULL) {
11896 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11897 "KextLog: No arguments in plist for loading fileset kext\n");
11898 printf("KextLog: No arguments in plist for loading fileset kext\n");
11899 return ret;
11900 }
11901
11902 ret = kOSKextReturnDisabled;
11903
11904 IORecursiveLockLock(sKextLock);
11905
11906 if (!sLoadEnabled) {
11907 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11908 "KextLog: Kext loading is disabled (attempt to load KCs).");
11909 IORecursiveLockUnlock(sKextLock);
11910 return ret;
11911 }
11912
11913 pageable_filepath = OSDynamicCast(OSString,
11914 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11915
11916 if (allow_fileset_load && pageable_filepath != NULL) {
11917 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11918
11919 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11920 if (ret) {
11921 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11922 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11923
11924 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11925 ret = kOSKextReturnKCLoadFailure;
11926 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11927 goto try_auxkc;
11928 }
11929 /*
11930 * Even if the AuxKC fails to load, we still want to send
11931 * the System KC personalities to the catalog for matching
11932 */
11933 start_matching = true;
11934 } else if (pageable_filepath != NULL) {
11935 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11936 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
11937 ret = kOSKextReturnUnsupported;
11938 }
11939
11940 try_auxkc:
11941 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
11942 if (akc_mh) {
11943 /*
11944 * If we try to load a deferred AuxKC, then don't ever attempt
11945 * a filesystem map of a file
11946 */
11947 allow_fileset_load = false;
11948
11949 /*
11950 * This function is only called once per boot, so we haven't
11951 * yet loaded an AuxKC. If we have registered the AuxKC mach
11952 * header, that means that the kext collection has been placed
11953 * in memory for us by the booter, and is waiting for us to
11954 * process it. Grab the deferred XML plist of info
11955 * dictionaries and add all the kexts.
11956 */
11957 OSSharedPtr<OSObject> parsedXML;
11958 OSSharedPtr<OSData> loaded_kcUUID;
11959 OSDictionary *infoDict;
11960 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
11961 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11962 #if !defined(VM_MAPPED_KEXTS)
11963 /*
11964 * On platforms where we don't dynamically wire-down / page-in
11965 * kext memory, we need to maintain the invariant that if the
11966 * AuxKC in memory does not contain a kext receipt, then we
11967 * should not load any of the kexts.
11968 */
11969 size_t receipt_sz = 0;
11970 if (getsectdatafromheader(akc_mh, kReceiptInfoSegment, kAuxKCReceiptSection, &receipt_sz) == NULL || receipt_sz == 0) {
11971 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11972 "KextLog: WARNING: Failed to load AuxKC from memory: missing receipt");
11973 ret = kOSKextReturnKCLoadFailure;
11974 goto try_codeless;
11975 }
11976 #endif
11977 if (infoDict) {
11978 bool added;
11979 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11980 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
11981 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
11982 if (!loaded_kcUUID) {
11983 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11984 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11985 } else if (!added) {
11986 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11987 "KextLog: WARNING: Failed to load AuxKC from memory.");
11988 }
11989 /* only return success if the pageable load (above) was successful */
11990 if (ret != kOSKextReturnKCLoadFailure) {
11991 ret = kOSReturnSuccess;
11992 }
11993 /* the registration of the AuxKC parsed out the KC's UUID already */
11994 } else {
11995 if (daemon_ready) {
11996 /*
11997 * Complain, but don't return an error if this isn't the first time the
11998 * IOKit daemon is checking in. If the daemon ever restarts, we will
11999 * hit this case because we've already consumed the deferred personalities.
12000 * We return success here so that a call to this function from a restarted
12001 * daemon with no codeless kexts will succeed.
12002 */
12003 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12004 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
12005 if (ret != kOSKextReturnKCLoadFailure) {
12006 ret = kOSReturnSuccess;
12007 }
12008 } else {
12009 /* this is a real error case */
12010 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12011 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
12012 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
12013 ret = kOSKextReturnKCLoadFailure;
12014 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12015 }
12016 }
12017 }
12018
12019 aux_filepath = OSDynamicCast(OSString,
12020 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
12021 if (allow_fileset_load && aux_filepath != NULL) {
12022 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
12023
12024 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
12025 if (ret) {
12026 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12027 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12028
12029 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
12030 ret = kOSKextReturnKCLoadFailure;
12031 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
12032 goto try_codeless;
12033 }
12034 start_matching = true;
12035 } else if (aux_filepath != NULL) {
12036 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
12037 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
12038 if (ret != kOSKextReturnKCLoadFailure) {
12039 ret = kOSKextReturnUnsupported;
12040 }
12041 }
12042
12043 try_codeless:
12044 /*
12045 * Load codeless kexts last so that there is no possibilty of a
12046 * codeless kext bundle ID preventing a kext in the system KC from
12047 * loading
12048 */
12049 codeless_kexts = OSDynamicCast(OSArray,
12050 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
12051 if (codeless_kexts != NULL) {
12052 uint32_t count = codeless_kexts->getCount();
12053 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12054 "KextLog: loading %d codeless kexts/dexts", count);
12055 for (uint32_t i = 0; i < count; i++) {
12056 OSDictionary *infoDict;
12057 infoDict = OSDynamicCast(OSDictionary,
12058 codeless_kexts->getObject(i));
12059 if (!infoDict) {
12060 continue;
12061 }
12062 // instantiate a new kext, and don't hold a reference
12063 // (the kext subsystem will hold one implicitly)
12064 OSKext::withCodelessInfo(infoDict);
12065 }
12066 /* ignore errors that are not KC load failures */
12067 if (ret != kOSKextReturnKCLoadFailure) {
12068 ret = kOSReturnSuccess;
12069 }
12070 start_matching = true;
12071 }
12072
12073 /* send personalities to the IOCatalog once */
12074 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
12075 OSKext::sendAllKextPersonalitiesToCatalog(true);
12076 /*
12077 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12078 * things as active and start all the delayed matching: the
12079 * dext and codeless kext personalities should have all been
12080 * delivered via this one call.
12081 */
12082 if (!daemon_ready) {
12083 OSKext::setIOKitDaemonActive();
12084 OSKext::setDeferredLoadSucceeded(TRUE);
12085 IOService::iokitDaemonLaunched();
12086 }
12087 if (sOSKextWasResetAfterUserspaceReboot) {
12088 sOSKextWasResetAfterUserspaceReboot = false;
12089 OSKext::setIOKitDaemonActive();
12090 IOService::startDeferredMatches();
12091 }
12092 }
12093
12094 if (ret == kOSKextReturnKCLoadFailure) {
12095 ret |= kcerr;
12096 }
12097
12098 /*
12099 * Only allow this function to attempt to load the pageable and
12100 * aux KCs once per boot.
12101 */
12102 daemon_ready = true;
12103
12104 IORecursiveLockUnlock(sKextLock);
12105
12106 return ret;
12107 }
12108
12109 OSReturn
12110 OSKext::resetMutableSegments(void)
12111 {
12112 kernel_segment_command_t *seg = NULL;
12113 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12114 u_int index = 0;
12115 OSKextSavedMutableSegment *savedSegment = NULL;
12116 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12117 OSReturn err;
12118
12119 if (!savedMutableSegments) {
12120 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12121 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12122 err = kOSKextReturnInternalError;
12123 goto finish;
12124 }
12125
12126 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12127 if (!segmentIsMutable(seg)) {
12128 continue;
12129 }
12130 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12131 uint64_t vmsize = seg->vmsize;
12132 err = kOSKextReturnInternalError;
12133 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12134 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12135 assert(savedSegment);
12136 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12137 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12138 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12139 err = savedSegment->restoreContents(seg);
12140 if (err != kOSReturnSuccess) {
12141 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12142 }
12143 }
12144 }
12145 if (err != kOSReturnSuccess) {
12146 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12147 }
12148 }
12149 err = kOSReturnSuccess;
12150 finish:
12151 return err;
12152 }
12153
12154
12155 /*********************************************************************
12156 * Assumes sKextLock is held.
12157 *********************************************************************/
12158 /* static */
12159 OSReturn
12160 OSKext::loadKCFileSet(
12161 const char *filepath,
12162 kc_kind_t type)
12163 {
12164 #if VM_MAPPED_KEXTS
12165 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12166 OSReturn err;
12167 struct vnode *vp = NULL;
12168 void *fileset_control;
12169 off_t fsize;
12170 bool pageable = (type == KCKindPageable);
12171
12172 if ((pageable && pageableKCloaded) ||
12173 (!pageable && auxKCloaded)) {
12174 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12175 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12176
12177 return kOSKextReturnInvalidArgument;
12178 }
12179
12180 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12181 if (!pageable && !pageableKCloaded) {
12182 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12183 "Trying to load the Aux KC without loading the Pageable KC");
12184 return kOSKextReturnInvalidArgument;
12185 }
12186
12187 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12188
12189 if (fileset_control == NULL) {
12190 printf("Could not get memory control object for file %s", filepath);
12191
12192 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12193 "Could not get memory control object for file %s", filepath);
12194 return kOSKextReturnInvalidArgument;
12195 }
12196 if (vp == NULL) {
12197 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12198 "Could not find vnode for file %s", filepath);
12199 return kOSKextReturnInvalidArgument;
12200 }
12201
12202 kernel_mach_header_t *mh = NULL;
12203 uintptr_t slide = 0;
12204
12205 #if CONFIG_CSR
12206 /*
12207 * When SIP is enabled, the KC we map must be SIP-protected
12208 */
12209 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12210 struct vnode_attr va;
12211 int error;
12212 VATTR_INIT(&va);
12213 VATTR_WANTED(&va, va_flags);
12214 error = vnode_getattr(vp, &va, vfs_context_current());
12215 if (error) {
12216 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12217 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12218 err = kOSKextReturnInternalError;
12219 goto finish;
12220 }
12221 if (!(va.va_flags & SF_RESTRICTED)) {
12222 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12223 "Path to KC '%s' is not SIP-protected", filepath);
12224 err = kOSKextReturnInvalidArgument;
12225 goto finish;
12226 }
12227 }
12228 #endif
12229
12230 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12231 if (err) {
12232 printf("KextLog: mapKCFileSet returned %d\n", err);
12233
12234 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12235 "mapKCFileSet returned %d\n", err);
12236
12237 err = kOSKextReturnInvalidArgument;
12238 }
12239
12240 #if CONFIG_CSR
12241 finish:
12242 #endif
12243 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12244 assert(vp != NULL);
12245 if (err == kOSReturnSuccess) {
12246 PE_set_kc_vp(type, vp);
12247 if (pageable) {
12248 pageableKCloaded = true;
12249 } else {
12250 auxKCloaded = true;
12251 }
12252 } else {
12253 vnode_put(vp);
12254 }
12255
12256 return err;
12257 #else
12258 (void)filepath;
12259 (void)type;
12260 return kOSKextReturnUnsupported;
12261 #endif // VM_MAPPED_KEXTS
12262 }
12263
12264 #if defined(__x86_64__) || defined(__i386__)
12265 /*********************************************************************
12266 * Assumes sKextLock is held.
12267 *********************************************************************/
12268 /* static */
12269 OSReturn
12270 OSKext::mapKCFileSet(
12271 void *control,
12272 vm_size_t fsize,
12273 kernel_mach_header_t **mhp,
12274 off_t file_offset,
12275 uintptr_t *slidep,
12276 bool pageable,
12277 void *map_entry_list)
12278 {
12279 bool fileset_load = false;
12280 kern_return_t ret;
12281 OSReturn err;
12282 kernel_section_t *infoPlistSection = NULL;
12283 OSDictionary *infoDict = NULL;
12284
12285 OSSharedPtr<OSObject> parsedXML;
12286 OSSharedPtr<OSString> errorString;
12287 OSSharedPtr<OSData> loaded_kcUUID;
12288
12289 /* Check if initial load for file set */
12290 if (*mhp == NULL) {
12291 fileset_load = true;
12292
12293 /* Get a page aligned address from kext map to map the file */
12294 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12295 if (pagealigned_addr == 0) {
12296 return kOSKextReturnNoMemory;
12297 }
12298
12299 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12300
12301 /* Allocate memory for bailout mechanism */
12302 map_entry_list = allocate_kcfileset_map_entry_list();
12303 if (map_entry_list == NULL) {
12304 return kOSKextReturnNoMemory;
12305 }
12306 }
12307
12308 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12309 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12310 /* mhp and slideptr are updated by mapKCTextSegment */
12311 if (err) {
12312 if (fileset_load) {
12313 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12314 }
12315 return err;
12316 }
12317
12318 /* Initialize the kc header globals */
12319 if (fileset_load) {
12320 if (pageable) {
12321 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12322 } else {
12323 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12324 }
12325 }
12326
12327 /* Iterate through all the segments and map necessary segments */
12328 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12329 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12330 vm_map_offset_t start;
12331 kernel_mach_header_t *k_mh = NULL;
12332 kernel_segment_command_t * seg = NULL;
12333 struct fileset_entry_command *fse = NULL;
12334
12335 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12336 seg = (kernel_segment_command_t *)lcp;
12337 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12338 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12339 fse = (struct fileset_entry_command *)lcp;
12340 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12341
12342 /* Map the segments of the mach-o binary */
12343 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12344 if (err) {
12345 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12346 return kOSKextReturnInvalidArgument;
12347 }
12348 continue;
12349 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12350 /* Check if the Aux KC is built pageable style */
12351 if (!pageable && !fileset_load && !auxKCloaded) {
12352 resetAuxKCSegmentOnUnload = true;
12353 }
12354 continue;
12355 } else {
12356 continue;
12357 }
12358
12359 if (fileset_load) {
12360 if (seg->vmsize == 0) {
12361 continue;
12362 }
12363
12364 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12365 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12366 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12367 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12368 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12369 continue;
12370 }
12371 } else {
12372 if (seg->vmsize == 0) {
12373 continue;
12374 }
12375
12376 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12377 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12378 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12379 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12380 continue;
12381 }
12382 }
12383
12384 ret = vm_map_kcfileset_segment(
12385 &start, seg->vmsize,
12386 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12387
12388 if (ret != KERN_SUCCESS) {
12389 if (fileset_load) {
12390 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12391 }
12392 return kOSKextReturnInvalidArgument;
12393 }
12394 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12395 }
12396
12397 /* Return if regular mach-o */
12398 if (!fileset_load) {
12399 return 0;
12400 }
12401
12402 /*
12403 * Fixup for the Pageable KC and the Aux KC is done by
12404 * i386_slide_kext_collection_mh_addrs, but it differs in
12405 * following ways:
12406 *
12407 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12408 * The fixup of kext segments and kext load commands are done at kext
12409 * load time by calling i386_slide_individual_kext.
12410 *
12411 * AuxKC old style: Fixup all the segments and all the load commands.
12412 *
12413 * AuxKC pageable style: Same as the Pageable KC.
12414 */
12415 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12416 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12417 if (ret != KERN_SUCCESS) {
12418 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12419 return kOSKextReturnInvalidArgument;
12420 }
12421
12422 /* Get the prelink info dictionary */
12423 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12424 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12425 if (parsedXML) {
12426 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12427 }
12428
12429 if (!infoDict) {
12430 const char *errorCString = "(unknown error)";
12431
12432 if (errorString && errorString->getCStringNoCopy()) {
12433 errorCString = errorString->getCStringNoCopy();
12434 } else if (parsedXML) {
12435 errorCString = "not a dictionary";
12436 }
12437 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12438 "Error unserializing kext info plist section: %s.", errorCString);
12439 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12440 return kOSKextReturnInvalidArgument;
12441 }
12442
12443 /* Validate that the Kext Collection is prelinked to the loaded KC */
12444 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12445 if (err) {
12446 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12447 return kOSKextReturnInvalidArgument;
12448 }
12449
12450 /* Set Protection of Segments */
12451 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12452
12453 OSKext::addKextsFromKextCollection(*mhp,
12454 infoDict, kPrelinkTextSegment,
12455 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12456
12457 /* Copy in the KC UUID */
12458 if (!loaded_kcUUID) {
12459 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12460 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12461 } else if (pageable) {
12462 pageablekc_uuid_valid = TRUE;
12463 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12464 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12465 } else {
12466 auxkc_uuid_valid = TRUE;
12467 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12468 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12469 }
12470
12471 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12472
12473 return 0;
12474 }
12475
12476 /*********************************************************************
12477 * Assumes sKextLock is held.
12478 *********************************************************************/
12479 /* static */
12480 OSReturn
12481 OSKext::mapKCTextSegment(
12482 void *control,
12483 kernel_mach_header_t **mhp,
12484 off_t file_offset,
12485 uintptr_t *slidep,
12486 void *map_entry_list)
12487 {
12488 kern_return_t ret;
12489 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12490 PAGE_MASK);
12491 vm_map_offset_t load_command_map_size = 0;
12492 kernel_mach_header_t *base_mh = *mhp;
12493
12494 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12495 ret = vm_map_kcfileset_segment(
12496 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12497 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12498
12499 if (ret != KERN_SUCCESS) {
12500 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12501
12502 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12503 "Failed to map mach header of kc fileset with error %d", ret);
12504 return kOSKextReturnInvalidArgument;
12505 }
12506
12507 if (slidep) {
12508 /* Verify that it's an MH_FILESET */
12509 if (base_mh->filetype != MH_FILESET) {
12510 printf("Kext Log: mapKCTextSegment mach header filetype"
12511 " is not an MH_FILESET, it is %x", base_mh->filetype);
12512
12513 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12514 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12515
12516 /* Unmap the mach header */
12517 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12518 return kOSKextReturnInvalidArgument;
12519 }
12520 }
12521
12522 /* Map the remaining pages of load commands */
12523 if (base_mh->sizeofcmds > mach_header_map_size) {
12524 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12525 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12526
12527 /* Map the load commands */
12528 ret = vm_map_kcfileset_segment(
12529 &load_command_addr, load_command_map_size,
12530 (memory_object_control_t)control, file_offset + mach_header_map_size,
12531 (VM_PROT_READ | VM_PROT_WRITE));
12532
12533 if (ret != KERN_SUCCESS) {
12534 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12535 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12536 "Failed to map load commands of kc fileset with error %d", ret);
12537
12538 /* Unmap the mach header */
12539 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12540 return kOSKextReturnInvalidArgument;
12541 }
12542 }
12543
12544 kernel_segment_command_t *text_seg;
12545 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12546
12547 /* Calculate the slide and vm addr of mach header */
12548 if (slidep) {
12549 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12550 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12551 }
12552
12553 /* Cache the text segment size and file offset before unmapping */
12554 vm_map_offset_t text_segment_size = text_seg->vmsize;
12555 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12556 vm_prot_t text_maxprot = text_seg->maxprot;
12557
12558 /* Unmap the first page and loadcommands and map the text segment */
12559 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12560 assert(ret == KERN_SUCCESS);
12561
12562 if (load_command_map_size) {
12563 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12564 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12565 assert(ret == KERN_SUCCESS);
12566 }
12567
12568 /* Map the text segment at actual vm addr specified in fileset */
12569 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12570 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12571 if (ret != KERN_SUCCESS) {
12572 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12573 "Failed to map Text segment of kc fileset with error %d", ret);
12574 return kOSKextReturnInvalidArgument;
12575 }
12576
12577 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12578 return 0;
12579 }
12580
12581 /*********************************************************************
12582 * Assumes sKextLock is held.
12583 *********************************************************************/
12584 /* static */
12585 OSReturn
12586 OSKext::protectKCFileSet(
12587 kernel_mach_header_t *mh,
12588 kc_kind_t type)
12589 {
12590 vm_map_t kext_map = g_kext_map;
12591 kernel_segment_command_t * seg = NULL;
12592 vm_map_offset_t start = 0;
12593 vm_map_offset_t end = 0;
12594 OSReturn ret = 0;
12595
12596 /* Set VM permissions */
12597 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12598 while (seg) {
12599 start = round_page(seg->vmaddr);
12600 end = trunc_page(seg->vmaddr + seg->vmsize);
12601
12602 /*
12603 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12604 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12605 * for the Aux KC as well.
12606 */
12607 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12608 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12609 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12610 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12611 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12612 ret = OSKext_protect((kernel_mach_header_t *)mh,
12613 kext_map, start, end, seg->maxprot, TRUE, type);
12614 if (ret != KERN_SUCCESS) {
12615 printf("OSKext protect failed with error %d", ret);
12616 return kOSKextReturnInvalidArgument;
12617 }
12618
12619 ret = OSKext_protect((kernel_mach_header_t *)mh,
12620 kext_map, start, end, seg->initprot, FALSE, type);
12621 if (ret != KERN_SUCCESS) {
12622 printf("OSKext protect failed with error %d", ret);
12623 return kOSKextReturnInvalidArgument;
12624 }
12625
12626 ret = OSKext_wire((kernel_mach_header_t *)mh,
12627 kext_map, start, end, seg->initprot, FALSE, type);
12628 if (ret != KERN_SUCCESS) {
12629 printf("OSKext wire failed with error %d", ret);
12630 return kOSKextReturnInvalidArgument;
12631 }
12632 }
12633
12634 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12635 }
12636
12637 return 0;
12638 }
12639
12640 /*********************************************************************
12641 * Assumes sKextLock is held.
12642 *********************************************************************/
12643 /* static */
12644 void
12645 OSKext::freeKCFileSetcontrol(void)
12646 {
12647 PE_reset_all_kc_vp();
12648 }
12649
12650 /*********************************************************************
12651 * Assumes sKextLock is held.
12652 *
12653 * resetKCFileSetSegments: Kext start function expects data segment to
12654 * be pristine on every load, unmap the dirty segments on unload and
12655 * remap them from FileSet on disk. Remap all segments of kext since
12656 * fixups are done per kext and not per segment.
12657 *********************************************************************/
12658 OSReturn
12659 OSKext::resetKCFileSetSegments(void)
12660 {
12661 kernel_segment_command_t *seg = NULL;
12662 kernel_segment_command_t *text_seg;
12663 uint32_t text_fileoff;
12664 kernel_mach_header_t *k_mh = NULL;
12665 uintptr_t slide;
12666 struct vnode *vp = NULL;
12667 void *fileset_control = NULL;
12668 bool pageable = (kc_type == KCKindPageable);
12669 OSReturn err;
12670 kern_return_t kr;
12671
12672 /* Check the vnode reference is still available */
12673 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12674 if (vp == NULL) {
12675 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12676 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12677 return kOSKextReturnInternalError;
12678 }
12679
12680 fileset_control = ubc_getobject(vp, 0);
12681 assert(fileset_control != NULL);
12682
12683 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12684 "Kext %s resetting all segments", getIdentifierCString());
12685
12686 k_mh = (kernel_mach_header_t *)kmod_info->address;
12687 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12688 text_fileoff = text_seg->fileoff;
12689 slide = PE_get_kc_slide(kc_type);
12690
12691 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12692 while (seg) {
12693 if (seg->vmsize == 0) {
12694 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12695 continue;
12696 }
12697
12698 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12699 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12700 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12701 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12702 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12703 continue;
12704 }
12705
12706 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12707 assert(kr == KERN_SUCCESS);
12708 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12709 }
12710
12711 /* Unmap the text segment */
12712 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12713 assert(kr == KERN_SUCCESS);
12714
12715 /* Map all the segments of the kext */
12716 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12717 if (err) {
12718 panic("Could not reset segments of a mapped kext, error %x", err);
12719 }
12720
12721 /* Update address in kmod_info, since it has been reset */
12722 if (kmod_info->address) {
12723 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12724 }
12725
12726 return 0;
12727 }
12728
12729 /*********************************************************************
12730 * Mechanism to track all segment mapping while mapping KC fileset.
12731 *********************************************************************/
12732
12733 struct kcfileset_map_entry {
12734 vm_map_offset_t me_start;
12735 vm_map_offset_t me_size;
12736 };
12737
12738 struct kcfileset_map_entry_list {
12739 int kme_list_count;
12740 int kme_list_index;
12741 struct kcfileset_map_entry kme_list[];
12742 };
12743
12744 #define KCFILESET_MAP_ENTRY_MAX (16380)
12745
12746 static void *
12747 allocate_kcfileset_map_entry_list(void)
12748 {
12749 struct kcfileset_map_entry_list *entry_list;
12750
12751 entry_list = (struct kcfileset_map_entry_list *)kalloc(sizeof(struct kcfileset_map_entry_list) +
12752 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12753
12754 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12755 entry_list->kme_list_index = 0;
12756 return entry_list;
12757 }
12758
12759 static void
12760 add_kcfileset_map_entry(
12761 void *map_entry_list,
12762 vm_map_offset_t start,
12763 vm_map_offset_t size)
12764 {
12765 if (map_entry_list == NULL) {
12766 return;
12767 }
12768
12769 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12770
12771 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12772 panic("Ran out of map kc fileset list\n");
12773 }
12774
12775 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12776 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12777
12778 entry_list->kme_list_index++;
12779 }
12780
12781 static void
12782 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12783 void *map_entry_list,
12784 boolean_t unmap_entries,
12785 bool pageable)
12786 {
12787 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12788
12789 if (unmap_entries) {
12790 for (int i = 0; i < entry_list->kme_list_index; i++) {
12791 kern_return_t ret;
12792 ret = vm_unmap_kcfileset_segment(
12793 &(entry_list->kme_list[i].me_start),
12794 entry_list->kme_list[i].me_size);
12795 assert(ret == KERN_SUCCESS);
12796 }
12797
12798 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
12799 }
12800
12801 kfree(entry_list, sizeof(struct kcfileset_map_entry_list) +
12802 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12803 }
12804
12805 /*********************************************************************
12806 * Mechanism to map kext segment.
12807 *********************************************************************/
12808
12809 kern_return_t
12810 vm_map_kcfileset_segment(
12811 vm_map_offset_t *start,
12812 vm_map_offset_t size,
12813 void *control,
12814 vm_object_offset_t fileoffset,
12815 vm_prot_t max_prot)
12816 {
12817 vm_map_kernel_flags_t vmk_flags;
12818 vmk_flags.vmkf_no_copy_on_read = 1;
12819 vmk_flags.vmkf_cs_enforcement = 0;
12820 vmk_flags.vmkf_cs_enforcement_override = 1;
12821 kern_return_t ret;
12822
12823 /* Add Write to max prot to allow fixups */
12824 max_prot = max_prot | VM_PROT_WRITE;
12825
12826 /*
12827 * Map the segments from file as COPY mappings to
12828 * make sure changes on disk to the file does not affect
12829 * mapped segments.
12830 */
12831 ret = vm_map_enter_mem_object_control(
12832 g_kext_map,
12833 start,
12834 size,
12835 (mach_vm_offset_t)0,
12836 VM_FLAGS_FIXED,
12837 vmk_flags,
12838 VM_KERN_MEMORY_OSKEXT,
12839 (memory_object_control_t)control,
12840 fileoffset,
12841 TRUE, /* copy */
12842 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12843 VM_INHERIT_NONE);
12844
12845 return ret;
12846 }
12847
12848 kern_return_t
12849 vm_unmap_kcfileset_segment(
12850 vm_map_offset_t *start,
12851 vm_map_offset_t size)
12852 {
12853 return mach_vm_deallocate(g_kext_map, *start, size);
12854 }
12855
12856 #endif //(__x86_64__) || defined(__i386__)
12857
12858 /*********************************************************************
12859 * Assumes sKextLock is held.
12860 *********************************************************************/
12861 /* static */
12862 OSReturn
12863 OSKext::validateKCFileSetUUID(
12864 OSDictionary *infoDict,
12865 kc_kind_t type)
12866 {
12867 OSReturn ret = kOSReturnSuccess;
12868
12869 if (!kernelcache_uuid_valid) {
12870 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12871 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12872 ret = kOSKextReturnInvalidArgument;
12873 goto finish;
12874 }
12875 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12876 if (ret != 0) {
12877 goto finish;
12878 }
12879
12880 #if defined(__x86_64__) || defined(__i386__)
12881 /* Check if the Aux KC is prelinked to correct Pageable KC */
12882 if (type == KCKindAuxiliary) {
12883 if (!pageablekc_uuid_valid) {
12884 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12885 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12886 ret = kOSKextReturnInvalidArgument;
12887 goto finish;
12888 }
12889 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12890 if (ret != 0) {
12891 goto finish;
12892 }
12893 }
12894 #endif //(__x86_64__) || defined(__i386__)
12895
12896 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12897 finish:
12898 return ret;
12899 }
12900
12901 /*********************************************************************
12902 * Assumes sKextLock is held.
12903 *********************************************************************/
12904 /* static */
12905 OSReturn
12906 OSKext::validateKCUUIDfromPrelinkInfo(
12907 uuid_t *loaded_kcuuid,
12908 kc_kind_t type,
12909 OSDictionary *infoDict,
12910 const char *uuid_key)
12911 {
12912 /* extract the UUID from the dictionary */
12913 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12914 if (!prelinkinfoKCUUID) {
12915 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12916 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12917 return kOSKextReturnInvalidArgument;
12918 }
12919
12920 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12921 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12922 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12923 return kOSKextReturnInvalidArgument;
12924 }
12925
12926 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
12927 prelinkinfoKCUUID->getLength())) {
12928 OSData *info_dict_uuid;
12929 uuid_string_t info_dict_uuid_str = {};
12930 uuid_string_t expected_uuid_str = {};
12931 uuid_string_t given_uuid_str = {};
12932 uuid_t given_uuid;
12933
12934 /* extract the KC UUID from the dictionary */
12935 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
12936 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
12937 uuid_t tmp_uuid;
12938 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
12939 uuid_unparse(tmp_uuid, info_dict_uuid_str);
12940 }
12941
12942 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
12943 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
12944 uuid_unparse(given_uuid, given_uuid_str);
12945
12946 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12947 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12948 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12949 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12950 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12951 if (type == KCKindPageable && sPanicOnKCMismatch) {
12952 panic("System KC UUID %s linked against %s, but %s is loaded",
12953 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
12954 }
12955 return kOSKextReturnInvalidArgument;
12956 }
12957
12958 return 0;
12959 }
12960
12961 /*********************************************************************
12962 * Assumes sKextLock is held.
12963 *********************************************************************/
12964 /* static */
12965 OSReturn
12966 OSKext::dispatchResource(OSDictionary * requestDict)
12967 {
12968 OSReturn result = kOSReturnError;
12969 OSSharedPtr<OSDictionary> callbackRecord;
12970 OSNumber * requestTag = NULL; // do not release
12971 OSNumber * requestResult = NULL; // do not release
12972 OSData * dataObj = NULL; // do not release
12973 uint32_t dataLength = 0;
12974 const void * dataPtr = NULL; // do not free
12975 OSData * callbackWrapper = NULL; // do not release
12976 OSKextRequestResourceCallback callback = NULL;
12977 OSData * contextWrapper = NULL; // do not release
12978 void * context = NULL; // do not free
12979 OSSharedPtr<OSKext> callbackKext;
12980
12981 /* Get the args from the request. Right now we need the tag
12982 * to look up the callback record, and the result for invoking the callback.
12983 */
12984 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12985 kKextRequestArgumentRequestTagKey));
12986 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12987 kKextRequestArgumentResultKey));
12988 if (!requestTag || !requestResult) {
12989 result = kOSKextReturnInvalidArgument;
12990 goto finish;
12991 }
12992
12993 /* Look for a callback record matching this request's tag.
12994 */
12995 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
12996 if (result != kOSReturnSuccess) {
12997 goto finish;
12998 }
12999
13000 /*****
13001 * Get the context pointer of the callback record (if there is one).
13002 */
13003 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord.get(),
13004 kKextRequestArgumentContextKey));
13005 context = _OSKextExtractPointer(contextWrapper);
13006 if (contextWrapper && !context) {
13007 goto finish;
13008 }
13009
13010 callbackWrapper = OSDynamicCast(OSData,
13011 _OSKextGetRequestArgument(callbackRecord.get(),
13012 kKextRequestArgumentCallbackKey));
13013 callback = _OSKextExtractCallbackPointer(callbackWrapper);
13014 if (!callback) {
13015 goto finish;
13016 }
13017
13018 /* Check for a data obj. We might not have one and that's ok, that means
13019 * we didn't find the requested resource, and we still have to tell the
13020 * caller that via the callback.
13021 */
13022 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
13023 kKextRequestArgumentValueKey));
13024 if (dataObj) {
13025 dataPtr = dataObj->getBytesNoCopy();
13026 dataLength = dataObj->getLength();
13027 }
13028
13029 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
13030 if (!callbackKext) {
13031 OSKextLog(/* kext */ NULL,
13032 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13033 "Can't invoke callback for resource request; ");
13034 goto finish;
13035 }
13036 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
13037 OSKextLog(/* kext */ NULL,
13038 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
13039 "Can't invoke kext resource callback; ");
13040 goto finish;
13041 }
13042
13043 (void)callback(requestTag->unsigned32BitValue(),
13044 (OSReturn)requestResult->unsigned32BitValue(),
13045 dataPtr, dataLength, context);
13046
13047 result = kOSReturnSuccess;
13048
13049 finish:
13050 return result;
13051 }
13052
13053 /*********************************************************************
13054 * Assumes sKextLock is held.
13055 *********************************************************************/
13056 /* static */
13057 OSReturn
13058 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
13059 {
13060 OSSharedPtr<OSDictionary> missingIDs;
13061 OSArray *bundleIDList = NULL; // do not release
13062
13063 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
13064 requestDict, kKextRequestArgumentMissingBundleIDs));
13065 if (!bundleIDList) {
13066 return kOSKextReturnInvalidArgument;
13067 }
13068
13069 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
13070 if (!missingIDs) {
13071 return kOSKextReturnNoMemory;
13072 }
13073
13074 uint32_t count, i;
13075 count = bundleIDList->getCount();
13076 for (i = 0; i < count; i++) {
13077 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
13078 if (thisID) {
13079 missingIDs->setObject(thisID, kOSBooleanFalse);
13080 }
13081 }
13082
13083 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13084
13085 return kOSReturnSuccess;
13086 }
13087
13088 /*********************************************************************
13089 * Assumes sKextLock is held.
13090 *********************************************************************/
13091 /* static */
13092 OSReturn
13093 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13094 {
13095 bool loadable = true;
13096 if (!kextIdentifier) {
13097 return kOSKextReturnInvalidArgument;
13098 }
13099
13100 if (requestDict) {
13101 OSBoolean *loadableArg;
13102 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13103 requestDict, kKextRequestArgumentBundleAvailability));
13104 /* If we find the "Bundle Available" arg, and it's false, then
13105 * mark the bundle ID as _not_ loadable
13106 */
13107 if (loadableArg && !loadableArg->getValue()) {
13108 loadable = false;
13109 }
13110 }
13111
13112 if (!sNonLoadableKextsByID) {
13113 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13114 }
13115
13116 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13117
13118 OSKextLog(/* kext */ NULL,
13119 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13120 "KextLog: AuxKC bundle %s marked as %s",
13121 kextIdentifier->getCStringNoCopy(),
13122 (loadable ? "loadable" : "NOT loadable"));
13123
13124 return kOSReturnSuccess;
13125 }
13126
13127 /*********************************************************************
13128 *********************************************************************/
13129 /* static */
13130 void
13131 OSKext::invokeRequestCallback(
13132 OSDictionary * callbackRecord,
13133 OSReturn callbackResult)
13134 {
13135 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
13136 OSSharedPtr<OSNumber> resultNum;
13137
13138 if (!predicate) {
13139 goto finish;
13140 }
13141
13142 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13143 8 * sizeof(callbackResult));
13144 if (!resultNum) {
13145 goto finish;
13146 }
13147
13148 /* Insert the result into the callback record and dispatch it as if it
13149 * were the reply coming down from user space.
13150 */
13151 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
13152 resultNum.get());
13153
13154 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13155 /* This removes the pending callback record.
13156 */
13157 OSKext::dispatchResource(callbackRecord);
13158 }
13159
13160 finish:
13161 return;
13162 }
13163
13164 /*********************************************************************
13165 * Assumes sKextLock is held.
13166 *********************************************************************/
13167 /* static */
13168 OSReturn
13169 OSKext::cancelRequest(
13170 OSKextRequestTag requestTag,
13171 void ** contextOut)
13172 {
13173 OSReturn result = kOSKextReturnNoMemory;
13174 OSSharedPtr<OSDictionary> callbackRecord;
13175 OSData * contextWrapper = NULL; // do not release
13176
13177 IORecursiveLockLock(sKextLock);
13178 result = OSKext::dequeueCallbackForRequestTag(requestTag,
13179 callbackRecord);
13180 IORecursiveLockUnlock(sKextLock);
13181
13182 if (result == kOSReturnSuccess && contextOut) {
13183 contextWrapper = OSDynamicCast(OSData,
13184 _OSKextGetRequestArgument(callbackRecord.get(),
13185 kKextRequestArgumentContextKey));
13186 *contextOut = _OSKextExtractPointer(contextWrapper);
13187 }
13188
13189 return result;
13190 }
13191
13192 /*********************************************************************
13193 * Assumes sKextLock is held.
13194 *********************************************************************/
13195 void
13196 OSKext::invokeOrCancelRequestCallbacks(
13197 OSReturn callbackResult,
13198 bool invokeFlag)
13199 {
13200 unsigned int count, i;
13201
13202 count = sRequestCallbackRecords->getCount();
13203 if (!count) {
13204 goto finish;
13205 }
13206
13207 i = count - 1;
13208 do {
13209 OSDictionary * request = OSDynamicCast(OSDictionary,
13210 sRequestCallbackRecords->getObject(i));
13211
13212 if (!request) {
13213 continue;
13214 }
13215 OSData * callbackWrapper = OSDynamicCast(OSData,
13216 _OSKextGetRequestArgument(request,
13217 kKextRequestArgumentCallbackKey));
13218
13219 if (!callbackWrapper) {
13220 sRequestCallbackRecords->removeObject(i);
13221 continue;
13222 }
13223
13224 vm_address_t callbackAddress = (vm_address_t)
13225 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13226
13227 if ((kmod_info->address <= callbackAddress) &&
13228 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13229 if (invokeFlag) {
13230 /* This removes the callback record.
13231 */
13232 invokeRequestCallback(request, callbackResult);
13233 } else {
13234 sRequestCallbackRecords->removeObject(i);
13235 }
13236 }
13237 } while (i--);
13238
13239 finish:
13240 return;
13241 }
13242
13243 /*********************************************************************
13244 * Assumes sKextLock is held.
13245 *********************************************************************/
13246 uint32_t
13247 OSKext::countRequestCallbacks(void)
13248 {
13249 uint32_t result = 0;
13250 unsigned int count, i;
13251
13252 count = sRequestCallbackRecords->getCount();
13253 if (!count) {
13254 goto finish;
13255 }
13256
13257 i = count - 1;
13258 do {
13259 OSDictionary * request = OSDynamicCast(OSDictionary,
13260 sRequestCallbackRecords->getObject(i));
13261
13262 if (!request) {
13263 continue;
13264 }
13265 OSData * callbackWrapper = OSDynamicCast(OSData,
13266 _OSKextGetRequestArgument(request,
13267 kKextRequestArgumentCallbackKey));
13268
13269 if (!callbackWrapper) {
13270 continue;
13271 }
13272
13273 vm_address_t callbackAddress = (vm_address_t)
13274 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13275
13276 if ((kmod_info->address <= callbackAddress) &&
13277 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13278 result++;
13279 }
13280 } while (i--);
13281
13282 finish:
13283 return result;
13284 }
13285
13286 /*********************************************************************
13287 *********************************************************************/
13288 static OSReturn
13289 _OSKextCreateRequest(
13290 const char * predicate,
13291 OSSharedPtr<OSDictionary> & requestR)
13292 {
13293 OSReturn result = kOSKextReturnNoMemory;
13294 OSSharedPtr<OSDictionary> request;
13295
13296 request = OSDictionary::withCapacity(2);
13297 if (!request) {
13298 goto finish;
13299 }
13300 result = _OSDictionarySetCStringValue(request.get(),
13301 kKextRequestPredicateKey, predicate);
13302 if (result != kOSReturnSuccess) {
13303 goto finish;
13304 }
13305 result = kOSReturnSuccess;
13306
13307 finish:
13308 if (result == kOSReturnSuccess) {
13309 requestR = os::move(request);
13310 }
13311
13312 return result;
13313 }
13314
13315 /*********************************************************************
13316 *********************************************************************/
13317 static OSString *
13318 _OSKextGetRequestPredicate(OSDictionary * requestDict)
13319 {
13320 return OSDynamicCast(OSString,
13321 requestDict->getObject(kKextRequestPredicateKey));
13322 }
13323
13324 /*********************************************************************
13325 *********************************************************************/
13326 static OSObject *
13327 _OSKextGetRequestArgument(
13328 OSDictionary * requestDict,
13329 const char * argName)
13330 {
13331 OSDictionary * args = OSDynamicCast(OSDictionary,
13332 requestDict->getObject(kKextRequestArgumentsKey));
13333 if (args) {
13334 return args->getObject(argName);
13335 }
13336 return NULL;
13337 }
13338
13339 /*********************************************************************
13340 *********************************************************************/
13341 static bool
13342 _OSKextSetRequestArgument(
13343 OSDictionary * requestDict,
13344 const char * argName,
13345 OSObject * value)
13346 {
13347 OSDictionary * args = OSDynamicCast(OSDictionary,
13348 requestDict->getObject(kKextRequestArgumentsKey));
13349 OSSharedPtr<OSDictionary> newArgs;
13350 if (!args) {
13351 newArgs = OSDictionary::withCapacity(2);
13352 args = newArgs.get();
13353 if (!args) {
13354 goto finish;
13355 }
13356 requestDict->setObject(kKextRequestArgumentsKey, args);
13357 }
13358 if (args) {
13359 return args->setObject(argName, value);
13360 }
13361 finish:
13362 return false;
13363 }
13364
13365 /*********************************************************************
13366 *********************************************************************/
13367 static void *
13368 _OSKextExtractPointer(OSData * wrapper)
13369 {
13370 void * result = NULL;
13371 const void * resultPtr = NULL;
13372
13373 if (!wrapper) {
13374 goto finish;
13375 }
13376 resultPtr = wrapper->getBytesNoCopy();
13377 result = *(void **)resultPtr;
13378 finish:
13379 return result;
13380 }
13381
13382 /*********************************************************************
13383 *********************************************************************/
13384 static OSKextRequestResourceCallback
13385 _OSKextExtractCallbackPointer(OSData * wrapper)
13386 {
13387 OSKextRequestResourceCallback result = NULL;
13388 const void * resultPtr = NULL;
13389
13390 if (!wrapper) {
13391 goto finish;
13392 }
13393 resultPtr = wrapper->getBytesNoCopy();
13394 result = *(OSKextRequestResourceCallback *)resultPtr;
13395 finish:
13396 return result;
13397 }
13398
13399
13400 /*********************************************************************
13401 *********************************************************************/
13402 static OSReturn
13403 _OSDictionarySetCStringValue(
13404 OSDictionary * dict,
13405 const char * cKey,
13406 const char * cValue)
13407 {
13408 OSReturn result = kOSKextReturnNoMemory;
13409 OSSharedPtr<const OSSymbol> key;
13410 OSSharedPtr<OSString> value;
13411
13412 key = OSSymbol::withCString(cKey);
13413 value = OSString::withCString(cValue);
13414 if (!key || !value) {
13415 goto finish;
13416 }
13417 if (dict->setObject(key.get(), value.get())) {
13418 result = kOSReturnSuccess;
13419 }
13420
13421 finish:
13422 return result;
13423 }
13424
13425 /*********************************************************************
13426 *********************************************************************/
13427 static bool
13428 _OSArrayContainsCString(
13429 OSArray * array,
13430 const char * cString)
13431 {
13432 bool result = false;
13433 OSSharedPtr<const OSSymbol> symbol;
13434 uint32_t count, i;
13435
13436 if (!array || !cString) {
13437 goto finish;
13438 }
13439
13440 symbol = OSSymbol::withCStringNoCopy(cString);
13441 if (!symbol) {
13442 goto finish;
13443 }
13444
13445 count = array->getCount();
13446 for (i = 0; i < count; i++) {
13447 OSObject * thisObject = array->getObject(i);
13448 if (symbol->isEqualTo(thisObject)) {
13449 result = true;
13450 goto finish;
13451 }
13452 }
13453
13454 finish:
13455 return result;
13456 }
13457
13458 #if CONFIG_KXLD
13459 /*********************************************************************
13460 * We really only care about boot / system start up related kexts.
13461 * We return true if we're less than REBUILD_MAX_TIME since start up,
13462 * otherwise return false.
13463 *********************************************************************/
13464 bool
13465 _OSKextInPrelinkRebuildWindow(void)
13466 {
13467 static bool outside_the_window = false;
13468 AbsoluteTime my_abstime;
13469 UInt64 my_ns;
13470 SInt32 my_secs;
13471
13472 if (outside_the_window) {
13473 return false;
13474 }
13475 clock_get_uptime(&my_abstime);
13476 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13477 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13478 if (my_secs > REBUILD_MAX_TIME) {
13479 outside_the_window = true;
13480 return false;
13481 }
13482 return true;
13483 }
13484 #endif /* CONFIG_KXLD */
13485
13486 /*********************************************************************
13487 *********************************************************************/
13488 bool
13489 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13490 {
13491 int unLoadedCount, i;
13492 bool result = false;
13493
13494 IORecursiveLockLock(sKextLock);
13495
13496 if (sUnloadedPrelinkedKexts == NULL) {
13497 goto finish;
13498 }
13499 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13500 if (unLoadedCount == 0) {
13501 goto finish;
13502 }
13503
13504 for (i = 0; i < unLoadedCount; i++) {
13505 const OSSymbol * myBundleID; // do not release
13506
13507 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13508 if (!myBundleID) {
13509 continue;
13510 }
13511 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13512 result = true;
13513 break;
13514 }
13515 }
13516 finish:
13517 IORecursiveLockUnlock(sKextLock);
13518 return result;
13519 }
13520
13521 #if PRAGMA_MARK
13522 #pragma mark Personalities (IOKit Drivers)
13523 #endif
13524 /*********************************************************************
13525 *********************************************************************/
13526 /* static */
13527 OSSharedPtr<OSArray>
13528 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13529 {
13530 OSSharedPtr<OSArray> result;
13531 OSSharedPtr<OSCollectionIterator> kextIterator;
13532 OSSharedPtr<OSArray> personalities;
13533
13534 OSString * kextID = NULL; // do not release
13535 OSKext * theKext = NULL; // do not release
13536
13537 IORecursiveLockLock(sKextLock);
13538
13539 /* Let's conservatively guess that any given kext has around 3
13540 * personalities for now.
13541 */
13542 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13543 if (!result) {
13544 goto finish;
13545 }
13546
13547 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
13548 if (!kextIterator) {
13549 goto finish;
13550 }
13551
13552 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
13553 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
13554 if (theKext->flags.requireExplicitLoad) {
13555 OSKextLog(theKext,
13556 kOSKextLogDebugLevel |
13557 kOSKextLogLoadFlag,
13558 "Kext %s requires an explicit kextload; "
13559 "omitting its personalities.",
13560 theKext->getIdentifierCString());
13561 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
13562 personalities = theKext->copyPersonalitiesArray();
13563 if (!personalities) {
13564 continue;
13565 }
13566 result->merge(personalities.get());
13567 } else {
13568 // xxx - check for better place to put this log msg
13569 OSKextLog(theKext,
13570 kOSKextLogWarningLevel |
13571 kOSKextLogLoadFlag,
13572 "Kext %s is not loadable during safe boot; "
13573 "omitting its personalities.",
13574 theKext->getIdentifierCString());
13575 }
13576 }
13577
13578 finish:
13579 IORecursiveLockUnlock(sKextLock);
13580
13581 return result;
13582 }
13583
13584 /*********************************************************************
13585 *********************************************************************/
13586 /* static */
13587 void
13588 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13589 {
13590 int numPersonalities = 0;
13591
13592 OSKextLog(/* kext */ NULL,
13593 kOSKextLogStepLevel |
13594 kOSKextLogLoadFlag,
13595 "Sending all eligible registered kexts' personalities "
13596 "to the IOCatalogue %s.",
13597 startMatching ? "and starting matching" : "but not starting matching");
13598
13599 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
13600 /* filterSafeBootFlag */ true);
13601
13602 if (personalities) {
13603 gIOCatalogue->addDrivers(personalities.get(), startMatching);
13604 numPersonalities = personalities->getCount();
13605 }
13606
13607 OSKextLog(/* kext */ NULL,
13608 kOSKextLogStepLevel |
13609 kOSKextLogLoadFlag,
13610 "%d kext personalit%s sent to the IOCatalogue; %s.",
13611 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13612 startMatching ? "matching started" : "matching not started");
13613 return;
13614 }
13615
13616 /*********************************************************************
13617 * Do not make a deep copy, just convert the IOKitPersonalities dict
13618 * to an array for sending to the IOCatalogue.
13619 *********************************************************************/
13620 OSSharedPtr<OSArray>
13621 OSKext::copyPersonalitiesArray(void)
13622 {
13623 OSSharedPtr<OSArray> result;
13624 OSDictionary * personalities = NULL; // do not release
13625 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
13626
13627 OSString * personalityName = NULL; // do not release
13628 OSString * personalityBundleIdentifier = NULL; // do not release
13629
13630 personalities = OSDynamicCast(OSDictionary,
13631 getPropertyForHostArch(kIOKitPersonalitiesKey));
13632 if (!personalities) {
13633 goto finish;
13634 }
13635
13636 result = OSArray::withCapacity(personalities->getCount());
13637 if (!result) {
13638 goto finish;
13639 }
13640
13641 personalitiesIterator =
13642 OSCollectionIterator::withCollection(personalities);
13643 if (!personalitiesIterator) {
13644 goto finish;
13645 }
13646 while ((personalityName = OSDynamicCast(OSString,
13647 personalitiesIterator->getNextObject()))) {
13648 OSDictionary * personality = OSDynamicCast(OSDictionary,
13649 personalities->getObject(personalityName));
13650
13651 /******
13652 * If the personality doesn't have a CFBundleIdentifier, or if it
13653 * differs from the kext's, insert the kext's ID so we can find it.
13654 * The publisher ID is used to remove personalities from bundles
13655 * correctly.
13656 */
13657 personalityBundleIdentifier = OSDynamicCast(OSString,
13658 personality->getObject(kCFBundleIdentifierKey));
13659
13660 if (!personalityBundleIdentifier) {
13661 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13662 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13663 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
13664 }
13665
13666 result->setObject(personality);
13667 }
13668
13669 finish:
13670 return result;
13671 }
13672
13673 /*********************************************************************
13674 * Might want to change this to a bool return?
13675 *********************************************************************/
13676 OSReturn
13677 OSKext::sendPersonalitiesToCatalog(
13678 bool startMatching,
13679 OSArray * personalityNames)
13680 {
13681 OSReturn result = kOSReturnSuccess;
13682 OSSharedPtr<OSArray> personalitiesToSend;
13683 OSDictionary * kextPersonalities = NULL; // do not release
13684 int count, i;
13685
13686 if (!sLoadEnabled) {
13687 OSKextLog(this,
13688 kOSKextLogErrorLevel |
13689 kOSKextLogLoadFlag,
13690 "Kext loading is disabled (attempt to start matching for kext %s).",
13691 getIdentifierCString());
13692 result = kOSKextReturnDisabled;
13693 goto finish;
13694 }
13695
13696 if (sSafeBoot && !isLoadableInSafeBoot()) {
13697 OSKextLog(this,
13698 kOSKextLogErrorLevel |
13699 kOSKextLogLoadFlag,
13700 "Kext %s is not loadable during safe boot; "
13701 "not sending personalities to the IOCatalogue.",
13702 getIdentifierCString());
13703 result = kOSKextReturnNotLoadable;
13704 goto finish;
13705 }
13706
13707 if (!personalityNames || !personalityNames->getCount()) {
13708 personalitiesToSend = copyPersonalitiesArray();
13709 } else {
13710 kextPersonalities = OSDynamicCast(OSDictionary,
13711 getPropertyForHostArch(kIOKitPersonalitiesKey));
13712 if (!kextPersonalities || !kextPersonalities->getCount()) {
13713 // not an error
13714 goto finish;
13715 }
13716 personalitiesToSend = OSArray::withCapacity(0);
13717 if (!personalitiesToSend) {
13718 result = kOSKextReturnNoMemory;
13719 goto finish;
13720 }
13721 count = personalityNames->getCount();
13722 for (i = 0; i < count; i++) {
13723 OSString * name = OSDynamicCast(OSString,
13724 personalityNames->getObject(i));
13725 if (!name) {
13726 continue;
13727 }
13728 OSDictionary * personality = OSDynamicCast(OSDictionary,
13729 kextPersonalities->getObject(name));
13730 if (personality) {
13731 personalitiesToSend->setObject(personality);
13732 }
13733 }
13734 }
13735 if (personalitiesToSend) {
13736 unsigned numPersonalities = personalitiesToSend->getCount();
13737 OSKextLog(this,
13738 kOSKextLogStepLevel |
13739 kOSKextLogLoadFlag,
13740 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13741 getIdentifierCString(),
13742 numPersonalities,
13743 numPersonalities > 1 ? "ies" : "y",
13744 startMatching ? " and starting matching" : " but not starting matching");
13745 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
13746 }
13747 finish:
13748 return result;
13749 }
13750
13751 /*********************************************************************
13752 * xxx - We should allow removing the kext's declared personalities,
13753 * xxx - even with other bundle identifiers.
13754 *********************************************************************/
13755 void
13756 OSKext::removePersonalitiesFromCatalog(void)
13757 {
13758 OSSharedPtr<OSDictionary> personality;
13759
13760 personality = OSDictionary::withCapacity(1);
13761 if (!personality) {
13762 goto finish;
13763 }
13764 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
13765
13766 OSKextLog(this,
13767 kOSKextLogStepLevel |
13768 kOSKextLogLoadFlag,
13769 "Kext %s removing all personalities naming it from the IOCatalogue.",
13770 getIdentifierCString());
13771
13772 /* Have the IOCatalog remove all personalities matching this kext's
13773 * bundle ID and trigger matching anew.
13774 */
13775 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
13776
13777 finish:
13778 return;
13779 }
13780
13781
13782 #if PRAGMA_MARK
13783 #pragma mark Logging
13784 #endif
13785 /*********************************************************************
13786 * Do not call any function that takes sKextLock here!
13787 *********************************************************************/
13788 /* static */
13789 OSKextLogSpec
13790 OSKext::setUserSpaceLogFilter(
13791 OSKextLogSpec newUserLogFilter,
13792 bool captureFlag)
13793 {
13794 OSKextLogSpec result;
13795 bool allocError = false;
13796
13797 /* Do not call any function that takes sKextLoggingLock during
13798 * this critical block. That means do logging after.
13799 */
13800 IOLockLock(sKextLoggingLock);
13801
13802 result = sUserSpaceKextLogFilter;
13803 sUserSpaceKextLogFilter = newUserLogFilter;
13804
13805 if (newUserLogFilter && captureFlag &&
13806 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13807 // xxx - do some measurements for a good initial capacity?
13808 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13809 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13810
13811 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
13812 allocError = true;
13813 }
13814 }
13815
13816 IOLockUnlock(sKextLoggingLock);
13817
13818 /* If the config flag itself is changing, log the state change
13819 * going both ways, before setting up the user-space log arrays,
13820 * so that this is only logged in the kernel.
13821 */
13822 if (result != newUserLogFilter) {
13823 OSKextLog(/* kext */ NULL,
13824 kOSKextLogDebugLevel |
13825 kOSKextLogGeneralFlag,
13826 "User-space log flags changed from 0x%x to 0x%x.",
13827 result, newUserLogFilter);
13828 }
13829 if (allocError) {
13830 OSKextLog(/* kext */ NULL,
13831 kOSKextLogErrorLevel |
13832 kOSKextLogGeneralFlag,
13833 "Failed to allocate user-space log message arrays.");
13834 }
13835
13836 return result;
13837 }
13838
13839 /*********************************************************************
13840 * Do not call any function that takes sKextLock here!
13841 *********************************************************************/
13842 /* static */
13843 OSSharedPtr<OSArray>
13844 OSKext::clearUserSpaceLogFilter(void)
13845 {
13846 OSSharedPtr<OSArray> result;
13847 OSKextLogSpec oldLogFilter;
13848 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
13849
13850 /* Do not call any function that takes sKextLoggingLock during
13851 * this critical block. That means do logging after.
13852 */
13853 IOLockLock(sKextLoggingLock);
13854
13855 result = OSArray::withCapacity(2);
13856 if (result) {
13857 result->setObject(sUserSpaceLogSpecArray.get());
13858 result->setObject(sUserSpaceLogMessageArray.get());
13859 }
13860 sUserSpaceLogSpecArray.reset();
13861 sUserSpaceLogMessageArray.reset();
13862
13863 oldLogFilter = sUserSpaceKextLogFilter;
13864 sUserSpaceKextLogFilter = newLogFilter;
13865
13866 IOLockUnlock(sKextLoggingLock);
13867
13868 /* If the config flag itself is changing, log the state change
13869 * going both ways, after tearing down the user-space log
13870 * arrays, so this is only logged within the kernel.
13871 */
13872 if (oldLogFilter != newLogFilter) {
13873 OSKextLog(/* kext */ NULL,
13874 kOSKextLogDebugLevel |
13875 kOSKextLogGeneralFlag,
13876 "User-space log flags changed from 0x%x to 0x%x.",
13877 oldLogFilter, newLogFilter);
13878 }
13879
13880 return result;
13881 }
13882
13883
13884 /*********************************************************************
13885 * Do not call any function that takes sKextLock here!
13886 *********************************************************************/
13887 /* static */
13888 OSKextLogSpec
13889 OSKext::getUserSpaceLogFilter(void)
13890 {
13891 OSKextLogSpec result;
13892
13893 IOLockLock(sKextLoggingLock);
13894 result = sUserSpaceKextLogFilter;
13895 IOLockUnlock(sKextLoggingLock);
13896
13897 return result;
13898 }
13899
13900 /*********************************************************************
13901 * This function is called by OSMetaClass during kernel C++ setup.
13902 * Be careful what you access here; assume only OSKext::initialize()
13903 * has been called.
13904 *
13905 * Do not call any function that takes sKextLock here!
13906 *********************************************************************/
13907 #define VTRESET "\033[0m"
13908
13909 #define VTBOLD "\033[1m"
13910 #define VTUNDER "\033[4m"
13911
13912 #define VTRED "\033[31m"
13913 #define VTGREEN "\033[32m"
13914 #define VTYELLOW "\033[33m"
13915 #define VTBLUE "\033[34m"
13916 #define VTMAGENTA "\033[35m"
13917 #define VTCYAN "\033[36m"
13918
13919 inline const char *
13920 colorForFlags(OSKextLogSpec flags)
13921 {
13922 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13923
13924 switch (logLevel) {
13925 case kOSKextLogErrorLevel:
13926 return VTRED VTBOLD;
13927 case kOSKextLogWarningLevel:
13928 return VTRED;
13929 case kOSKextLogBasicLevel:
13930 return VTYELLOW VTUNDER;
13931 case kOSKextLogProgressLevel:
13932 return VTYELLOW;
13933 case kOSKextLogStepLevel:
13934 return VTGREEN;
13935 case kOSKextLogDetailLevel:
13936 return VTCYAN;
13937 case kOSKextLogDebugLevel:
13938 return VTMAGENTA;
13939 default:
13940 return ""; // white
13941 }
13942 }
13943
13944 inline bool
13945 logSpecMatch(
13946 OSKextLogSpec msgLogSpec,
13947 OSKextLogSpec logFilter)
13948 {
13949 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
13950 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
13951 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
13952
13953 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
13954 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
13955 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
13956
13957 /* Explicit messages always get logged.
13958 */
13959 if (msgLevel == kOSKextLogExplicitLevel) {
13960 return true;
13961 }
13962
13963 /* Warnings and errors are logged regardless of the flags.
13964 */
13965 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
13966 return true;
13967 }
13968
13969 /* A verbose message that isn't for a logging-enabled kext and isn't global
13970 * does *not* get logged.
13971 */
13972 if (!msgKextGlobal && !filterKextGlobal) {
13973 return false;
13974 }
13975
13976 /* Warnings and errors are logged regardless of the flags.
13977 * All other messages must fit the flags and
13978 * have a level at or below the filter.
13979 *
13980 */
13981 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
13982 return true;
13983 }
13984 return false;
13985 }
13986
13987 extern "C" {
13988 void
13989 OSKextLog(
13990 OSKext * aKext,
13991 OSKextLogSpec msgLogSpec,
13992 const char * format, ...)
13993 {
13994 va_list argList;
13995
13996 va_start(argList, format);
13997 OSKextVLog(aKext, msgLogSpec, format, argList);
13998 va_end(argList);
13999 }
14000
14001 void
14002 OSKextVLog(
14003 OSKext * aKext,
14004 OSKextLogSpec msgLogSpec,
14005 const char * format,
14006 va_list srcArgList)
14007 {
14008 extern int disableConsoleOutput;
14009
14010 bool logForKernel = false;
14011 bool logForUser = false;
14012 va_list argList;
14013 char stackBuffer[120];
14014 uint32_t length = 0;
14015 char * allocBuffer = NULL; // must kfree
14016 OSSharedPtr<OSNumber> logSpecNum;
14017 OSSharedPtr<OSString> logString;
14018 char * buffer = stackBuffer; // do not free
14019
14020 IOLockLock(sKextLoggingLock);
14021
14022 /* Set the kext/global bit in the message spec if we have no
14023 * kext or if the kext requests logging.
14024 */
14025 if (!aKext || aKext->flags.loggingEnabled) {
14026 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
14027 }
14028
14029 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
14030 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14031 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
14032 }
14033
14034 if (!(logForKernel || logForUser)) {
14035 goto finish;
14036 }
14037
14038 /* No goto from here until past va_end()!
14039 */
14040 va_copy(argList, srcArgList);
14041 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
14042 va_end(argList);
14043
14044 if (length + 1 >= sizeof(stackBuffer)) {
14045 allocBuffer = (char *)kheap_alloc_tag(KHEAP_TEMP,
14046 length + 1, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14047 if (!allocBuffer) {
14048 goto finish;
14049 }
14050
14051 /* No goto from here until past va_end()!
14052 */
14053 va_copy(argList, srcArgList);
14054 vsnprintf(allocBuffer, length + 1, format, argList);
14055 va_end(argList);
14056
14057 buffer = allocBuffer;
14058 }
14059
14060 /* If user space wants the log message, queue it up.
14061 */
14062 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
14063 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
14064 logString = OSString::withCString(buffer);
14065 if (logSpecNum && logString) {
14066 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
14067 sUserSpaceLogMessageArray->setObject(logString.get());
14068 }
14069 }
14070
14071 /* Always log messages from the kernel according to the kernel's
14072 * log flags.
14073 */
14074 if (logForKernel) {
14075 /* If we are in console mode and have a custom log filter,
14076 * colorize the log message.
14077 */
14078 if (!disableConsoleOutput && sBootArgLogFilterFound) {
14079 const char * color = ""; // do not free
14080 color = colorForFlags(msgLogSpec);
14081 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14082 buffer, color[0] ? VTRESET : "");
14083 } else {
14084 printf("%s\n", buffer);
14085 }
14086 }
14087
14088 finish:
14089 IOLockUnlock(sKextLoggingLock);
14090
14091 if (allocBuffer) {
14092 kheap_free(KHEAP_TEMP, allocBuffer, (length + 1) * sizeof(char));
14093 }
14094 return;
14095 }
14096
14097 #if KASLR_IOREG_DEBUG
14098
14099 #define IOLOG_INDENT( the_indention ) \
14100 { \
14101 int i; \
14102 for ( i = 0; i < (the_indention); i++ ) { \
14103 IOLog(" "); \
14104 } \
14105 }
14106
14107 extern vm_offset_t vm_kernel_stext;
14108 extern vm_offset_t vm_kernel_etext;
14109 extern mach_vm_offset_t kext_alloc_base;
14110 extern mach_vm_offset_t kext_alloc_max;
14111
14112 bool ScanForAddrInObject(OSObject * theObject,
14113 int indent );
14114
14115 bool
14116 ScanForAddrInObject(OSObject * theObject,
14117 int indent)
14118 {
14119 const OSMetaClass * myTypeID;
14120 OSSharedPtr<OSCollectionIterator> myIter;
14121 OSSymbol * myKey;
14122 OSObject * myValue;
14123 bool myResult = false;
14124
14125 if (theObject == NULL) {
14126 IOLog("%s: theObject is NULL \n",
14127 __FUNCTION__);
14128 return myResult;
14129 }
14130
14131 myTypeID = OSTypeIDInst(theObject);
14132
14133 if (myTypeID == OSTypeID(OSDictionary)) {
14134 OSDictionary * myDictionary;
14135
14136 myDictionary = OSDynamicCast(OSDictionary, theObject);
14137 myIter = OSCollectionIterator::withCollection( myDictionary );
14138 if (myIter == NULL) {
14139 return myResult;
14140 }
14141
14142 // !! reset the iterator
14143 myIter->reset();
14144
14145 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14146 bool myTempResult;
14147
14148 myValue = myDictionary->getObject(myKey);
14149 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14150 if (myTempResult) {
14151 // if we ever get a true result return true
14152 myResult = true;
14153 IOLOG_INDENT(indent);
14154 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14155 }
14156 }
14157
14158 // !! release the iterator
14159 myIter.reset();
14160 } else if (myTypeID == OSTypeID(OSArray)) {
14161 OSArray * myArray;
14162
14163 myArray = OSDynamicCast(OSArray, theObject);
14164 myIter = OSCollectionIterator::withCollection(myArray);
14165 if (myIter == NULL) {
14166 return myResult;
14167 }
14168 // !! reset the iterator
14169 myIter->reset();
14170
14171 while ((myValue = myIter->getNextObject())) {
14172 bool myTempResult;
14173 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14174 if (myTempResult) {
14175 // if we ever get a true result return true
14176 myResult = true;
14177 IOLOG_INDENT(indent);
14178 IOLog("OSArray: \n");
14179 }
14180 }
14181 // !! release the iterator
14182 myIter.reset();
14183 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14184 // should we look for addresses in strings?
14185 } else if (myTypeID == OSTypeID(OSData)) {
14186 void * * myPtrPtr;
14187 unsigned int myLen;
14188 OSData * myDataObj;
14189
14190 myDataObj = OSDynamicCast(OSData, theObject);
14191 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14192 myLen = myDataObj->getLength();
14193
14194 if (myPtrPtr && myLen && myLen > 7) {
14195 int i;
14196 int myPtrCount = (myLen / sizeof(void *));
14197
14198 for (i = 0; i < myPtrCount; i++) {
14199 UInt64 numberValue = (UInt64) * (myPtrPtr);
14200
14201 if (kext_alloc_max != 0 &&
14202 numberValue >= kext_alloc_base &&
14203 numberValue < kext_alloc_max) {
14204 OSSharedPtr<OSKext> myKext;
14205 // IOLog("found OSData %p in kext map %p to %p \n",
14206 // *(myPtrPtr),
14207 // (void *) kext_alloc_base,
14208 // (void *) kext_alloc_max);
14209
14210 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14211 if (myKext) {
14212 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14213 *(myPtrPtr),
14214 myKext->getIdentifierCString());
14215 }
14216 myResult = true;
14217 }
14218 if (vm_kernel_etext != 0 &&
14219 numberValue >= vm_kernel_stext &&
14220 numberValue < vm_kernel_etext) {
14221 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14222 *(myPtrPtr),
14223 (void *) vm_kernel_stext,
14224 (void *) vm_kernel_etext);
14225 myResult = true;
14226 }
14227 myPtrPtr++;
14228 }
14229 }
14230 } else if (myTypeID == OSTypeID(OSBoolean)) {
14231 // do nothing here...
14232 } else if (myTypeID == OSTypeID(OSNumber)) {
14233 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14234
14235 UInt64 numberValue = number->unsigned64BitValue();
14236
14237 if (kext_alloc_max != 0 &&
14238 numberValue >= kext_alloc_base &&
14239 numberValue < kext_alloc_max) {
14240 OSSharedPtr<OSKext> myKext;
14241 IOLog("found OSNumber in kext map %p to %p \n",
14242 (void *) kext_alloc_base,
14243 (void *) kext_alloc_max);
14244 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14245
14246 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14247 if (myKext) {
14248 IOLog("found in kext \"%s\" \n",
14249 myKext->getIdentifierCString());
14250 }
14251
14252 myResult = true;
14253 }
14254 if (vm_kernel_etext != 0 &&
14255 numberValue >= vm_kernel_stext &&
14256 numberValue < vm_kernel_etext) {
14257 IOLog("found OSNumber in kernel text segment %p to %p \n",
14258 (void *) vm_kernel_stext,
14259 (void *) vm_kernel_etext);
14260 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14261 myResult = true;
14262 }
14263 }
14264 #if 0
14265 else {
14266 const OSMetaClass* myMetaClass = NULL;
14267
14268 myMetaClass = theObject->getMetaClass();
14269 if (myMetaClass) {
14270 IOLog("class %s \n", myMetaClass->getClassName());
14271 } else {
14272 IOLog("Unknown object \n" );
14273 }
14274 }
14275 #endif
14276
14277 return myResult;
14278 }
14279 #endif // KASLR_KEXT_DEBUG
14280 }; /* extern "C" */
14281
14282 #if PRAGMA_MARK
14283 #pragma mark Backtrace Dump & kmod_get_info() support
14284 #endif
14285 /*********************************************************************
14286 * This function must be safe to call in panic context.
14287 *********************************************************************/
14288 /* static */
14289 void
14290 OSKext::printKextsInBacktrace(
14291 vm_offset_t * addr __unused,
14292 unsigned int cnt __unused,
14293 int (* printf_func)(const char *fmt, ...) __unused,
14294 uint32_t flags __unused)
14295 {
14296 addr64_t summary_page = 0;
14297 addr64_t last_summary_page = 0;
14298 bool found_kmod = false;
14299 u_int i = 0;
14300
14301 if (kPrintKextsLock & flags) {
14302 if (!sKextSummariesLock) {
14303 return;
14304 }
14305 IOLockLock(sKextSummariesLock);
14306 }
14307
14308 if (!gLoadedKextSummaries) {
14309 (*printf_func)(" can't perform kext scan: no kext summary");
14310 goto finish;
14311 }
14312
14313 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14314 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14315 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14316 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14317 (*printf_func)(" can't perform kext scan: "
14318 "missing kext summary page %p", summary_page);
14319 goto finish;
14320 }
14321 }
14322
14323 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14324 OSKextLoadedKextSummary * summary;
14325
14326 summary = gLoadedKextSummaries->summaries + i;
14327 if (!summary->address) {
14328 continue;
14329 }
14330
14331 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14332 continue;
14333 }
14334
14335 if (!found_kmod) {
14336 if (!(kPrintKextsTerse & flags)) {
14337 (*printf_func)(" Kernel Extensions in backtrace:\n");
14338 }
14339 found_kmod = true;
14340 }
14341
14342 printSummary(summary, printf_func, flags);
14343 }
14344
14345 finish:
14346 if (kPrintKextsLock & flags) {
14347 IOLockUnlock(sKextSummariesLock);
14348 }
14349
14350 return;
14351 }
14352
14353 /*********************************************************************
14354 * This function must be safe to call in panic context.
14355 *********************************************************************/
14356 /* static */
14357 boolean_t
14358 OSKext::summaryIsInBacktrace(
14359 OSKextLoadedKextSummary * summary,
14360 vm_offset_t * addr,
14361 unsigned int cnt)
14362 {
14363 u_int i = 0;
14364
14365 for (i = 0; i < cnt; i++) {
14366 vm_offset_t kscan_addr = addr[i];
14367 #if __has_feature(ptrauth_calls)
14368 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14369 #endif /* __has_feature(ptrauth_calls) */
14370 if ((kscan_addr >= summary->text_exec_address) &&
14371 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
14372 return TRUE;
14373 }
14374 }
14375
14376 return FALSE;
14377 }
14378
14379 /*
14380 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14381 * sKextSummariesLock held.
14382 */
14383 OSKextLoadedKextSummary *
14384 OSKext::summaryForAddress(uintptr_t addr)
14385 {
14386 #if __has_feature(ptrauth_calls)
14387 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14388 #endif /* __has_feature(ptrauth_calls) */
14389 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14390 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14391 if (!summary->address) {
14392 continue;
14393 }
14394
14395 #if VM_MAPPED_KEXTS
14396 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14397 * support split kexts, but we also may unmap the kexts, which can
14398 * race with the above codepath (see OSKext::unload). As such,
14399 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14400 */
14401 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14402 return summary;
14403 }
14404 #else
14405 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14406 kernel_segment_command_t *seg;
14407
14408 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14409 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14410 return summary;
14411 }
14412 }
14413 #endif
14414 }
14415
14416 /* addr did not map to any kext */
14417 return NULL;
14418 }
14419
14420 /* static */
14421 void *
14422 OSKext::kextForAddress(const void *address)
14423 {
14424 void * image = NULL;
14425 OSKextActiveAccount * active;
14426 OSKext * kext = NULL;
14427 uint32_t baseIdx;
14428 uint32_t lim;
14429 uintptr_t addr = (uintptr_t) address;
14430 size_t i;
14431
14432 if (!addr) {
14433 return NULL;
14434 }
14435 #if __has_feature(ptrauth_calls)
14436 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14437 #endif /* __has_feature(ptrauth_calls) */
14438
14439 if (sKextAccountsCount) {
14440 IOSimpleLockLock(sKextAccountsLock);
14441 // bsearch sKextAccounts list
14442 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14443 active = &sKextAccounts[baseIdx + (lim >> 1)];
14444 if ((addr >= active->address) && (addr < active->address_end)) {
14445 kext = active->account->kext;
14446 if (kext && kext->kmod_info) {
14447 image = (void *) kext->kmod_info->address;
14448 }
14449 break;
14450 } else if (addr > active->address) {
14451 // move right
14452 baseIdx += (lim >> 1) + 1;
14453 lim--;
14454 }
14455 // else move left
14456 }
14457 IOSimpleLockUnlock(sKextAccountsLock);
14458 }
14459 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14460 image = (void *) &_mh_execute_header;
14461 }
14462 if (!image && gLoadedKextSummaries) {
14463 IOLockLock(sKextSummariesLock);
14464 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14465 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14466 if (addr >= summary->address && addr < summary->address + summary->size) {
14467 image = (void *)summary->address;
14468 }
14469 }
14470 IOLockUnlock(sKextSummariesLock);
14471 }
14472
14473 return image;
14474 }
14475
14476 /*
14477 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14478 * Safe to call in panic context.
14479 */
14480 static OSKextLoadedKextSummary *
14481 findSummary(uint32_t tagID)
14482 {
14483 OSKextLoadedKextSummary * summary;
14484 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14485 summary = gLoadedKextSummaries->summaries + i;
14486 if (summary->loadTag == tagID) {
14487 return summary;
14488 }
14489 }
14490 return NULL;
14491 }
14492
14493 /*********************************************************************
14494 * This function must be safe to call in panic context.
14495 *********************************************************************/
14496 void
14497 OSKext::printSummary(
14498 OSKextLoadedKextSummary * summary,
14499 int (* printf_func)(const char *fmt, ...),
14500 uint32_t flags)
14501 {
14502 kmod_reference_t * kmod_ref = NULL;
14503 uuid_string_t uuid;
14504 char version[kOSKextVersionMaxLength];
14505 uint64_t tmpAddr;
14506 uint64_t tmpSize;
14507 OSKextLoadedKextSummary *dependencySummary;
14508
14509 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14510 strlcpy(version, "unknown version", sizeof(version));
14511 }
14512 (void) uuid_unparse(summary->uuid, uuid);
14513
14514 #if defined(__arm__) || defined(__arm64__)
14515 tmpAddr = summary->text_exec_address;
14516 tmpSize = summary->text_exec_size;
14517 #else
14518 tmpAddr = summary->address;
14519 tmpSize = summary->size;
14520 #endif
14521 if (kPrintKextsUnslide & flags) {
14522 tmpAddr = ml_static_unslide(tmpAddr);
14523 }
14524 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14525 (kPrintKextsTerse & flags) ? "" : " ",
14526 summary->name, version, uuid,
14527 tmpAddr, tmpAddr + tmpSize - 1);
14528
14529 if (kPrintKextsTerse & flags) {
14530 return;
14531 }
14532
14533 /* print dependency info */
14534 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14535 kmod_ref;
14536 kmod_ref = kmod_ref->next) {
14537 kmod_info_t * rinfo;
14538
14539 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14540 (*printf_func)(" kmod dependency scan stopped "
14541 "due to missing dependency page: %p\n",
14542 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14543 break;
14544 }
14545 rinfo = kmod_ref->info;
14546
14547 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14548 (*printf_func)(" kmod dependency scan stopped "
14549 "due to missing kmod page: %p\n",
14550 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14551 break;
14552 }
14553
14554 if (!rinfo->address) {
14555 continue; // skip fake entries for built-ins
14556 }
14557
14558 dependencySummary = findSummary(rinfo->id);
14559 uuid[0] = 0x00;
14560 tmpAddr = rinfo->address;
14561 tmpSize = rinfo->size;
14562 if (dependencySummary) {
14563 (void) uuid_unparse(dependencySummary->uuid, uuid);
14564 #if defined(__arm__) || defined(__arm64__)
14565 tmpAddr = dependencySummary->text_exec_address;
14566 tmpSize = dependencySummary->text_exec_size;
14567 #endif
14568 }
14569
14570 if (kPrintKextsUnslide & flags) {
14571 tmpAddr = ml_static_unslide(tmpAddr);
14572 }
14573 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14574 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
14575 }
14576 return;
14577 }
14578
14579
14580 #if !defined(__arm__) && !defined(__arm64__)
14581 /*******************************************************************************
14582 * substitute() looks at an input string (a pointer within a larger buffer)
14583 * for a match to a substring, and on match it writes the marker & substitution
14584 * character to an output string, updating the scan (from) and
14585 * output (to) indexes as appropriate.
14586 *******************************************************************************/
14587 static int substitute(
14588 const char * scan_string,
14589 char * string_out,
14590 uint32_t * to_index,
14591 uint32_t * from_index,
14592 const char * substring,
14593 char marker,
14594 char substitution);
14595
14596 /* string_out must be at least KMOD_MAX_NAME bytes.
14597 */
14598 static int
14599 substitute(
14600 const char * scan_string,
14601 char * string_out,
14602 uint32_t * to_index,
14603 uint32_t * from_index,
14604 const char * substring,
14605 char marker,
14606 char substitution)
14607 {
14608 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
14609
14610 /* On a substring match, append the marker (if there is one) and then
14611 * the substitution character, updating the output (to) index accordingly.
14612 * Then update the input (from) length by the length of the substring
14613 * that got replaced.
14614 */
14615 if (!strncmp(scan_string, substring, substring_length)) {
14616 if (marker) {
14617 string_out[(*to_index)++] = marker;
14618 }
14619 string_out[(*to_index)++] = substitution;
14620 (*from_index) += substring_length;
14621 return 1;
14622 }
14623 return 0;
14624 }
14625
14626 /*******************************************************************************
14627 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14628 * KMOD_MAX_NAME characters and performs various substitutions of common
14629 * prefixes & substrings as defined by tables in kext_panic_report.h.
14630 *******************************************************************************/
14631 static void compactIdentifier(
14632 const char * identifier,
14633 char * identifier_out,
14634 char ** identifier_out_end);
14635
14636 static void
14637 compactIdentifier(
14638 const char * identifier,
14639 char * identifier_out,
14640 char ** identifier_out_end)
14641 {
14642 uint32_t from_index, to_index;
14643 uint32_t scan_from_index = 0;
14644 uint32_t scan_to_index = 0;
14645 subs_entry_t * subs_entry = NULL;
14646 int did_sub = 0;
14647
14648 from_index = to_index = 0;
14649 identifier_out[0] = '\0';
14650
14651 /* Replace certain identifier prefixes with shorter @+character sequences.
14652 * Check the return value of substitute() so we only replace the prefix.
14653 */
14654 for (subs_entry = &kext_identifier_prefix_subs[0];
14655 subs_entry->substring && !did_sub;
14656 subs_entry++) {
14657 did_sub = substitute(identifier, identifier_out,
14658 &scan_to_index, &scan_from_index,
14659 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14660 }
14661 did_sub = 0;
14662
14663 /* Now scan through the identifier looking for the common substrings
14664 * and replacing them with shorter !+character sequences via substitute().
14665 */
14666 for (/* see above */;
14667 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14668 /* see loop */) {
14669 const char * scan_string = &identifier[scan_from_index];
14670
14671 did_sub = 0;
14672
14673 if (scan_from_index) {
14674 for (subs_entry = &kext_identifier_substring_subs[0];
14675 subs_entry->substring && !did_sub;
14676 subs_entry++) {
14677 did_sub = substitute(scan_string, identifier_out,
14678 &scan_to_index, &scan_from_index,
14679 subs_entry->substring, '!', subs_entry->substitute);
14680 }
14681 }
14682
14683 /* If we didn't substitute, copy the input character to the output.
14684 */
14685 if (!did_sub) {
14686 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14687 }
14688 }
14689
14690 identifier_out[scan_to_index] = '\0';
14691 if (identifier_out_end) {
14692 *identifier_out_end = &identifier_out[scan_to_index];
14693 }
14694
14695 return;
14696 }
14697 #endif /* !defined(__arm__) && !defined(__arm64__) */
14698
14699 /*******************************************************************************
14700 * assemble_identifier_and_version() adds to a string buffer a compacted
14701 * bundle identifier followed by a version string.
14702 *******************************************************************************/
14703
14704 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14705 */
14706 static size_t assemble_identifier_and_version(
14707 kmod_info_t * kmod_info,
14708 char * identPlusVers,
14709 size_t bufSize);
14710
14711 static size_t
14712 assemble_identifier_and_version(
14713 kmod_info_t * kmod_info,
14714 char * identPlusVers,
14715 size_t bufSize)
14716 {
14717 size_t result = 0;
14718
14719 #if defined(__arm__) || defined(__arm64__)
14720 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14721 #else
14722 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14723 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
14724 #endif
14725 identPlusVers[result++] = '\t'; // increment for real char
14726 identPlusVers[result] = '\0'; // don't increment for nul char
14727 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14728 if (result >= bufSize) {
14729 identPlusVers[bufSize - 1] = '\0';
14730 result = bufSize - 1;
14731 }
14732
14733 return result;
14734 }
14735
14736 /*******************************************************************************
14737 * Assumes sKextLock is held.
14738 *******************************************************************************/
14739 /* static */
14740 int
14741 OSKext::saveLoadedKextPanicListTyped(
14742 const char * prefix,
14743 int invertFlag,
14744 int libsFlag,
14745 char * paniclist,
14746 uint32_t list_size)
14747 {
14748 int result = -1;
14749 unsigned int count, i;
14750
14751 count = sLoadedKexts->getCount();
14752 if (!count) {
14753 goto finish;
14754 }
14755
14756 i = count - 1;
14757 do {
14758 OSObject * rawKext = sLoadedKexts->getObject(i);
14759 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14760 int match;
14761 size_t identPlusVersLength;
14762 size_t tempLen;
14763 char identPlusVers[2 * KMOD_MAX_NAME];
14764
14765 if (!rawKext) {
14766 printf("OSKext::saveLoadedKextPanicListTyped - "
14767 "NULL kext in loaded kext list; continuing\n");
14768 continue;
14769 }
14770
14771 if (!theKext) {
14772 printf("OSKext::saveLoadedKextPanicListTyped - "
14773 "Kext type cast failed in loaded kext list; continuing\n");
14774 continue;
14775 }
14776
14777 /* Skip all built-in kexts.
14778 */
14779 if (theKext->isKernelComponent()) {
14780 continue;
14781 }
14782
14783 kmod_info_t * kmod_info = theKext->kmod_info;
14784
14785 /* Filter for kmod name (bundle identifier).
14786 */
14787 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14788 if ((match && invertFlag) || (!match && !invertFlag)) {
14789 continue;
14790 }
14791
14792 /* Filter for libraries (kexts that have a compatible version).
14793 */
14794 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14795 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14796 continue;
14797 }
14798
14799 if (!kmod_info ||
14800 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14801 printf("kext scan stopped due to missing kmod_info page: %p\n",
14802 kmod_info);
14803 goto finish;
14804 }
14805
14806 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14807 identPlusVers,
14808 sizeof(identPlusVers));
14809 if (!identPlusVersLength) {
14810 printf("error saving loaded kext info\n");
14811 goto finish;
14812 }
14813
14814 /* make sure everything fits and we null terminate.
14815 */
14816 tempLen = strlcat(paniclist, identPlusVers, list_size);
14817 if (tempLen >= list_size) {
14818 // panic list is full, keep it and null terminate
14819 paniclist[list_size - 1] = 0x00;
14820 result = 0;
14821 goto finish;
14822 }
14823 tempLen = strlcat(paniclist, "\n", list_size);
14824 if (tempLen >= list_size) {
14825 // panic list is full, keep it and null terminate
14826 paniclist[list_size - 1] = 0x00;
14827 result = 0;
14828 goto finish;
14829 }
14830 } while (i--);
14831
14832 result = 0;
14833 finish:
14834
14835 return result;
14836 }
14837
14838 /*********************************************************************
14839 *********************************************************************/
14840 /* static */
14841 void
14842 OSKext::saveLoadedKextPanicList(void)
14843 {
14844 char * newlist = NULL;
14845 uint32_t newlist_size = 0;
14846
14847 newlist_size = KEXT_PANICLIST_SIZE;
14848 newlist = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, newlist_size,
14849 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14850
14851 if (!newlist) {
14852 OSKextLog(/* kext */ NULL,
14853 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14854 "Couldn't allocate kext panic log buffer.");
14855 goto finish;
14856 }
14857
14858 newlist[0] = '\0';
14859
14860 // non-"com.apple." kexts
14861 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14862 /* libs? */ -1, newlist, newlist_size) != 0) {
14863 goto finish;
14864 }
14865 // "com.apple." nonlibrary kexts
14866 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14867 /* libs? */ 0, newlist, newlist_size) != 0) {
14868 goto finish;
14869 }
14870 // "com.apple." library kexts
14871 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14872 /* libs? */ 1, newlist, newlist_size) != 0) {
14873 goto finish;
14874 }
14875
14876 if (loaded_kext_paniclist) {
14877 kheap_free(KHEAP_DATA_BUFFERS, loaded_kext_paniclist,
14878 loaded_kext_paniclist_size);
14879 }
14880 loaded_kext_paniclist = newlist;
14881 newlist = NULL;
14882 loaded_kext_paniclist_size = newlist_size;
14883
14884 finish:
14885 if (newlist) {
14886 kheap_free(KHEAP_TEMP, newlist, newlist_size);
14887 }
14888 return;
14889 }
14890
14891 /*********************************************************************
14892 * Assumes sKextLock is held.
14893 *********************************************************************/
14894 void
14895 OSKext::savePanicString(bool isLoading)
14896 {
14897 u_long len;
14898
14899 if (!kmod_info) {
14900 return; // do not goto finish here b/c of lock
14901 }
14902
14903 len = assemble_identifier_and_version( kmod_info,
14904 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14905 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14906 if (!len) {
14907 printf("error saving unloaded kext info\n");
14908 goto finish;
14909 }
14910
14911 if (isLoading) {
14912 last_loaded_strlen = len;
14913 last_loaded_address = (void *)kmod_info->address;
14914 last_loaded_size = kmod_info->size;
14915 clock_get_uptime(&last_loaded_timestamp);
14916 } else {
14917 last_unloaded_strlen = len;
14918 last_unloaded_address = (void *)kmod_info->address;
14919 last_unloaded_size = kmod_info->size;
14920 clock_get_uptime(&last_unloaded_timestamp);
14921 }
14922
14923 finish:
14924 return;
14925 }
14926
14927 /*********************************************************************
14928 *********************************************************************/
14929 /* static */
14930 void
14931 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
14932 {
14933 if (last_loaded_strlen) {
14934 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14935 AbsoluteTime_to_scalar(&last_loaded_timestamp),
14936 last_loaded_strlen, last_loaded_str_buf,
14937 last_loaded_address, last_loaded_size);
14938 }
14939
14940 if (last_unloaded_strlen) {
14941 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
14942 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
14943 last_unloaded_strlen, last_unloaded_str_buf,
14944 last_unloaded_address, last_unloaded_size);
14945 }
14946
14947 printf_func("loaded kexts:\n");
14948 if (loaded_kext_paniclist &&
14949 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
14950 loaded_kext_paniclist[0]) {
14951 printf_func("%.*s",
14952 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
14953 loaded_kext_paniclist);
14954 } else {
14955 printf_func("(none)\n");
14956 }
14957 return;
14958 }
14959
14960 /*********************************************************************
14961 * Assumes sKextLock is held.
14962 *********************************************************************/
14963 /* static */
14964 void
14965 OSKext::updateLoadedKextSummaries(void)
14966 {
14967 kern_return_t result = KERN_FAILURE;
14968 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
14969 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
14970 OSKext *aKext;
14971 vm_map_offset_t start, end;
14972 size_t summarySize = 0;
14973 size_t size;
14974 u_int count;
14975 u_int maxKexts;
14976 u_int i, j;
14977 OSKextActiveAccount * accountingList;
14978 OSKextActiveAccount * prevAccountingList;
14979 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
14980
14981 prevAccountingList = NULL;
14982 prevAccountingListCount = 0;
14983
14984 #if DEVELOPMENT || DEBUG
14985 if (IORecursiveLockHaveLock(sKextLock) == false) {
14986 panic("sKextLock must be held");
14987 }
14988 #endif
14989
14990 IOLockLock(sKextSummariesLock);
14991
14992 count = sLoadedKexts->getCount();
14993 for (i = 0, maxKexts = 0; i < count; ++i) {
14994 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14995 maxKexts += (aKext && aKext->isExecutable());
14996 }
14997
14998 if (!maxKexts) {
14999 goto finish;
15000 }
15001 if (maxKexts < kOSKextTypicalLoadCount) {
15002 maxKexts = kOSKextTypicalLoadCount;
15003 }
15004
15005 /* Calculate the size needed for the new summary headers.
15006 */
15007
15008 size = sizeof(*gLoadedKextSummaries);
15009 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
15010 size = round_page(size);
15011
15012 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
15013 if (gLoadedKextSummaries) {
15014 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
15015 gLoadedKextSummaries = NULL;
15016 gLoadedKextSummariesTimestamp = mach_absolute_time();
15017 sLoadedKextSummariesAllocSize = 0;
15018 }
15019 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
15020 if (result != KERN_SUCCESS) {
15021 goto finish;
15022 }
15023 summaryHeader = summaryHeaderAlloc;
15024 summarySize = size;
15025 } else {
15026 summaryHeader = gLoadedKextSummaries;
15027 summarySize = sLoadedKextSummariesAllocSize;
15028
15029 start = (vm_map_offset_t) summaryHeader;
15030 end = start + summarySize;
15031 result = vm_map_protect(kernel_map,
15032 start,
15033 end,
15034 VM_PROT_DEFAULT,
15035 FALSE);
15036 if (result != KERN_SUCCESS) {
15037 goto finish;
15038 }
15039 }
15040
15041 /* Populate the summary header.
15042 */
15043
15044 bzero(summaryHeader, summarySize);
15045 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
15046 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
15047
15048 /* Populate each kext summary.
15049 */
15050
15051 count = sLoadedKexts->getCount();
15052 accountingListAlloc = 0;
15053 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15054 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15055 if (!aKext || !aKext->isExecutable()) {
15056 continue;
15057 }
15058
15059 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
15060 summaryHeader->numSummaries++;
15061 accountingListAlloc++;
15062 }
15063
15064 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
15065 accountingListCount = 0;
15066 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15067 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15068 if (!aKext || !aKext->isExecutable()) {
15069 continue;
15070 }
15071
15072 OSKextActiveAccount activeAccount;
15073 aKext->updateActiveAccount(&activeAccount);
15074 // order by address
15075 for (idx = 0; idx < accountingListCount; idx++) {
15076 if (activeAccount.address < accountingList[idx].address) {
15077 break;
15078 }
15079 }
15080 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
15081 accountingList[idx] = activeAccount;
15082 accountingListCount++;
15083 }
15084 assert(accountingListCount == accountingListAlloc);
15085 /* Write protect the buffer and move it into place.
15086 */
15087
15088 start = (vm_map_offset_t) summaryHeader;
15089 end = start + summarySize;
15090
15091 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15092 if (result != KERN_SUCCESS) {
15093 goto finish;
15094 }
15095
15096 gLoadedKextSummaries = summaryHeader;
15097 gLoadedKextSummariesTimestamp = mach_absolute_time();
15098 sLoadedKextSummariesAllocSize = summarySize;
15099 summaryHeaderAlloc = NULL;
15100
15101 /* Call the magic breakpoint function through a static function pointer so
15102 * the compiler can't optimize the function away.
15103 */
15104 if (sLoadedKextSummariesUpdated) {
15105 (*sLoadedKextSummariesUpdated)();
15106 }
15107
15108 IOSimpleLockLock(sKextAccountsLock);
15109 prevAccountingList = sKextAccounts;
15110 prevAccountingListCount = sKextAccountsCount;
15111 sKextAccounts = accountingList;
15112 sKextAccountsCount = accountingListCount;
15113 IOSimpleLockUnlock(sKextAccountsLock);
15114
15115 finish:
15116 IOLockUnlock(sKextSummariesLock);
15117
15118 /* If we had to allocate a new buffer but failed to generate the summaries,
15119 * free that now.
15120 */
15121 if (summaryHeaderAlloc) {
15122 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15123 }
15124 if (prevAccountingList) {
15125 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15126 }
15127
15128 return;
15129 }
15130
15131 /*********************************************************************
15132 *********************************************************************/
15133 void
15134 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15135 {
15136 OSSharedPtr<OSData> uuid;
15137
15138 strlcpy(summary->name, getIdentifierCString(),
15139 sizeof(summary->name));
15140
15141 uuid = copyUUID();
15142 if (uuid) {
15143 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
15144 }
15145
15146 if (flags.builtin) {
15147 // this value will stop lldb from parsing the mach-o header
15148 // summary->address = UINT64_MAX;
15149 // summary->size = 0;
15150 summary->address = kmod_info->address;
15151 summary->size = kmod_info->size;
15152 } else {
15153 summary->address = kmod_info->address;
15154 summary->size = kmod_info->size;
15155 }
15156 summary->version = getVersion();
15157 summary->loadTag = kmod_info->id;
15158 summary->flags = 0;
15159 summary->reference_list = (uint64_t) kmod_info->reference_list;
15160
15161 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15162 if (summary->text_exec_address == 0) {
15163 // Fallback to __TEXT
15164 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15165 }
15166 return;
15167 }
15168
15169 /*********************************************************************
15170 *********************************************************************/
15171
15172 void
15173 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
15174 {
15175 kernel_mach_header_t *hdr = NULL;
15176 kernel_segment_command_t *seg = NULL;
15177
15178 bzero(accountp, sizeof(*accountp));
15179
15180 hdr = (kernel_mach_header_t *)kmod_info->address;
15181 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15182 /*
15183 * If this kext supports split segments (or is in a new
15184 * MH_FILESET kext collection), use the first
15185 * executable segment as the range for instructions
15186 * (and thus for backtracing.
15187 */
15188 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15189 if (seg->initprot & VM_PROT_EXECUTE) {
15190 break;
15191 }
15192 }
15193 }
15194 if (seg) {
15195 accountp->address = seg->vmaddr;
15196 if (accountp->address) {
15197 accountp->address_end = seg->vmaddr + seg->vmsize;
15198 }
15199 } else {
15200 /* For non-split kexts and for kexts without executable
15201 * segments, just use the kmod_info range (as the kext
15202 * is either all in one range or should not show up in
15203 * instruction backtraces).
15204 */
15205 accountp->address = kmod_info->address;
15206 if (accountp->address) {
15207 accountp->address_end = kmod_info->address + kmod_info->size;
15208 }
15209 }
15210
15211 accountp->account = this->account;
15212 }
15213
15214 bool
15215 OSKext::isDriverKit(void)
15216 {
15217 OSString *bundleType;
15218
15219 if (infoDict) {
15220 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15221 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15222 return TRUE;
15223 }
15224 }
15225 return FALSE;
15226 }
15227
15228 bool
15229 OSKext::isInFileset(void)
15230 {
15231 if (!kmod_info) {
15232 goto check_prelinked;
15233 }
15234
15235 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15236 return true;
15237 }
15238
15239 check_prelinked:
15240 if (isPrelinked()) {
15241 /*
15242 * If we haven't setup kmod_info yet, but we know
15243 * we're loading a prelinked kext in an MH_FILESET KC,
15244 * then return true
15245 */
15246 kc_format_t kc_format;
15247 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15248 return true;
15249 }
15250 }
15251 return false;
15252 }
15253
15254 bool
15255 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15256 {
15257 kern_return_t result;
15258 if (!super::init()) {
15259 return false;
15260 }
15261 if (seg == nullptr) {
15262 return false;
15263 }
15264 result = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&data, seg->vmsize, VM_KERN_MEMORY_KEXT);
15265 if (result != KERN_SUCCESS) {
15266 return false;
15267 }
15268 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15269 savedSegment = seg;
15270 vmsize = seg->vmsize;
15271 vmaddr = seg->vmaddr;
15272 return true;
15273 }
15274
15275 OSSharedPtr<OSKextSavedMutableSegment>
15276 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15277 {
15278 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15279 if (me && !me->initWithSegment(seg)) {
15280 return nullptr;
15281 }
15282 return me;
15283 }
15284
15285 void
15286 OSKextSavedMutableSegment::free(void)
15287 {
15288 if (data) {
15289 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15290 }
15291 }
15292
15293 vm_offset_t
15294 OSKextSavedMutableSegment::getVMAddr() const
15295 {
15296 return vmaddr;
15297 }
15298
15299 vm_offset_t
15300 OSKextSavedMutableSegment::getVMSize() const
15301 {
15302 return vmsize;
15303 }
15304
15305 OSReturn
15306 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15307 {
15308 if (seg != savedSegment) {
15309 return kOSKextReturnInvalidArgument;
15310 }
15311 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15312 return kOSKextReturnInvalidArgument;
15313 }
15314 memcpy((void *)seg->vmaddr, data, vmsize);
15315 return kOSReturnSuccess;
15316 }
15317
15318 extern "C" kern_return_t
15319 OSKextSetReceiptQueried(void)
15320 {
15321 OSKextLog(/* kext */ NULL,
15322 kOSKextLogStepLevel | kOSKextLogGeneralFlag,
15323 "Setting kext receipt as queried");
15324
15325 IOService::publishResource(kOSKextReceiptQueried, kOSBooleanTrue);
15326 return KERN_SUCCESS;
15327 }
15328
15329 extern "C" const vm_allocation_site_t *
15330 OSKextGetAllocationSiteForCaller(uintptr_t address)
15331 {
15332 OSKextActiveAccount * active;
15333 vm_allocation_site_t * site;
15334 vm_allocation_site_t * releasesite;
15335
15336 uint32_t baseIdx;
15337 uint32_t lim;
15338 #if __has_feature(ptrauth_calls)
15339 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15340 #endif /* __has_feature(ptrauth_calls) */
15341
15342 IOSimpleLockLock(sKextAccountsLock);
15343 site = releasesite = NULL;
15344
15345 // bsearch sKextAccounts list
15346 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15347 active = &sKextAccounts[baseIdx + (lim >> 1)];
15348 if ((address >= active->address) && (address < active->address_end)) {
15349 site = &active->account->site;
15350 if (!site->tag) {
15351 vm_tag_alloc_locked(site, &releasesite);
15352 }
15353 break;
15354 } else if (address > active->address) {
15355 // move right
15356 baseIdx += (lim >> 1) + 1;
15357 lim--;
15358 }
15359 // else move left
15360 }
15361 IOSimpleLockUnlock(sKextAccountsLock);
15362 if (releasesite) {
15363 kern_allocation_name_release(releasesite);
15364 }
15365
15366 return site;
15367 }
15368
15369 extern "C" uint32_t
15370 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
15371 {
15372 OSKextAccount * account = (typeof(account))site;
15373 const char * kname;
15374
15375 if (name) {
15376 if (account->kext) {
15377 kname = account->kext->getIdentifierCString();
15378 } else {
15379 kname = "<>";
15380 }
15381 strlcpy(name, kname, namelen);
15382 }
15383
15384 return account->loadTag;
15385 }
15386
15387 extern "C" void
15388 OSKextFreeSite(vm_allocation_site_t * site)
15389 {
15390 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15391 IODelete(freeAccount, OSKextAccount, 1);
15392 }
15393
15394 /*********************************************************************
15395 *********************************************************************/
15396
15397 #if CONFIG_IMAGEBOOT
15398 int
15399 OSKextGetUUIDForName(const char *name, uuid_t uuid)
15400 {
15401 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
15402 if (!kext) {
15403 return 1;
15404 }
15405
15406 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
15407 if (uuid_data) {
15408 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
15409 return 0;
15410 }
15411
15412 return 1;
15413 }
15414 #endif
15415
15416 static int
15417 sysctl_willuserspacereboot
15418 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15419 {
15420 int new_value = 0, old_value = 0, changed = 0;
15421 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15422 if (error) {
15423 return error;
15424 }
15425 if (changed) {
15426 OSKext::willUserspaceReboot();
15427 }
15428 return 0;
15429 }
15430
15431 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15432 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15433 NULL, 0, sysctl_willuserspacereboot, "I", "");