]> git.saurik.com Git - apple/xnu.git/blob - libkern/c++/OSKext.cpp
xnu-7195.81.3.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_to_remove = NULL;
979
980 const char __unused * dt_segment_name = NULL;
981 void __unused * segment_paddress = NULL;
982 int __unused segment_size = 0;
983
984 OSKextLog(/* kext */ NULL,
985 kOSKextLogProgressLevel |
986 kOSKextLogGeneralFlag,
987 "Jettisoning kext bootstrap segments.");
988
989 /*
990 * keep the linkedit segment around when booted from a new MH_FILESET
991 * KC because all the kexts shared a linkedit segment.
992 */
993 kc_format_t kc_format;
994 if (!PE_get_primary_kc_format(&kc_format)) {
995 OSKextLog(/* kext */ NULL,
996 kOSKextLogErrorLevel |
997 kOSKextLogGeneralFlag,
998 "Unable to determine primary KC format");
999 }
1000
1001 /*****
1002 * Dispose of unnecessary stuff that the booter didn't need to load.
1003 */
1004 dt_result = IODTGetLoaderInfo(dt_kernel_header_name,
1005 (void **)&dt_mach_header, &dt_mach_header_size);
1006 if (dt_result == 0 && dt_mach_header) {
1007 IODTFreeLoaderInfo(dt_kernel_header_name, (void *)dt_mach_header,
1008 round_page_32(dt_mach_header_size));
1009 }
1010 dt_result = IODTGetLoaderInfo(dt_kernel_symtab_name,
1011 (void **)&dt_symtab, &dt_symtab_size);
1012 if (dt_result == 0 && dt_symtab) {
1013 IODTFreeLoaderInfo(dt_kernel_symtab_name, (void *)dt_symtab,
1014 round_page_32(dt_symtab_size));
1015 }
1016
1017 /*****
1018 * KLD bootstrap segment.
1019 */
1020 // xxx - should rename KLD segment
1021 seg_to_remove = getsegbyname("__KLD");
1022 if (seg_to_remove) {
1023 OSRuntimeUnloadCPPForSegment(seg_to_remove);
1024 }
1025
1026 #if __arm__ || __arm64__
1027 /* Free the memory that was set up by bootx.
1028 */
1029 dt_segment_name = "Kernel-__KLD";
1030 if (0 == IODTGetLoaderInfo(dt_segment_name, &segment_paddress, &segment_size)) {
1031 /* We cannot free this with KTRR enabled, as we cannot
1032 * update the permissions on the KLD range this late
1033 * in the boot process.
1034 */
1035 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1036 (int)segment_size);
1037 }
1038 #elif __i386__ || __x86_64__
1039 /* On x86, use the mapping data from the segment load command to
1040 * unload KLD directly.
1041 * This may invalidate any assumptions about "avail_start"
1042 * defining the lower bound for valid physical addresses.
1043 */
1044 if (seg_to_remove && seg_to_remove->vmaddr && seg_to_remove->vmsize) {
1045 bzero((void *)seg_to_remove->vmaddr, seg_to_remove->vmsize);
1046 ml_static_mfree(seg_to_remove->vmaddr, seg_to_remove->vmsize);
1047 }
1048 #else
1049 #error arch
1050 #endif
1051
1052 seg_to_remove = NULL;
1053
1054 /*****
1055 * Prelinked kernel's symtab (if there is one).
1056 */
1057 if (kc_format != KCFormatFileset) {
1058 kernel_section_t * sect;
1059 sect = getsectbyname("__PRELINK", "__symtab");
1060 if (sect && sect->addr && sect->size) {
1061 ml_static_mfree(sect->addr, sect->size);
1062 }
1063 }
1064
1065 seg_to_remove = (kernel_segment_command_t *)getsegbyname("__LINKEDIT");
1066
1067 /* kxld always needs the kernel's __LINKEDIT segment, but we can make it
1068 * pageable, unless keepsyms is set. To do that, we have to copy it from
1069 * its booter-allocated memory, free the booter memory, reallocate proper
1070 * managed memory, then copy the segment back in.
1071 *
1072 * NOTE: This optimization is not valid for fileset KCs because each
1073 * fileset entry (kext or xnu) in an MH_FILESET has a LINKEDIT segment
1074 * that points to one fileset-global LINKEDIT segment. This
1075 * optimization is also only valid for platforms that support vm
1076 * mapped kexts or mapped kext collections (pageable KCs)
1077 */
1078 #if VM_MAPPED_KEXTS
1079 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1080 kern_return_t mem_result;
1081 void *seg_copy = NULL;
1082 void *seg_data = NULL;
1083 vm_map_offset_t seg_offset = 0;
1084 vm_map_offset_t seg_copy_offset = 0;
1085 vm_map_size_t seg_length = 0;
1086
1087 seg_data = (void *) seg_to_remove->vmaddr;
1088 seg_offset = (vm_map_offset_t) seg_to_remove->vmaddr;
1089 seg_length = (vm_map_size_t) seg_to_remove->vmsize;
1090
1091 /* Allocate space for the LINKEDIT copy.
1092 */
1093 mem_result = kmem_alloc(kernel_map, (vm_offset_t *) &seg_copy,
1094 seg_length, VM_KERN_MEMORY_KEXT);
1095 if (mem_result != KERN_SUCCESS) {
1096 OSKextLog(/* kext */ NULL,
1097 kOSKextLogErrorLevel |
1098 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1099 "Can't copy __LINKEDIT segment for VM reassign.");
1100 return result;
1101 }
1102 seg_copy_offset = (vm_map_offset_t) seg_copy;
1103
1104 /* Copy it out.
1105 */
1106 memcpy(seg_copy, seg_data, seg_length);
1107
1108 /* Dump the booter memory.
1109 */
1110 ml_static_mfree(seg_offset, seg_length);
1111
1112 /* Set up the VM region.
1113 */
1114 mem_result = vm_map_enter_mem_object(
1115 kernel_map,
1116 &seg_offset,
1117 seg_length, /* mask */ 0,
1118 VM_FLAGS_FIXED | VM_FLAGS_OVERWRITE,
1119 VM_MAP_KERNEL_FLAGS_NONE,
1120 VM_KERN_MEMORY_NONE,
1121 (ipc_port_t)NULL,
1122 (vm_object_offset_t) 0,
1123 /* copy */ FALSE,
1124 /* cur_protection */ VM_PROT_READ | VM_PROT_WRITE,
1125 /* max_protection */ VM_PROT_ALL,
1126 /* inheritance */ VM_INHERIT_DEFAULT);
1127 if ((mem_result != KERN_SUCCESS) ||
1128 (seg_offset != (vm_map_offset_t) seg_data)) {
1129 OSKextLog(/* kext */ NULL,
1130 kOSKextLogErrorLevel |
1131 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1132 "Can't create __LINKEDIT VM entry at %p, length 0x%llx (error 0x%x).",
1133 seg_data, seg_length, mem_result);
1134 return result;
1135 }
1136
1137 /* And copy it back.
1138 */
1139 memcpy(seg_data, seg_copy, seg_length);
1140
1141 /* Free the copy.
1142 */
1143 kmem_free(kernel_map, seg_copy_offset, seg_length);
1144 } else if (!sKeepSymbols && kc_format == KCFormatFileset) {
1145 /* Remove the linkedit segment of the Boot KC */
1146 kernel_mach_header_t *mh = (kernel_mach_header_t *)PE_get_kc_header(KCKindPrimary);
1147 OSKext::jettisonFileSetLinkeditSegment(mh);
1148 }
1149 #else // !VM_MAPPED_KEXTS
1150 /*****
1151 * Dump the LINKEDIT segment, unless keepsyms is set.
1152 */
1153 if (!sKeepSymbols && kc_format != KCFormatFileset) {
1154 dt_segment_name = "Kernel-__LINKEDIT";
1155 if (0 == IODTGetLoaderInfo(dt_segment_name,
1156 &segment_paddress, &segment_size)) {
1157 #ifdef SECURE_KERNEL
1158 vm_offset_t vmaddr = ml_static_ptovirt((vm_offset_t)segment_paddress);
1159 bzero((void*)vmaddr, segment_size);
1160 #endif
1161 IODTFreeLoaderInfo(dt_segment_name, (void *)segment_paddress,
1162 (int)segment_size);
1163 }
1164 } else {
1165 OSKextLog(/* kext */ NULL,
1166 kOSKextLogBasicLevel |
1167 kOSKextLogGeneralFlag,
1168 "keepsyms boot arg specified; keeping linkedit segment for symbols.");
1169 }
1170 #endif // VM_MAPPED_KEXTS
1171
1172 seg_to_remove = NULL;
1173
1174 result = kOSReturnSuccess;
1175
1176 return result;
1177 }
1178
1179 #if CONFIG_KXLD
1180 /*********************************************************************
1181 *********************************************************************/
1182 void
1183 OSKext::flushNonloadedKexts(
1184 Boolean flushPrelinkedKexts)
1185 {
1186 OSSharedPtr<OSSet> keepKexts;
1187
1188 /* TODO: make this more efficient with MH_FILESET kexts */
1189
1190 // Do not unload prelinked kexts on arm because the kernelcache is not
1191 // structured in a way that allows them to be unmapped
1192 #if !defined(__x86_64__)
1193 flushPrelinkedKexts = false;
1194 #endif /* defined(__x86_64__) */
1195
1196 IORecursiveLockLock(sKextLock);
1197
1198 OSKextLog(/* kext */ NULL,
1199 kOSKextLogProgressLevel |
1200 kOSKextLogKextBookkeepingFlag,
1201 "Flushing nonloaded kexts and other unused data.");
1202
1203 OSKext::considerDestroyingLinkContext();
1204
1205 /* If we aren't flushing unused prelinked kexts, we have to put them
1206 * aside while we flush everything else so make a container for them.
1207 */
1208 keepKexts = OSSet::withCapacity(16);
1209 if (!keepKexts) {
1210 goto finish;
1211 }
1212
1213 /* Set aside prelinked kexts (in-use or not) and break
1214 * any lingering inter-kext references for nonloaded kexts
1215 * so they have min. retain counts.
1216 */
1217 {
1218 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1219 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1220 if (!thisKext) {
1221 return false;
1222 }
1223 if (!flushPrelinkedKexts && thisKext->isPrelinked()) {
1224 keepKexts->setObject(thisKext);
1225 } else if (!thisKext->declaresExecutable()) {
1226 /*
1227 * Don't unload codeless kexts, because they never appear in the loadedKexts array.
1228 * Requesting one from the IOKit daemon will load it and then immediately remove it by calling
1229 * flushNonloadedKexts().
1230 * And adding one to loadedKexts breaks code assuming they have kmod_info etc.
1231 */
1232 keepKexts->setObject(thisKext);
1233 } else if (thisKext->isInFileset()) {
1234 /* keep all kexts in the new MH_FILESET KC */
1235 keepKexts->setObject(thisKext);
1236 }
1237
1238 thisKext->flushDependencies(/* forceIfLoaded */ false);
1239 return false;
1240 });
1241 }
1242 /* Dump all the kexts in the ID dictionary; we'll repopulate it shortly.
1243 */
1244 sKextsByID->flushCollection();
1245
1246 /* Now put the loaded kexts back into the ID dictionary.
1247 */
1248 sLoadedKexts->iterateObjects(^bool (OSObject * obj) {
1249 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1250 if (!thisKext) {
1251 return false;
1252 }
1253 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1254 return false;
1255 });
1256
1257 /* Finally, put back the kept kexts if we saved any.
1258 */
1259 keepKexts->iterateObjects(^bool (OSObject * obj) {
1260 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1261 if (!thisKext) {
1262 return false;
1263 }
1264 sKextsByID->setObject(thisKext->getIdentifierCString(), thisKext);
1265 return false;
1266 });
1267
1268 finish:
1269 IORecursiveLockUnlock(sKextLock);
1270 return;
1271 }
1272 #else /* !CONFIG_KXLD */
1273
1274 void
1275 OSKext::flushNonloadedKexts(
1276 Boolean flushPrelinkedKexts __unused)
1277 {
1278 IORecursiveLockLock(sKextLock);
1279
1280 OSKextLog(/* kext */ NULL,
1281 kOSKextLogProgressLevel |
1282 kOSKextLogKextBookkeepingFlag,
1283 "Flushing dependency info for non-loaded kexts.");
1284
1285 /*
1286 * In a world where we don't dynamically link kexts, they all come
1287 * from a kext collection that's either in wired memory, or
1288 * wire-on-demand. We don't need to mess around with moving kexts in
1289 * and out of the sKextsByID array - they can all just stay there.
1290 * Here we just flush the dependency list for kexts that are not
1291 * loaded.
1292 */
1293 sKextsByID->iterateObjects(^bool (const OSSymbol * thisID __unused, OSObject * obj) {
1294 OSKext * thisKext = OSDynamicCast(OSKext, obj);
1295 if (!thisKext) {
1296 return false;
1297 }
1298 thisKext->flushDependencies(/* forceIfLoaded */ false);
1299 return false;
1300 });
1301
1302 IORecursiveLockUnlock(sKextLock);
1303 return;
1304 }
1305
1306 #endif /* CONFIG_KXLD */
1307
1308 /*********************************************************************
1309 *********************************************************************/
1310 /* static */
1311 void
1312 OSKext::setIOKitDaemonActive(bool active)
1313 {
1314 IOServiceTrace(IOSERVICE_KEXTD_ALIVE, 0, 0, 0, 0);
1315 IORecursiveLockLock(sKextLock);
1316 sIOKitDaemonActive = active;
1317 if (sKernelRequests->getCount()) {
1318 OSKext::pingIOKitDaemon();
1319 }
1320 IORecursiveLockUnlock(sKextLock);
1321
1322 return;
1323 }
1324
1325 /*********************************************************************
1326 * OSKextLib.cpp might need access to this someday but for now it's
1327 * private.
1328 *********************************************************************/
1329 extern "C" {
1330 extern void ipc_port_release_send(ipc_port_t);
1331 };
1332
1333 /* static */
1334 OSReturn
1335 OSKext::pingIOKitDaemon(void)
1336 {
1337 OSReturn result = kOSReturnError;
1338 #if !NO_KEXTD
1339 mach_port_t kextd_port = IPC_PORT_NULL;
1340
1341 if (!sIOKitDaemonActive) {
1342 result = kOSKextReturnDisabled; // basically unavailable
1343 goto finish;
1344 }
1345
1346 result = host_get_kextd_port(host_priv_self(), &kextd_port);
1347 if (result != KERN_SUCCESS || !IPC_PORT_VALID(kextd_port)) {
1348 OSKextLog(/* kext */ NULL,
1349 kOSKextLogErrorLevel |
1350 kOSKextLogIPCFlag,
1351 "Can't get " kIOKitDaemonName " port.");
1352 goto finish;
1353 }
1354
1355 result = kextd_ping(kextd_port);
1356 if (result != KERN_SUCCESS) {
1357 OSKextLog(/* kext */ NULL,
1358 kOSKextLogErrorLevel |
1359 kOSKextLogIPCFlag,
1360 kIOKitDaemonName " ping failed (0x%x).", (int)result);
1361 goto finish;
1362 }
1363
1364 finish:
1365 if (IPC_PORT_VALID(kextd_port)) {
1366 ipc_port_release_send(kextd_port);
1367 }
1368 #endif
1369
1370 return result;
1371 }
1372
1373 /*********************************************************************
1374 *********************************************************************/
1375 /* static */
1376 void
1377 OSKext::setDeferredLoadSucceeded(Boolean succeeded)
1378 {
1379 IORecursiveLockLock(sKextLock);
1380 sDeferredLoadSucceeded = succeeded;
1381 IORecursiveLockUnlock(sKextLock);
1382
1383 return;
1384 }
1385
1386 /*********************************************************************
1387 * Called from IOSystemShutdownNotification.
1388 *********************************************************************/
1389 /* static */
1390 void
1391 OSKext::willShutdown(void)
1392 {
1393 #if !NO_KEXTD
1394 OSReturn checkResult = kOSReturnError;
1395 #endif
1396 OSSharedPtr<OSDictionary> exitRequest;
1397
1398 IORecursiveLockLock(sKextLock);
1399
1400 OSKext::setLoadEnabled(false);
1401 OSKext::setUnloadEnabled(false);
1402 OSKext::setAutounloadsEnabled(false);
1403 OSKext::setKernelRequestsEnabled(false);
1404
1405 #if defined(__x86_64__) || defined(__i386__)
1406 if (IOPMRootDomainGetWillShutdown()) {
1407 OSKext::freeKCFileSetcontrol();
1408 }
1409 #endif // (__x86_64__) || defined(__i386__)
1410
1411 #if !NO_KEXTD
1412 OSKextLog(/* kext */ NULL,
1413 kOSKextLogProgressLevel |
1414 kOSKextLogGeneralFlag,
1415 "System shutdown; requesting immediate " kIOKitDaemonName " exit.");
1416
1417 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonExit,
1418 exitRequest);
1419 if (checkResult != kOSReturnSuccess) {
1420 goto finish;
1421 }
1422 if (!sKernelRequests->setObject(exitRequest.get())) {
1423 goto finish;
1424 }
1425
1426 OSKext::pingIOKitDaemon();
1427
1428 finish:
1429 #endif
1430
1431 IORecursiveLockUnlock(sKextLock);
1432 return;
1433 }
1434
1435 void
1436 OSKext::willUserspaceReboot(void)
1437 {
1438 OSKext::willShutdown();
1439 IOService::userSpaceWillReboot();
1440 gIOCatalogue->terminateDriversForUserspaceReboot();
1441 }
1442
1443 void
1444 OSKext::resetAfterUserspaceReboot(void)
1445 {
1446 OSSharedPtr<OSArray> arr = OSArray::withCapacity(1);
1447 IOService::updateConsoleUsers(arr.get(), 0, true /* after_userspace_reboot */);
1448
1449 IORecursiveLockLock(sKextLock);
1450 gIOCatalogue->resetAfterUserspaceReboot();
1451 IOService::userSpaceDidReboot();
1452 OSKext::setLoadEnabled(true);
1453 OSKext::setUnloadEnabled(true);
1454 OSKext::setAutounloadsEnabled(true);
1455 OSKext::setKernelRequestsEnabled(true);
1456 sOSKextWasResetAfterUserspaceReboot = true;
1457 IORecursiveLockUnlock(sKextLock);
1458 }
1459
1460 extern "C" void
1461 OSKextResetAfterUserspaceReboot(void)
1462 {
1463 OSKext::resetAfterUserspaceReboot();
1464 }
1465
1466 /*********************************************************************
1467 *********************************************************************/
1468 /* static */
1469 bool
1470 OSKext::getLoadEnabled(void)
1471 {
1472 bool result;
1473
1474 IORecursiveLockLock(sKextLock);
1475 result = sLoadEnabled;
1476 IORecursiveLockUnlock(sKextLock);
1477 return result;
1478 }
1479
1480 /*********************************************************************
1481 *********************************************************************/
1482 /* static */
1483 bool
1484 OSKext::setLoadEnabled(bool flag)
1485 {
1486 bool result;
1487
1488 IORecursiveLockLock(sKextLock);
1489 result = sLoadEnabled;
1490 sLoadEnabled = (flag ? true : false);
1491
1492 if (sLoadEnabled != result) {
1493 OSKextLog(/* kext */ NULL,
1494 kOSKextLogBasicLevel |
1495 kOSKextLogLoadFlag,
1496 "Kext loading now %sabled.", sLoadEnabled ? "en" : "dis");
1497 }
1498
1499 IORecursiveLockUnlock(sKextLock);
1500
1501 return result;
1502 }
1503
1504 /*********************************************************************
1505 *********************************************************************/
1506 /* static */
1507 bool
1508 OSKext::getUnloadEnabled(void)
1509 {
1510 bool result;
1511
1512 IORecursiveLockLock(sKextLock);
1513 result = sUnloadEnabled;
1514 IORecursiveLockUnlock(sKextLock);
1515 return result;
1516 }
1517
1518 /*********************************************************************
1519 *********************************************************************/
1520 /* static */
1521 bool
1522 OSKext::setUnloadEnabled(bool flag)
1523 {
1524 bool result;
1525
1526 IORecursiveLockLock(sKextLock);
1527 result = sUnloadEnabled;
1528 sUnloadEnabled = (flag ? true : false);
1529 IORecursiveLockUnlock(sKextLock);
1530
1531 if (sUnloadEnabled != result) {
1532 OSKextLog(/* kext */ NULL,
1533 kOSKextLogBasicLevel |
1534 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1535 "Kext unloading now %sabled.", sUnloadEnabled ? "en" : "dis");
1536 }
1537
1538 return result;
1539 }
1540
1541 /*********************************************************************
1542 * Do not call any function that takes sKextLock here!
1543 *********************************************************************/
1544 /* static */
1545 bool
1546 OSKext::getAutounloadEnabled(void)
1547 {
1548 bool result;
1549
1550 IORecursiveLockLock(sKextInnerLock);
1551 result = sAutounloadEnabled ? true : false;
1552 IORecursiveLockUnlock(sKextInnerLock);
1553 return result;
1554 }
1555
1556 /*********************************************************************
1557 * Do not call any function that takes sKextLock here!
1558 *********************************************************************/
1559 /* static */
1560 bool
1561 OSKext::setAutounloadsEnabled(bool flag)
1562 {
1563 bool result;
1564
1565 IORecursiveLockLock(sKextInnerLock);
1566
1567 result = sAutounloadEnabled;
1568 sAutounloadEnabled = (flag ? true : false);
1569 if (!sAutounloadEnabled && sUnloadCallout) {
1570 thread_call_cancel(sUnloadCallout);
1571 }
1572
1573 if (sAutounloadEnabled != result) {
1574 OSKextLog(/* kext */ NULL,
1575 kOSKextLogBasicLevel |
1576 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
1577 "Kext autounloading now %sabled.",
1578 sAutounloadEnabled ? "en" : "dis");
1579 }
1580
1581 IORecursiveLockUnlock(sKextInnerLock);
1582
1583 return result;
1584 }
1585
1586 /*********************************************************************
1587 *********************************************************************/
1588 /* instance method operating on OSKext field */
1589 bool
1590 OSKext::setAutounloadEnabled(bool flag)
1591 {
1592 bool result = flags.autounloadEnabled ? true : false;
1593 flags.autounloadEnabled = flag ? 1 : 0;
1594
1595 if (result != (flag ? true : false)) {
1596 OSKextLog(this,
1597 kOSKextLogProgressLevel |
1598 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
1599 "Autounloading for kext %s now %sabled.",
1600 getIdentifierCString(),
1601 flags.autounloadEnabled ? "en" : "dis");
1602 }
1603 return result;
1604 }
1605
1606 /*********************************************************************
1607 *********************************************************************/
1608 /* static */
1609 bool
1610 OSKext::setKernelRequestsEnabled(bool flag)
1611 {
1612 bool result;
1613
1614 IORecursiveLockLock(sKextLock);
1615 result = sKernelRequestsEnabled;
1616 sKernelRequestsEnabled = flag ? true : false;
1617
1618 if (sKernelRequestsEnabled != result) {
1619 OSKextLog(/* kext */ NULL,
1620 kOSKextLogBasicLevel |
1621 kOSKextLogGeneralFlag,
1622 "Kernel requests now %sabled.",
1623 sKernelRequestsEnabled ? "en" : "dis");
1624 }
1625 IORecursiveLockUnlock(sKextLock);
1626 return result;
1627 }
1628
1629 /*********************************************************************
1630 *********************************************************************/
1631 /* static */
1632 bool
1633 OSKext::getKernelRequestsEnabled(void)
1634 {
1635 bool result;
1636
1637 IORecursiveLockLock(sKextLock);
1638 result = sKernelRequestsEnabled;
1639 IORecursiveLockUnlock(sKextLock);
1640 return result;
1641 }
1642
1643 static bool
1644 segmentIsMutable(kernel_segment_command_t *seg)
1645 {
1646 /* Mutable segments have to have VM_PROT_WRITE */
1647 if ((seg->maxprot & VM_PROT_WRITE) == 0) {
1648 return false;
1649 }
1650 /* Exclude the __DATA_CONST segment */
1651 if (strncmp(seg->segname, "__DATA_CONST", sizeof(seg->segname)) == 0) {
1652 return false;
1653 }
1654 /* Exclude __LINKEDIT */
1655 if (strncmp(seg->segname, "__LINKEDIT", sizeof(seg->segname)) == 0) {
1656 return false;
1657 }
1658 return true;
1659 }
1660
1661 #if PRAGMA_MARK
1662 #pragma mark Kext Life Cycle
1663 #endif
1664 /*********************************************************************
1665 *********************************************************************/
1666 OSSharedPtr<OSKext>
1667 OSKext::withPrelinkedInfoDict(
1668 OSDictionary * anInfoDict,
1669 bool doCoalescedSlides,
1670 kc_kind_t type)
1671 {
1672 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
1673
1674 if (newKext && !newKext->initWithPrelinkedInfoDict(anInfoDict, doCoalescedSlides, type)) {
1675 return NULL;
1676 }
1677
1678 return newKext;
1679 }
1680
1681 /*********************************************************************
1682 *********************************************************************/
1683 bool
1684 OSKext::initWithPrelinkedInfoDict(
1685 OSDictionary * anInfoDict,
1686 bool doCoalescedSlides,
1687 kc_kind_t type)
1688 {
1689 bool result = false;
1690 OSString * kextPath = NULL; // do not release
1691 OSNumber * addressNum = NULL; // reused; do not release
1692 OSNumber * lengthNum = NULL; // reused; do not release
1693 OSBoolean * scratchBool = NULL; // do not release
1694 void * data = NULL; // do not free
1695 void * srcData = NULL; // do not free
1696 OSSharedPtr<OSData> prelinkedExecutable;
1697 uint32_t length = 0; // reused
1698 uintptr_t kext_slide = PE_get_kc_slide(type);
1699 bool shouldSaveSegments = false;
1700
1701 if (!super::init()) {
1702 goto finish;
1703 }
1704
1705 /* Get the path. Don't look for an arch-specific path property.
1706 */
1707 kextPath = OSDynamicCast(OSString,
1708 anInfoDict->getObject(kPrelinkBundlePathKey));
1709
1710 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
1711 goto finish;
1712 }
1713
1714 #if KASLR_KEXT_DEBUG
1715 IOLog("kaslr: doCoalescedSlides %d kext %s \n", doCoalescedSlides, getIdentifierCString());
1716 #endif
1717
1718 /* Also get the executable's bundle-relative path if present.
1719 * Don't look for an arch-specific path property.
1720 */
1721 executableRelPath.reset(OSDynamicCast(OSString,
1722 anInfoDict->getObject(kPrelinkExecutableRelativePathKey)), OSRetain);
1723 userExecutableRelPath.reset(OSDynamicCast(OSString,
1724 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
1725
1726 /* Don't need the paths to be in the info dictionary any more.
1727 */
1728 anInfoDict->removeObject(kPrelinkBundlePathKey);
1729 anInfoDict->removeObject(kPrelinkExecutableRelativePathKey);
1730
1731 scratchBool = OSDynamicCast(OSBoolean,
1732 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
1733 if (scratchBool == kOSBooleanTrue) {
1734 flags.requireExplicitLoad = 1;
1735 }
1736
1737 /* Create an OSData wrapper around the linked executable.
1738 */
1739 addressNum = OSDynamicCast(OSNumber,
1740 anInfoDict->getObject(kPrelinkExecutableLoadKey));
1741 if (addressNum && addressNum->unsigned64BitValue() != kOSKextCodelessKextLoadAddr) {
1742 lengthNum = OSDynamicCast(OSNumber,
1743 anInfoDict->getObject(kPrelinkExecutableSizeKey));
1744 if (!lengthNum) {
1745 OSKextLog(this,
1746 kOSKextLogErrorLevel |
1747 kOSKextLogArchiveFlag,
1748 "Kext %s can't find prelinked kext executable size.",
1749 getIdentifierCString());
1750 return result;
1751 }
1752
1753 data = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1754 length = (uint32_t) (lengthNum->unsigned32BitValue());
1755
1756 #if KASLR_KEXT_DEBUG
1757 IOLog("kaslr: unslid 0x%lx slid 0x%lx length %u - prelink executable \n",
1758 (unsigned long)ml_static_unslide((vm_offset_t)data),
1759 (unsigned long)data,
1760 length);
1761 #endif
1762
1763 anInfoDict->removeObject(kPrelinkExecutableLoadKey);
1764 anInfoDict->removeObject(kPrelinkExecutableSizeKey);
1765
1766 /* If the kext's load address differs from its source address, allocate
1767 * space in the kext map at the load address and copy the kext over.
1768 */
1769 addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject(kPrelinkExecutableSourceKey));
1770 if (addressNum) {
1771 srcData = (void *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1772
1773 #if KASLR_KEXT_DEBUG
1774 IOLog("kaslr: unslid 0x%lx slid 0x%lx - prelink executable source \n",
1775 (unsigned long)ml_static_unslide((vm_offset_t)srcData),
1776 (unsigned long)srcData);
1777 #endif
1778
1779 if (data != srcData) {
1780 #if __LP64__
1781 kern_return_t alloc_result;
1782
1783 alloc_result = kext_alloc((vm_offset_t *)&data, length, /* fixed */ TRUE);
1784 if (alloc_result != KERN_SUCCESS) {
1785 OSKextLog(this,
1786 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1787 "Failed to allocate space for prelinked kext %s.",
1788 getIdentifierCString());
1789 goto finish;
1790 }
1791 memcpy(data, srcData, length);
1792 #else
1793 OSKextLog(this,
1794 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
1795 "Error: prelinked kext %s - source and load addresses "
1796 "differ on ILP32 architecture.",
1797 getIdentifierCString());
1798 goto finish;
1799 #endif /* __LP64__ */
1800 }
1801
1802 anInfoDict->removeObject(kPrelinkExecutableSourceKey);
1803 }
1804
1805 prelinkedExecutable = OSData::withBytesNoCopy(data, length);
1806 if (!prelinkedExecutable) {
1807 OSKextLog(this,
1808 kOSKextLogErrorLevel |
1809 kOSKextLogGeneralFlag | kOSKextLogArchiveFlag,
1810 "Kext %s failed to create executable wrapper.",
1811 getIdentifierCString());
1812 goto finish;
1813 }
1814
1815 #if VM_MAPPED_KEXTS
1816 prelinkedExecutable->setDeallocFunction(osdata_kext_free);
1817 #else
1818 prelinkedExecutable->setDeallocFunction(osdata_phys_free);
1819 #endif
1820 setLinkedExecutable(prelinkedExecutable.get());
1821 addressNum = OSDynamicCast(OSNumber,
1822 anInfoDict->getObject(kPrelinkKmodInfoKey));
1823 if (!addressNum) {
1824 OSKextLog(this,
1825 kOSKextLogErrorLevel |
1826 kOSKextLogArchiveFlag,
1827 "Kext %s can't find prelinked kext kmod_info address.",
1828 getIdentifierCString());
1829 goto finish;
1830 }
1831
1832 if (addressNum->unsigned64BitValue() != 0) {
1833 kmod_info = (kmod_info_t *) (((uintptr_t) (addressNum->unsigned64BitValue())) + kext_slide);
1834 if (kmod_info->address) {
1835 kmod_info->address = (((uintptr_t)(kmod_info->address)) + kext_slide);
1836 } else {
1837 kmod_info->address = (uintptr_t)data;
1838 kmod_info->size = length;
1839 }
1840 #if KASLR_KEXT_DEBUG
1841 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info \n",
1842 (unsigned long)((vm_offset_t)kmod_info) - kext_slide,
1843 (unsigned long)kmod_info);
1844 IOLog("kaslr: unslid 0x%lx slid 0x%lx - kmod_info->address \n",
1845 (unsigned long)((vm_offset_t)kmod_info->address) - kext_slide,
1846 (unsigned long)kmod_info->address);
1847 #endif
1848 }
1849
1850 anInfoDict->removeObject(kPrelinkKmodInfoKey);
1851 }
1852
1853 if ((addressNum = OSDynamicCast(OSNumber, anInfoDict->getObject("ModuleIndex")))) {
1854 uintptr_t builtinTextStart;
1855 uintptr_t builtinTextEnd;
1856
1857 flags.builtin = true;
1858 builtinKmodIdx = addressNum->unsigned32BitValue();
1859 assert(builtinKmodIdx < gBuiltinKmodsCount);
1860
1861 builtinTextStart = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx];
1862 builtinTextEnd = ((uintptr_t *)gBuiltinKmodsSectionStart->addr)[builtinKmodIdx + 1];
1863
1864 kmod_info = ((kmod_info_t **)gBuiltinKmodsSectionInfo->addr)[builtinKmodIdx];
1865 kmod_info->address = builtinTextStart;
1866 kmod_info->size = builtinTextEnd - builtinTextStart;
1867 }
1868
1869 /* If the plist has a UUID for an interface, save that off.
1870 */
1871 if (isInterface()) {
1872 interfaceUUID.reset(OSDynamicCast(OSData,
1873 anInfoDict->getObject(kPrelinkInterfaceUUIDKey)), OSRetain);
1874 if (interfaceUUID) {
1875 anInfoDict->removeObject(kPrelinkInterfaceUUIDKey);
1876 }
1877 }
1878
1879 result = (kOSReturnSuccess == slidePrelinkedExecutable(doCoalescedSlides));
1880 if (!result) {
1881 goto finish;
1882 }
1883
1884 kc_type = type;
1885 /* Exclude builtin and codeless kexts */
1886 if (prelinkedExecutable && kmod_info) {
1887 switch (kc_type) {
1888 case KCKindPrimary:
1889 shouldSaveSegments = (
1890 getPropertyForHostArch(kOSMutableSegmentCopy) == kOSBooleanTrue ||
1891 getPropertyForHostArch(kOSBundleAllowUserLoadKey) == kOSBooleanTrue);
1892 if (shouldSaveSegments) {
1893 flags.resetSegmentsFromImmutableCopy = 1;
1894 }
1895 break;
1896 case KCKindPageable:
1897 flags.resetSegmentsFromVnode = 1;
1898 break;
1899 case KCKindAuxiliary:
1900 if (!pageableKCloaded) {
1901 flags.resetSegmentsFromImmutableCopy = 1;
1902 } else if (resetAuxKCSegmentOnUnload) {
1903 flags.resetSegmentsFromVnode = 1;
1904 }
1905 break;
1906 default:
1907 break;
1908 }
1909 }
1910
1911 if (flags.resetSegmentsFromImmutableCopy) {
1912 /* Save a pristine copy of the mutable segments */
1913 kernel_segment_command_t *seg = NULL;
1914 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
1915
1916 savedMutableSegments = OSArray::withCapacity(0);
1917
1918 for (seg = firstsegfromheader(k_mh); seg; seg = nextsegfromheader(k_mh, seg)) {
1919 if (!segmentIsMutable(seg)) {
1920 continue;
1921 }
1922 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
1923 uint64_t vmsize = seg->vmsize;
1924 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
1925 "Saving kext %s mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1926 OSSharedPtr<OSKextSavedMutableSegment> savedSegment = OSKextSavedMutableSegment::withSegment(seg);
1927 if (!savedSegment) {
1928 OSKextLog(this,
1929 kOSKextLogErrorLevel |
1930 kOSKextLogGeneralFlag,
1931 "Kext %s failed to save mutable segment %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
1932 result = kOSKextReturnInternalError;
1933 goto finish;
1934 }
1935 savedMutableSegments->setObject(savedSegment);
1936 }
1937 }
1938
1939 if (doCoalescedSlides == false && !flags.resetSegmentsFromVnode) {
1940 /*
1941 * set VM protections now, wire pages for the old style Aux KC now,
1942 * wire pages for the rest of the KC types at load time.
1943 */
1944 result = (kOSReturnSuccess == setVMAttributes(true, (type == KCKindAuxiliary) ? true : false));
1945 if (!result) {
1946 goto finish;
1947 }
1948 }
1949
1950 flags.prelinked = true;
1951
1952 /* If we created a kext from prelink info,
1953 * we must be booting from a prelinked kernel.
1954 */
1955 sPrelinkBoot = true;
1956
1957 result = registerIdentifier();
1958
1959 finish:
1960 return result;
1961 }
1962
1963 /*********************************************************************
1964 *********************************************************************/
1965 /* static */
1966 OSSharedPtr<OSKext>
1967 OSKext::withCodelessInfo(OSDictionary * anInfoDict)
1968 {
1969 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
1970
1971 if (newKext && !newKext->initWithCodelessInfo(anInfoDict)) {
1972 return NULL;
1973 }
1974
1975 return newKext;
1976 }
1977
1978 /*********************************************************************
1979 *********************************************************************/
1980 bool
1981 OSKext::initWithCodelessInfo(OSDictionary * anInfoDict)
1982 {
1983 bool result = false;
1984 OSString * kextPath = NULL; // do not release
1985 OSBoolean * scratchBool = NULL; // do not release
1986
1987 if (anInfoDict == NULL || !super::init()) {
1988 goto finish;
1989 }
1990
1991 /*
1992 * Get the path. Don't look for an arch-specific path property.
1993 */
1994 kextPath = OSDynamicCast(OSString,
1995 anInfoDict->getObject(kKextRequestArgumentCodelessInfoBundlePathKey));
1996 if (!kextPath) {
1997 OSKextLog(NULL,
1998 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
1999 "Requested codeless kext dictionary does not contain the '%s' key",
2000 kKextRequestArgumentCodelessInfoBundlePathKey);
2001 goto finish;
2002 }
2003
2004 uniquePersonalityProperties(anInfoDict);
2005
2006 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
2007 goto finish;
2008 }
2009
2010 /*
2011 * This path is meant to initialize codeless kexts only. Refuse
2012 * anything that looks like it has an executable and/or declares
2013 * itself as a kernel component.
2014 */
2015 if (declaresExecutable() || isKernelComponent()) {
2016 OSKextLog(NULL,
2017 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
2018 "Refusing to register codeless kext that declares an executable/kernel component: %s",
2019 getIdentifierCString());
2020 goto finish;
2021 }
2022
2023 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
2024 boolean_t updated = updateExcludeList(infoDict.get());
2025 if (updated) {
2026 OSKextLog(this,
2027 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
2028 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
2029 }
2030 }
2031
2032 kc_type = KCKindNone;
2033
2034 scratchBool = OSDynamicCast(OSBoolean,
2035 getPropertyForHostArch(kOSBundleRequireExplicitLoadKey));
2036 if (scratchBool == kOSBooleanTrue) {
2037 flags.requireExplicitLoad = 1;
2038 }
2039
2040 /* Also get the executable's bundle-relative path if present.
2041 * Don't look for an arch-specific path property.
2042 */
2043 userExecutableRelPath.reset(OSDynamicCast(OSString,
2044 anInfoDict->getObject(kCFBundleDriverKitExecutableKey)), OSRetain);
2045
2046 /* remove unnecessary paths from the info dict */
2047 anInfoDict->removeObject(kKextRequestArgumentCodelessInfoBundlePathKey);
2048
2049 result = registerIdentifier();
2050
2051 finish:
2052 return result;
2053 }
2054
2055 /*********************************************************************
2056 *********************************************************************/
2057 /* static */
2058 void
2059 OSKext::setAllVMAttributes(void)
2060 {
2061 OSSharedPtr<OSCollectionIterator> kextIterator;
2062 const OSSymbol * thisID = NULL; // do not release
2063
2064 IORecursiveLockLock(sKextLock);
2065
2066 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
2067 if (!kextIterator) {
2068 goto finish;
2069 }
2070
2071 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
2072 OSKext * thisKext; // do not release
2073
2074 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
2075 if (!thisKext || thisKext->isInterface() || !thisKext->declaresExecutable()) {
2076 continue;
2077 }
2078
2079 if (!thisKext->flags.resetSegmentsFromVnode) {
2080 /*
2081 * set VM protections now, wire pages for the old style Aux KC now,
2082 * wire pages for the rest of the KC types at load time.
2083 */
2084 thisKext->setVMAttributes(true, (thisKext->kc_type == KCKindAuxiliary) ? true : false);
2085 }
2086 }
2087
2088 finish:
2089 IORecursiveLockUnlock(sKextLock);
2090
2091 return;
2092 }
2093
2094 /*********************************************************************
2095 *********************************************************************/
2096 OSSharedPtr<OSKext>
2097 OSKext::withBooterData(
2098 OSString * deviceTreeName,
2099 OSData * booterData)
2100 {
2101 OSSharedPtr<OSKext> newKext(OSMakeShared<OSKext>());
2102
2103 if (newKext && !newKext->initWithBooterData(deviceTreeName, booterData)) {
2104 return NULL;
2105 }
2106
2107 return newKext;
2108 }
2109
2110 /*********************************************************************
2111 *********************************************************************/
2112 typedef struct _BooterKextFileInfo {
2113 uint32_t infoDictPhysAddr;
2114 uint32_t infoDictLength;
2115 uint32_t executablePhysAddr;
2116 uint32_t executableLength;
2117 uint32_t bundlePathPhysAddr;
2118 uint32_t bundlePathLength;
2119 } _BooterKextFileInfo;
2120
2121 bool
2122 OSKext::initWithBooterData(
2123 OSString * deviceTreeName,
2124 OSData * booterData)
2125 {
2126 bool result = false;
2127 _BooterKextFileInfo * kextFileInfo = NULL; // do not free
2128 char * infoDictAddr = NULL; // do not free
2129 void * executableAddr = NULL; // do not free
2130 char * bundlePathAddr = NULL; // do not free
2131
2132 OSDictionary * theInfoDict = NULL; // do not release
2133 OSSharedPtr<OSObject> parsedXML;
2134 OSSharedPtr<OSString> kextPath;
2135
2136 OSSharedPtr<OSString> errorString;
2137 OSSharedPtr<OSData> executable;
2138
2139 if (!super::init()) {
2140 goto finish;
2141 }
2142
2143 kextFileInfo = (_BooterKextFileInfo *)booterData->getBytesNoCopy();
2144 if (!kextFileInfo) {
2145 OSKextLog(this,
2146 kOSKextLogErrorLevel |
2147 kOSKextLogGeneralFlag,
2148 "No booter-provided data for kext device tree entry %s.",
2149 deviceTreeName->getCStringNoCopy());
2150 goto finish;
2151 }
2152
2153 /* The info plist must exist or we can't read the kext.
2154 */
2155 if (!kextFileInfo->infoDictPhysAddr || !kextFileInfo->infoDictLength) {
2156 OSKextLog(this,
2157 kOSKextLogErrorLevel |
2158 kOSKextLogGeneralFlag,
2159 "No kext info dictionary for booter device tree entry %s.",
2160 deviceTreeName->getCStringNoCopy());
2161 goto finish;
2162 }
2163
2164 infoDictAddr = (char *)ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
2165 if (!infoDictAddr) {
2166 OSKextLog(this,
2167 kOSKextLogErrorLevel |
2168 kOSKextLogGeneralFlag,
2169 "Can't translate physical address 0x%x of kext info dictionary "
2170 "for device tree entry %s.",
2171 (int)kextFileInfo->infoDictPhysAddr,
2172 deviceTreeName->getCStringNoCopy());
2173 goto finish;
2174 }
2175
2176 parsedXML = OSUnserializeXML(infoDictAddr, errorString);
2177 if (parsedXML) {
2178 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
2179 }
2180 if (!theInfoDict) {
2181 const char * errorCString = "(unknown error)";
2182
2183 if (errorString && errorString->getCStringNoCopy()) {
2184 errorCString = errorString->getCStringNoCopy();
2185 } else if (parsedXML) {
2186 errorCString = "not a dictionary";
2187 }
2188 OSKextLog(this,
2189 kOSKextLogErrorLevel |
2190 kOSKextLogGeneralFlag,
2191 "Error unserializing info dictionary for device tree entry %s: %s.",
2192 deviceTreeName->getCStringNoCopy(), errorCString);
2193 goto finish;
2194 }
2195
2196 /* A bundle path is not mandatory.
2197 */
2198 if (kextFileInfo->bundlePathPhysAddr && kextFileInfo->bundlePathLength) {
2199 bundlePathAddr = (char *)ml_static_ptovirt(kextFileInfo->bundlePathPhysAddr);
2200 if (!bundlePathAddr) {
2201 OSKextLog(this,
2202 kOSKextLogErrorLevel |
2203 kOSKextLogGeneralFlag,
2204 "Can't translate physical address 0x%x of kext bundle path "
2205 "for device tree entry %s.",
2206 (int)kextFileInfo->bundlePathPhysAddr,
2207 deviceTreeName->getCStringNoCopy());
2208 goto finish;
2209 }
2210 bundlePathAddr[kextFileInfo->bundlePathLength - 1] = '\0'; // just in case!
2211
2212 kextPath = OSString::withCString(bundlePathAddr);
2213 if (!kextPath) {
2214 OSKextLog(this,
2215 kOSKextLogErrorLevel |
2216 kOSKextLogGeneralFlag,
2217 "Failed to create wrapper for device tree entry %s kext path %s.",
2218 deviceTreeName->getCStringNoCopy(), bundlePathAddr);
2219 goto finish;
2220 }
2221 }
2222
2223 if (!setInfoDictionaryAndPath(theInfoDict, kextPath.get())) {
2224 goto finish;
2225 }
2226
2227 /* An executable is not mandatory.
2228 */
2229 if (kextFileInfo->executablePhysAddr && kextFileInfo->executableLength) {
2230 executableAddr = (void *)ml_static_ptovirt(kextFileInfo->executablePhysAddr);
2231 if (!executableAddr) {
2232 OSKextLog(this,
2233 kOSKextLogErrorLevel |
2234 kOSKextLogGeneralFlag,
2235 "Can't translate physical address 0x%x of kext executable "
2236 "for device tree entry %s.",
2237 (int)kextFileInfo->executablePhysAddr,
2238 deviceTreeName->getCStringNoCopy());
2239 goto finish;
2240 }
2241
2242 executable = OSData::withBytesNoCopy(executableAddr,
2243 kextFileInfo->executableLength);
2244 if (!executable) {
2245 OSKextLog(this,
2246 kOSKextLogErrorLevel |
2247 kOSKextLogGeneralFlag,
2248 "Failed to create executable wrapper for device tree entry %s.",
2249 deviceTreeName->getCStringNoCopy());
2250 goto finish;
2251 }
2252
2253 /* A kext with an executable needs to retain the whole booterData
2254 * object to keep the executable in memory.
2255 */
2256 if (!setExecutable(executable.get(), booterData)) {
2257 OSKextLog(this,
2258 kOSKextLogErrorLevel |
2259 kOSKextLogGeneralFlag,
2260 "Failed to set kext executable for device tree entry %s.",
2261 deviceTreeName->getCStringNoCopy());
2262 goto finish;
2263 }
2264 }
2265
2266 result = registerIdentifier();
2267
2268 finish:
2269 return result;
2270 }
2271
2272 /*********************************************************************
2273 *********************************************************************/
2274 bool
2275 OSKext::registerIdentifier(void)
2276 {
2277 bool result = false;
2278 OSKext * existingKext = NULL; // do not release
2279 bool existingIsLoaded = false;
2280 bool existingIsPrelinked = false;
2281 bool existingIsCodeless = false;
2282 bool existingIsDext = false;
2283 OSKextVersion newVersion = -1;
2284 OSKextVersion existingVersion = -1;
2285 char newVersionCString[kOSKextVersionMaxLength];
2286 char existingVersionCString[kOSKextVersionMaxLength];
2287 OSSharedPtr<OSData> newUUID;
2288 OSSharedPtr<OSData> existingUUID;
2289
2290 IORecursiveLockLock(sKextLock);
2291
2292 /* Get the new kext's version for checks & log messages.
2293 */
2294 newVersion = getVersion();
2295 OSKextVersionGetString(newVersion, newVersionCString,
2296 kOSKextVersionMaxLength);
2297
2298 /* If we don't have an existing kext with this identifier,
2299 * just record the new kext and we're done!
2300 */
2301 existingKext = OSDynamicCast(OSKext, sKextsByID->getObject(bundleID.get()));
2302 if (!existingKext) {
2303 sKextsByID->setObject(bundleID.get(), this);
2304 result = true;
2305 goto finish;
2306 }
2307
2308 /* Get the existing kext's version for checks & log messages.
2309 */
2310 existingVersion = existingKext->getVersion();
2311 OSKextVersionGetString(existingVersion,
2312 existingVersionCString, kOSKextVersionMaxLength);
2313
2314 existingIsLoaded = existingKext->isLoaded();
2315 existingIsPrelinked = existingKext->isPrelinked();
2316 existingIsDext = existingKext->isDriverKit();
2317 existingIsCodeless = !existingKext->declaresExecutable() && !existingIsDext;
2318
2319 /* If we have a non-codeless kext with this identifier that's already
2320 * loaded/prelinked, we can't use the new one, but let's be really
2321 * thorough and check how the two are related for a precise diagnostic
2322 * log message.
2323 *
2324 * This check is valid for kexts that declare an executable and for
2325 * dexts, but not for codeless kexts - we can just replace those.
2326 */
2327 if ((!existingIsCodeless || existingIsDext) &&
2328 (existingIsLoaded || existingIsPrelinked)) {
2329 bool sameVersion = (newVersion == existingVersion);
2330 bool sameExecutable = true; // assume true unless we have UUIDs
2331
2332 /* Only get the UUID if the existing kext is loaded. Doing so
2333 * might have to uncompress an mkext executable and we shouldn't
2334 * take that hit when neither kext is loaded.
2335 *
2336 * Note: there is no decompression that happens when all kexts
2337 * are loaded from kext collecitons.
2338 */
2339 newUUID = copyUUID();
2340 existingUUID = existingKext->copyUUID();
2341
2342 if (existingIsDext && !isDriverKit()) {
2343 OSKextLog(this,
2344 kOSKextLogWarningLevel |
2345 kOSKextLogKextBookkeepingFlag,
2346 "Notice - new kext %s, v%s matches a %s dext"
2347 "with the same bundle ID, v%s.",
2348 getIdentifierCString(), newVersionCString,
2349 (existingIsLoaded ? "loaded" : "prelinked"),
2350 existingVersionCString);
2351 goto finish;
2352 }
2353
2354 /* I'm entirely too paranoid about checking equivalence of executables,
2355 * but I remember nasty problems with it in the past.
2356 *
2357 * - If we have UUIDs for both kexts, compare them.
2358 * - If only one kext has a UUID, they're definitely different.
2359 */
2360 if (newUUID && existingUUID) {
2361 sameExecutable = newUUID->isEqualTo(existingUUID.get());
2362 } else if (newUUID || existingUUID) {
2363 sameExecutable = false;
2364 }
2365
2366 if (!newUUID && !existingUUID) {
2367 /* If there are no UUIDs, we can't really tell that the executables
2368 * are *different* without a lot of work; the loaded kext's
2369 * unrelocated executable is no longer around (and we never had it
2370 * in-kernel for a prelinked kext). We certainly don't want to do
2371 * a whole fake link for the new kext just to compare, either.
2372 */
2373 OSKextLog(this,
2374 kOSKextLogWarningLevel |
2375 kOSKextLogKextBookkeepingFlag,
2376 "Notice - new kext %s, v%s matches %s kext "
2377 "but can't determine if executables are the same (no UUIDs).",
2378 getIdentifierCString(),
2379 newVersionCString,
2380 (existingIsLoaded ? "loaded" : "prelinked"));
2381 }
2382
2383 if (sameVersion && sameExecutable) {
2384 OSKextLog(this,
2385 (existingIsLoaded ? kOSKextLogWarningLevel : kOSKextLogStepLevel) |
2386 kOSKextLogKextBookkeepingFlag,
2387 "Refusing new kext %s, v%s: a %s copy is already present "
2388 "(same version and executable).",
2389 getIdentifierCString(), newVersionCString,
2390 (existingIsLoaded ? "loaded" : "prelinked"));
2391 } else {
2392 if (!sameVersion) {
2393 /* This condition is significant so log it under warnings.
2394 */
2395 OSKextLog(this,
2396 kOSKextLogWarningLevel |
2397 kOSKextLogKextBookkeepingFlag,
2398 "Refusing new kext %s, v%s: already have %s v%s.",
2399 getIdentifierCString(),
2400 newVersionCString,
2401 (existingIsLoaded ? "loaded" : "prelinked"),
2402 existingVersionCString);
2403 } else {
2404 /* This condition is significant so log it under warnings.
2405 */
2406 OSKextLog(this,
2407 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2408 "Refusing new kext %s, v%s: a %s copy with a different "
2409 "executable UUID is already present.",
2410 getIdentifierCString(), newVersionCString,
2411 (existingIsLoaded ? "loaded" : "prelinked"));
2412 }
2413 }
2414 goto finish;
2415 } /* if ((!existingIsCodeless || existingIsDext) && (existingIsLoaded || existingIsPrelinked)) */
2416
2417 /* Refuse to allow an existing loaded codeless kext be replaced by a
2418 * normal kext with the same bundle ID.
2419 */
2420 if (existingIsCodeless && declaresExecutable()) {
2421 OSKextLog(this,
2422 kOSKextLogWarningLevel | kOSKextLogKextBookkeepingFlag,
2423 "Refusing new kext %s, v%s: a codeless copy is already %s",
2424 getIdentifierCString(), newVersionCString,
2425 (existingIsLoaded ? "loaded" : "prelinked"));
2426 goto finish;
2427 }
2428
2429 /* Dexts packaged in the BootKC will be protected against replacement
2430 * by non-dexts by the logic above which checks if they are prelinked.
2431 * Dexts which are prelinked into the System KC will be registered
2432 * before any other kexts in the AuxKC are registered, and we never
2433 * put dexts in the AuxKC. Therefore, there is no need to check if an
2434 * existing object is a dext and is being replaced by a non-dext.
2435 * The scenario cannot happen by construction.
2436 *
2437 * See: OSKext::loadFileSetKexts()
2438 */
2439
2440 /* We have two nonloaded/nonprelinked kexts, so our decision depends on whether
2441 * user loads are happening or if we're still in early boot. User agents are
2442 * supposed to resolve dependencies topside and include only the exact
2443 * kexts needed; so we always accept the new kext (in fact we should never
2444 * see an older unloaded copy hanging around).
2445 */
2446 if (sUserLoadsActive) {
2447 sKextsByID->setObject(bundleID.get(), this);
2448 result = true;
2449
2450 OSKextLog(this,
2451 kOSKextLogStepLevel |
2452 kOSKextLogKextBookkeepingFlag,
2453 "Dropping old copy of kext %s (v%s) for newly-added (v%s).",
2454 getIdentifierCString(),
2455 existingVersionCString,
2456 newVersionCString);
2457
2458 goto finish;
2459 }
2460
2461 /* During early boot, the kext with the highest version always wins out.
2462 * Prelinked kernels will never hit this, but mkexts and booter-read
2463 * kexts might have duplicates.
2464 */
2465 if (newVersion > existingVersion) {
2466 sKextsByID->setObject(bundleID.get(), this);
2467 result = true;
2468
2469 OSKextLog(this,
2470 kOSKextLogStepLevel |
2471 kOSKextLogKextBookkeepingFlag,
2472 "Dropping lower version (v%s) of registered kext %s for higher (v%s).",
2473 existingVersionCString,
2474 getIdentifierCString(),
2475 newVersionCString);
2476 } else {
2477 OSKextLog(this,
2478 kOSKextLogStepLevel |
2479 kOSKextLogKextBookkeepingFlag,
2480 "Kext %s is already registered with a higher/same version (v%s); "
2481 "dropping newly-added (v%s).",
2482 getIdentifierCString(),
2483 existingVersionCString,
2484 newVersionCString);
2485 }
2486
2487 /* result has been set appropriately by now. */
2488
2489 finish:
2490
2491 IORecursiveLockUnlock(sKextLock);
2492
2493 if (result) {
2494 OSKextLog(this,
2495 kOSKextLogStepLevel |
2496 kOSKextLogKextBookkeepingFlag,
2497 "Kext %s, v%s registered and available for loading.",
2498 getIdentifierCString(), newVersionCString);
2499 }
2500
2501 return result;
2502 }
2503
2504 /*********************************************************************
2505 * Does the bare minimum validation to look up a kext.
2506 * All other validation is done on the spot as needed.
2507 **********************************************************************/
2508 bool
2509 OSKext::setInfoDictionaryAndPath(
2510 OSDictionary * aDictionary,
2511 OSString * aPath)
2512 {
2513 bool result = false;
2514 OSString * bundleIDString = NULL; // do not release
2515 OSString * versionString = NULL; // do not release
2516 OSString * compatibleVersionString = NULL; // do not release
2517 const char * versionCString = NULL; // do not free
2518 const char * compatibleVersionCString = NULL; // do not free
2519 OSBoolean * scratchBool = NULL; // do not release
2520 OSDictionary * scratchDict = NULL; // do not release
2521
2522 if (infoDict) {
2523 panic("Attempt to set info dictionary on a kext "
2524 "that already has one (%s).",
2525 getIdentifierCString());
2526 }
2527
2528 if (!aDictionary || !OSDynamicCast(OSDictionary, aDictionary)) {
2529 goto finish;
2530 }
2531
2532 infoDict.reset(aDictionary, OSRetain);
2533
2534 /* Check right away if the info dictionary has any log flags.
2535 */
2536 scratchBool = OSDynamicCast(OSBoolean,
2537 getPropertyForHostArch(kOSBundleEnableKextLoggingKey));
2538 if (scratchBool == kOSBooleanTrue) {
2539 flags.loggingEnabled = 1;
2540 }
2541
2542 /* The very next thing to get is the bundle identifier. Unlike
2543 * in user space, a kext with no bundle identifier gets axed
2544 * immediately.
2545 */
2546 bundleIDString = OSDynamicCast(OSString,
2547 getPropertyForHostArch(kCFBundleIdentifierKey));
2548 if (!bundleIDString) {
2549 OSKextLog(this,
2550 kOSKextLogErrorLevel |
2551 kOSKextLogValidationFlag,
2552 "CFBundleIdentifier missing/invalid type in kext %s.",
2553 aPath ? aPath->getCStringNoCopy() : "(unknown)");
2554 goto finish;
2555 }
2556 bundleID = OSSymbol::withString(bundleIDString);
2557 if (!bundleID) {
2558 OSKextLog(this,
2559 kOSKextLogErrorLevel |
2560 kOSKextLogValidationFlag,
2561 "Can't copy bundle identifier as symbol for kext %s.",
2562 bundleIDString->getCStringNoCopy());
2563 goto finish;
2564 }
2565
2566 /* Save the path if we got one (it should always be available but it's
2567 * just something nice to have for bookkeeping).
2568 */
2569 if (aPath) {
2570 path.reset(aPath, OSRetain);
2571 }
2572
2573 /*****
2574 * Minimal validation to initialize. We'll do other validation on the spot.
2575 */
2576 if (bundleID->getLength() >= KMOD_MAX_NAME) {
2577 OSKextLog(this,
2578 kOSKextLogErrorLevel |
2579 kOSKextLogValidationFlag,
2580 "Kext %s error - CFBundleIdentifier over max length %d.",
2581 getIdentifierCString(), KMOD_MAX_NAME - 1);
2582 goto finish;
2583 }
2584
2585 version = compatibleVersion = -1;
2586
2587 versionString = OSDynamicCast(OSString,
2588 getPropertyForHostArch(kCFBundleVersionKey));
2589 if (!versionString) {
2590 OSKextLog(this,
2591 kOSKextLogErrorLevel |
2592 kOSKextLogValidationFlag,
2593 "Kext %s error - CFBundleVersion missing/invalid type.",
2594 getIdentifierCString());
2595 goto finish;
2596 }
2597 versionCString = versionString->getCStringNoCopy();
2598 version = OSKextParseVersionString(versionCString);
2599 if (version < 0) {
2600 OSKextLog(this,
2601 kOSKextLogErrorLevel |
2602 kOSKextLogValidationFlag,
2603 "Kext %s error - CFBundleVersion bad value '%s'.",
2604 getIdentifierCString(), versionCString);
2605 goto finish;
2606 }
2607
2608 compatibleVersion = -1; // set to illegal value for kexts that don't have
2609
2610 compatibleVersionString = OSDynamicCast(OSString,
2611 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
2612 if (compatibleVersionString) {
2613 compatibleVersionCString = compatibleVersionString->getCStringNoCopy();
2614 compatibleVersion = OSKextParseVersionString(compatibleVersionCString);
2615 if (compatibleVersion < 0) {
2616 OSKextLog(this,
2617 kOSKextLogErrorLevel |
2618 kOSKextLogValidationFlag,
2619 "Kext %s error - OSBundleCompatibleVersion bad value '%s'.",
2620 getIdentifierCString(), compatibleVersionCString);
2621 goto finish;
2622 }
2623
2624 if (compatibleVersion > version) {
2625 OSKextLog(this,
2626 kOSKextLogErrorLevel |
2627 kOSKextLogValidationFlag,
2628 "Kext %s error - %s %s > %s %s (must be <=).",
2629 getIdentifierCString(),
2630 kOSBundleCompatibleVersionKey, compatibleVersionCString,
2631 kCFBundleVersionKey, versionCString);
2632 goto finish;
2633 }
2634 }
2635
2636 /* Check to see if this kext is in exclude list */
2637 if (isInExcludeList()) {
2638 OSKextLog(this,
2639 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2640 "Kext %s is in exclude list, not loadable",
2641 getIdentifierCString());
2642 goto finish;
2643 }
2644
2645 /* Set flags for later use if the infoDict gets flushed. We only
2646 * check for true values, not false ones(!)
2647 */
2648 scratchBool = OSDynamicCast(OSBoolean,
2649 getPropertyForHostArch(kOSBundleIsInterfaceKey));
2650 if (scratchBool == kOSBooleanTrue) {
2651 flags.interface = 1;
2652 }
2653
2654 scratchBool = OSDynamicCast(OSBoolean,
2655 getPropertyForHostArch(kOSKernelResourceKey));
2656 if (scratchBool == kOSBooleanTrue) {
2657 flags.kernelComponent = 1;
2658 flags.interface = 1; // xxx - hm. the kernel itself isn't an interface...
2659 flags.started = 1;
2660
2661 /* A kernel component has one implicit dependency on the kernel.
2662 */
2663 flags.hasAllDependencies = 1;
2664 }
2665
2666 /* Make sure common string values in personalities are uniqued to OSSymbols.
2667 */
2668 scratchDict = OSDynamicCast(OSDictionary,
2669 getPropertyForHostArch(kIOKitPersonalitiesKey));
2670 if (scratchDict) {
2671 uniquePersonalityProperties(scratchDict);
2672 }
2673
2674 result = true;
2675
2676 finish:
2677
2678 return result;
2679 }
2680
2681 /*********************************************************************
2682 * Not used for prelinked kernel boot as there is no unrelocated
2683 * executable.
2684 *********************************************************************/
2685 bool
2686 OSKext::setExecutable(
2687 OSData * anExecutable,
2688 OSData * externalData,
2689 bool externalDataIsMkext)
2690 {
2691 bool result = false;
2692 const char * executableKey = NULL; // do not free
2693
2694 if (!anExecutable) {
2695 infoDict->removeObject(_kOSKextExecutableKey);
2696 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
2697 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
2698 result = true;
2699 goto finish;
2700 }
2701
2702 if (infoDict->getObject(_kOSKextExecutableKey) ||
2703 infoDict->getObject(_kOSKextMkextExecutableReferenceKey)) {
2704 panic("Attempt to set an executable on a kext "
2705 "that already has one (%s).",
2706 getIdentifierCString());
2707 goto finish;
2708 }
2709
2710 if (externalDataIsMkext) {
2711 executableKey = _kOSKextMkextExecutableReferenceKey;
2712 } else {
2713 executableKey = _kOSKextExecutableKey;
2714 }
2715
2716 if (anExecutable) {
2717 infoDict->setObject(executableKey, anExecutable);
2718 if (externalData) {
2719 infoDict->setObject(_kOSKextExecutableExternalDataKey, externalData);
2720 }
2721 }
2722
2723 result = true;
2724
2725 finish:
2726 return result;
2727 }
2728
2729 /*********************************************************************
2730 *********************************************************************/
2731 static void
2732 uniqueStringPlistProperty(OSDictionary * dict, const char * key)
2733 {
2734 OSObject * value = NULL; // do not release
2735 OSString * stringValue = NULL; // do not release
2736 OSSharedPtr<const OSSymbol> symbolValue;
2737
2738 value = dict->getObject(key);
2739 if (!value) {
2740 goto finish;
2741 }
2742 if (OSDynamicCast(OSSymbol, value)) {
2743 /* this is already an OSSymbol: we're good */
2744 goto finish;
2745 }
2746
2747 stringValue = OSDynamicCast(OSString, value);
2748 if (!stringValue) {
2749 goto finish;
2750 }
2751
2752 symbolValue = OSSymbol::withString(stringValue);
2753 if (!symbolValue) {
2754 goto finish;
2755 }
2756
2757 dict->setObject(key, symbolValue.get());
2758
2759 finish:
2760 return;
2761 }
2762
2763 /*********************************************************************
2764 *********************************************************************/
2765 static void
2766 uniqueStringPlistProperty(OSDictionary * dict, const OSString * key)
2767 {
2768 OSObject * value = NULL; // do not release
2769 OSString * stringValue = NULL; // do not release
2770 OSSharedPtr<const OSSymbol> symbolValue;
2771
2772 value = dict->getObject(key);
2773 if (!value) {
2774 goto finish;
2775 }
2776 if (OSDynamicCast(OSSymbol, value)) {
2777 /* this is already an OSSymbol: we're good */
2778 goto finish;
2779 }
2780
2781 stringValue = OSDynamicCast(OSString, value);
2782 if (!stringValue) {
2783 goto finish;
2784 }
2785
2786 symbolValue = OSSymbol::withString(stringValue);
2787 if (!symbolValue) {
2788 goto finish;
2789 }
2790
2791 dict->setObject(key, symbolValue.get());
2792
2793 finish:
2794 return;
2795 }
2796
2797 void
2798 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict)
2799 {
2800 OSKext::uniquePersonalityProperties(personalityDict, true);
2801 }
2802
2803 /*********************************************************************
2804 * Replace common personality property values with uniqued instances
2805 * to save on wired memory.
2806 *********************************************************************/
2807 /* static */
2808 void
2809 OSKext::uniquePersonalityProperties(OSDictionary * personalityDict, bool defaultAddKernelBundleIdentifier)
2810 {
2811 /* Properties every personality has.
2812 */
2813 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKey);
2814 uniqueStringPlistProperty(personalityDict, kIOProviderClassKey);
2815 uniqueStringPlistProperty(personalityDict, gIOClassKey.get());
2816 if (personalityDict->getObject(kCFBundleIdentifierKernelKey)) {
2817 uniqueStringPlistProperty(personalityDict, kCFBundleIdentifierKernelKey);
2818 } else if (defaultAddKernelBundleIdentifier) {
2819 personalityDict->setObject(kCFBundleIdentifierKernelKey, personalityDict->getObject(kCFBundleIdentifierKey));
2820 }
2821
2822 /* Other commonly used properties.
2823 */
2824 uniqueStringPlistProperty(personalityDict, gIOMatchCategoryKey);
2825 uniqueStringPlistProperty(personalityDict, gIOResourceMatchKey);
2826 uniqueStringPlistProperty(personalityDict, gIOUserClientClassKey);
2827
2828 uniqueStringPlistProperty(personalityDict, "HIDDefaultBehavior");
2829 uniqueStringPlistProperty(personalityDict, "HIDPointerAccelerationType");
2830 uniqueStringPlistProperty(personalityDict, "HIDRemoteControlType");
2831 uniqueStringPlistProperty(personalityDict, "HIDScrollAccelerationType");
2832 uniqueStringPlistProperty(personalityDict, "IOPersonalityPublisher");
2833 uniqueStringPlistProperty(personalityDict, "Physical Interconnect");
2834 uniqueStringPlistProperty(personalityDict, "Physical Interconnect Location");
2835 uniqueStringPlistProperty(personalityDict, "Vendor");
2836 uniqueStringPlistProperty(personalityDict, "Vendor Identification");
2837 uniqueStringPlistProperty(personalityDict, "Vendor Name");
2838 uniqueStringPlistProperty(personalityDict, "bConfigurationValue");
2839 uniqueStringPlistProperty(personalityDict, "bInterfaceNumber");
2840 uniqueStringPlistProperty(personalityDict, "idProduct");
2841
2842 return;
2843 }
2844
2845 /*********************************************************************
2846 *********************************************************************/
2847 void
2848 OSKext::free(void)
2849 {
2850 if (isLoaded()) {
2851 panic("Attempt to free loaded kext %s.", getIdentifierCString());
2852 }
2853
2854 infoDict.reset();
2855 bundleID.reset();
2856 path.reset();
2857 executableRelPath.reset();
2858 userExecutableRelPath.reset();
2859 dependencies.reset();
2860 linkedExecutable.reset();
2861 metaClasses.reset();
2862 interfaceUUID.reset();
2863 driverKitUUID.reset();
2864
2865 if (isInterface() && kmod_info) {
2866 kfree(kmod_info, sizeof(kmod_info_t));
2867 }
2868
2869 super::free();
2870 return;
2871 }
2872
2873 #if PRAGMA_MARK
2874 #pragma mark Mkext files
2875 #endif
2876
2877 #if CONFIG_KXLD
2878 /*
2879 * mkext archives are really only relevant on kxld-enabled kernels.
2880 * Without a dynamic kernel linker, we don't need to support any mkexts.
2881 */
2882
2883 /*********************************************************************
2884 *********************************************************************/
2885 OSReturn
2886 OSKext::readMkextArchive(OSData * mkextData,
2887 uint32_t * checksumPtr)
2888 {
2889 OSReturn result = kOSKextReturnBadData;
2890 uint32_t mkextLength = 0;
2891 mkext_header * mkextHeader = NULL; // do not free
2892 uint32_t mkextVersion = 0;
2893
2894 /* Note default return of kOSKextReturnBadData above.
2895 */
2896 mkextLength = mkextData->getLength();
2897 if (mkextLength < sizeof(mkext_basic_header)) {
2898 OSKextLog(/* kext */ NULL,
2899 kOSKextLogErrorLevel |
2900 kOSKextLogArchiveFlag,
2901 "Mkext archive too small to be valid.");
2902 goto finish;
2903 }
2904
2905 mkextHeader = (mkext_header *)mkextData->getBytesNoCopy();
2906
2907 if (MKEXT_GET_MAGIC(mkextHeader) != MKEXT_MAGIC ||
2908 MKEXT_GET_SIGNATURE(mkextHeader) != MKEXT_SIGN) {
2909 OSKextLog(/* kext */ NULL,
2910 kOSKextLogErrorLevel |
2911 kOSKextLogArchiveFlag,
2912 "Mkext archive has invalid magic or signature.");
2913 goto finish;
2914 }
2915
2916 if (MKEXT_GET_LENGTH(mkextHeader) != mkextLength) {
2917 OSKextLog(/* kext */ NULL,
2918 kOSKextLogErrorLevel |
2919 kOSKextLogArchiveFlag,
2920 "Mkext archive recorded length doesn't match actual file length.");
2921 goto finish;
2922 }
2923
2924 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2925
2926 if (mkextVersion == MKEXT_VERS_2) {
2927 result = OSKext::readMkext2Archive(mkextData, NULL, checksumPtr);
2928 } else {
2929 OSKextLog(/* kext */ NULL,
2930 kOSKextLogErrorLevel |
2931 kOSKextLogArchiveFlag,
2932 "Mkext archive of unsupported mkext version 0x%x.", mkextVersion);
2933 result = kOSKextReturnUnsupported;
2934 }
2935
2936 finish:
2937 return result;
2938 }
2939
2940 /*********************************************************************
2941 * Assumes magic, signature, version, length have been checked.
2942 * xxx - need to add further bounds checking for each file entry
2943 *
2944 * Should keep track of all kexts created so far, and if we hit a
2945 * fatal error halfway through, remove those kexts. If we've dropped
2946 * an older version that had already been read, whoops! Might want to
2947 * add a level of buffering?
2948 *********************************************************************/
2949 /* static */
2950 OSReturn
2951 OSKext::readMkext2Archive(
2952 OSData * mkextData,
2953 OSDictionary ** mkextPlistOut,
2954 uint32_t * checksumPtr)
2955 {
2956 OSReturn result = kOSReturnError;
2957 uint32_t mkextLength;
2958 mkext2_header * mkextHeader = NULL; // do not free
2959 void * mkextEnd = NULL; // do not free
2960 uint32_t mkextVersion;
2961 uint8_t * crc_address = NULL;
2962 size_t crc_buffer_size = 0;
2963 uint32_t checksum;
2964 uint32_t mkextPlistOffset;
2965 uint32_t mkextPlistCompressedSize;
2966 char * mkextPlistEnd = NULL; // do not free
2967 uint32_t mkextPlistFullSize;
2968 OSSharedPtr<OSString> errorString;
2969 OSSharedPtr<OSData> mkextPlistUncompressedData;
2970 const char * mkextPlistDataBuffer = NULL; // do not free
2971 OSSharedPtr<OSObject> parsedXML;
2972 OSDictionary * mkextPlist = NULL; // do not release
2973 OSArray * mkextInfoDictArray = NULL; // do not release
2974 uint32_t count, i;
2975 kc_format_t kc_format;
2976
2977 if (!PE_get_primary_kc_format(&kc_format)) {
2978 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
2979 "Unable to determine primary KC format");
2980 goto finish;
2981 }
2982
2983 mkextLength = mkextData->getLength();
2984 mkextHeader = (mkext2_header *)mkextData->getBytesNoCopy();
2985 mkextEnd = (char *)mkextHeader + mkextLength;
2986 mkextVersion = MKEXT_GET_VERSION(mkextHeader);
2987
2988 crc_address = (u_int8_t *)&mkextHeader->version;
2989 crc_buffer_size = (uintptr_t)mkextHeader +
2990 MKEXT_GET_LENGTH(mkextHeader) - (uintptr_t)crc_address;
2991 if (crc_buffer_size > INT32_MAX) {
2992 OSKextLog(/* kext */ NULL,
2993 kOSKextLogErrorLevel |
2994 kOSKextLogArchiveFlag,
2995 "Mkext archive size is too large (%lu > INT32_MAX).",
2996 crc_buffer_size);
2997 result = kOSKextReturnBadData;
2998 goto finish;
2999 }
3000 checksum = mkext_adler32(crc_address, (int32_t)crc_buffer_size);
3001
3002 if (MKEXT_GET_CHECKSUM(mkextHeader) != checksum) {
3003 OSKextLog(/* kext */ NULL,
3004 kOSKextLogErrorLevel |
3005 kOSKextLogArchiveFlag,
3006 "Mkext archive has bad checksum.");
3007 result = kOSKextReturnBadData;
3008 goto finish;
3009 }
3010
3011 if (checksumPtr) {
3012 *checksumPtr = checksum;
3013 }
3014
3015 /* Check that the CPU type & subtype match that of the running kernel. */
3016 if (MKEXT_GET_CPUTYPE(mkextHeader) == (UInt32)CPU_TYPE_ANY) {
3017 OSKextLog(/* kext */ NULL,
3018 kOSKextLogErrorLevel |
3019 kOSKextLogArchiveFlag,
3020 "Mkext archive must have a specific CPU type.");
3021 result = kOSKextReturnBadData;
3022 goto finish;
3023 } else {
3024 if ((UInt32)_mh_execute_header.cputype !=
3025 MKEXT_GET_CPUTYPE(mkextHeader)) {
3026 OSKextLog(/* kext */ NULL,
3027 kOSKextLogErrorLevel |
3028 kOSKextLogArchiveFlag,
3029 "Mkext archive does not match the running kernel's CPU type.");
3030 result = kOSKextReturnArchNotFound;
3031 goto finish;
3032 }
3033 }
3034
3035 mkextPlistOffset = MKEXT2_GET_PLIST(mkextHeader);
3036 mkextPlistCompressedSize = MKEXT2_GET_PLIST_COMPSIZE(mkextHeader);
3037 mkextPlistEnd = (char *)mkextHeader + mkextPlistOffset +
3038 mkextPlistCompressedSize;
3039 if (mkextPlistEnd > mkextEnd) {
3040 OSKextLog(/* kext */ NULL,
3041 kOSKextLogErrorLevel |
3042 kOSKextLogArchiveFlag,
3043 "Mkext archive file overrun.");
3044 result = kOSKextReturnBadData;
3045 }
3046
3047 mkextPlistFullSize = MKEXT2_GET_PLIST_FULLSIZE(mkextHeader);
3048 if (mkextPlistCompressedSize) {
3049 mkextPlistUncompressedData = sKernelKext->extractMkext2FileData(
3050 (UInt8 *)mkextHeader + mkextPlistOffset,
3051 "plist",
3052 mkextPlistCompressedSize, mkextPlistFullSize);
3053 if (!mkextPlistUncompressedData) {
3054 goto finish;
3055 }
3056 mkextPlistDataBuffer = (const char *)
3057 mkextPlistUncompressedData->getBytesNoCopy();
3058 } else {
3059 mkextPlistDataBuffer = (const char *)mkextHeader + mkextPlistOffset;
3060 }
3061
3062 /* IOCFSerialize added a nul byte to the end of the string. Very nice of it.
3063 */
3064 parsedXML = OSUnserializeXML(mkextPlistDataBuffer, errorString);
3065 if (parsedXML) {
3066 mkextPlist = OSDynamicCast(OSDictionary, parsedXML.get());
3067 }
3068 if (!mkextPlist) {
3069 const char * errorCString = "(unknown error)";
3070
3071 if (errorString && errorString->getCStringNoCopy()) {
3072 errorCString = errorString->getCStringNoCopy();
3073 } else if (parsedXML) {
3074 errorCString = "not a dictionary";
3075 }
3076 OSKextLog(/* kext */ NULL,
3077 kOSKextLogErrorLevel |
3078 kOSKextLogArchiveFlag,
3079 "Error unserializing mkext plist: %s.", errorCString);
3080 goto finish;
3081 }
3082
3083 mkextInfoDictArray = OSDynamicCast(OSArray,
3084 mkextPlist->getObject(kMKEXTInfoDictionariesKey));
3085 if (!mkextInfoDictArray) {
3086 OSKextLog(/* kext */ NULL,
3087 kOSKextLogErrorLevel |
3088 kOSKextLogArchiveFlag,
3089 "Mkext archive contains no kext info dictionaries.");
3090 goto finish;
3091 }
3092
3093 count = mkextInfoDictArray->getCount();
3094 for (i = 0; i < count; i++) {
3095 OSDictionary * infoDict;
3096
3097
3098 infoDict = OSDynamicCast(OSDictionary,
3099 mkextInfoDictArray->getObject(i));
3100
3101 /* Create the kext for the entry, then release it, because the
3102 * kext system keeps them around until explicitly removed.
3103 * Any creation/registration failures are already logged for us.
3104 */
3105 if (infoDict) {
3106 OSSharedPtr<OSKext> newKext = OSKext::withMkext2Info(infoDict, mkextData);
3107
3108 /* Fail dynamic loading of a kext when booted from MH_FILESET */
3109 if (kc_format == KCFormatFileset &&
3110 newKext &&
3111 !(newKext->isPrelinked()) &&
3112 newKext->declaresExecutable()) {
3113 result = kOSReturnError;
3114 printf("Kext LOG: Dynamic loading of kext denied for kext %s\n",
3115 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3116
3117 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
3118 "Dynamic loading of kext denied for kext %s\n",
3119 newKext->getIdentifier() ? newKext->getIdentifierCString() : "unknown kext");
3120 goto finish;
3121 }
3122 }
3123 }
3124
3125 /* If the caller needs the plist, hand them back our copy
3126 */
3127 if (mkextPlistOut) {
3128 *mkextPlistOut = mkextPlist;
3129 parsedXML.detach();
3130 }
3131
3132 /* Even if we didn't keep any kexts from the mkext, we may have a load
3133 * request to process, so we are successful (no errors occurred).
3134 */
3135 result = kOSReturnSuccess;
3136
3137 finish:
3138 return result;
3139 }
3140
3141 /* static */
3142 OSReturn
3143 OSKext::readMkext2Archive(
3144 OSData * mkextData,
3145 OSSharedPtr<OSDictionary> &mkextPlistOut,
3146 uint32_t * checksumPtr)
3147 {
3148 OSDictionary * mkextPlist = NULL;
3149 OSReturn ret;
3150
3151 if (kOSReturnSuccess == (ret = readMkext2Archive(mkextData,
3152 &mkextPlist,
3153 checksumPtr))) {
3154 mkextPlistOut.reset(mkextPlist, OSNoRetain);
3155 }
3156 return ret;
3157 }
3158
3159 /*********************************************************************
3160 *********************************************************************/
3161 /* static */
3162 OSSharedPtr<OSKext>
3163 OSKext::withMkext2Info(
3164 OSDictionary * anInfoDict,
3165 OSData * mkextData)
3166 {
3167 OSSharedPtr<OSKext> newKext = OSMakeShared<OSKext>();
3168
3169 if (newKext && !newKext->initWithMkext2Info(anInfoDict, mkextData)) {
3170 return NULL;
3171 }
3172
3173 return newKext;
3174 }
3175
3176 /*********************************************************************
3177 *********************************************************************/
3178 bool
3179 OSKext::initWithMkext2Info(
3180 OSDictionary * anInfoDict,
3181 OSData * mkextData)
3182 {
3183 bool result = false;
3184 OSString * kextPath = NULL; // do not release
3185 OSNumber * executableOffsetNum = NULL; // do not release
3186 OSSharedPtr<OSData> executable;
3187
3188 if (anInfoDict == NULL || !super::init()) {
3189 goto finish;
3190 }
3191
3192 /* Get the path. Don't look for an arch-specific path property.
3193 */
3194 kextPath = OSDynamicCast(OSString,
3195 anInfoDict->getObject(kMKEXTBundlePathKey));
3196
3197 if (!setInfoDictionaryAndPath(anInfoDict, kextPath)) {
3198 goto finish;
3199 }
3200
3201 /* If we have a path to the executable, save it.
3202 */
3203 executableRelPath.reset(OSDynamicCast(OSString,
3204 anInfoDict->getObject(kMKEXTExecutableRelativePathKey)), OSRetain);
3205
3206 /* Don't need the paths to be in the info dictionary any more.
3207 */
3208 anInfoDict->removeObject(kMKEXTBundlePathKey);
3209 anInfoDict->removeObject(kMKEXTExecutableRelativePathKey);
3210
3211 executableOffsetNum = OSDynamicCast(OSNumber,
3212 infoDict->getObject(kMKEXTExecutableKey));
3213 if (executableOffsetNum) {
3214 executable = createMkext2FileEntry(mkextData,
3215 executableOffsetNum, "executable");
3216 infoDict->removeObject(kMKEXTExecutableKey);
3217 if (!executable) {
3218 goto finish;
3219 }
3220 if (!setExecutable(executable.get(), mkextData, true)) {
3221 goto finish;
3222 }
3223 }
3224
3225 result = registerIdentifier();
3226
3227 finish:
3228 return result;
3229 }
3230
3231 /*********************************************************************
3232 *********************************************************************/
3233 OSSharedPtr<OSData>
3234 OSKext::createMkext2FileEntry(
3235 OSData * mkextData,
3236 OSNumber * offsetNum,
3237 const char * name)
3238 {
3239 OSSharedPtr<OSData> result;
3240 MkextEntryRef entryRef;
3241 uint8_t * mkextBuffer = (uint8_t *)mkextData->getBytesNoCopy();
3242 uint32_t entryOffset = offsetNum->unsigned32BitValue();
3243
3244 result = OSData::withCapacity(sizeof(entryRef));
3245 if (!result) {
3246 goto finish;
3247 }
3248
3249 entryRef.mkext = (mkext_basic_header *)mkextBuffer;
3250 entryRef.fileinfo = mkextBuffer + entryOffset;
3251 if (!result->appendBytes(&entryRef, sizeof(entryRef))) {
3252 result.reset();
3253 goto finish;
3254 }
3255
3256 finish:
3257 if (!result) {
3258 OSKextLog(this,
3259 kOSKextLogErrorLevel |
3260 kOSKextLogArchiveFlag,
3261 "Can't create wrapper for mkext file entry '%s' of kext %s.",
3262 name, getIdentifierCString());
3263 }
3264 return result;
3265 }
3266
3267 /*********************************************************************
3268 *********************************************************************/
3269 extern "C" {
3270 static void * z_alloc(void *, u_int items, u_int size);
3271 static void z_free(void *, void *ptr);
3272
3273 typedef struct z_mem {
3274 uint32_t alloc_size;
3275 uint8_t data[0];
3276 } z_mem;
3277
3278 /*
3279 * Space allocation and freeing routines for use by zlib routines.
3280 */
3281 void *
3282 z_alloc(void * notused __unused, u_int num_items, u_int size)
3283 {
3284 void * result = NULL;
3285 z_mem * zmem = NULL;
3286
3287 uint64_t total = ((uint64_t)num_items) * ((uint64_t)size);
3288 //Check for overflow due to multiplication
3289 if (total > UINT32_MAX) {
3290 panic("z_alloc(%p, %x, %x): overflow caused by %x * %x\n",
3291 notused, num_items, size, num_items, size);
3292 }
3293
3294 uint64_t allocSize64 = total + ((uint64_t)sizeof(zmem));
3295 //Check for overflow due to addition
3296 if (allocSize64 > UINT32_MAX) {
3297 panic("z_alloc(%p, %x, %x): overflow caused by %x + %lx\n",
3298 notused, num_items, size, (uint32_t)total, sizeof(zmem));
3299 }
3300 uint32_t allocSize = (uint32_t)allocSize64;
3301
3302 zmem = (z_mem *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, allocSize,
3303 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
3304 if (!zmem) {
3305 goto finish;
3306 }
3307 zmem->alloc_size = allocSize;
3308 result = (void *)&(zmem->data);
3309 finish:
3310 return result;
3311 }
3312
3313 void
3314 z_free(void * notused __unused, void * ptr)
3315 {
3316 uint32_t * skipper = (uint32_t *)ptr - 1;
3317 z_mem * zmem = (z_mem *)skipper;
3318 kheap_free(KHEAP_DATA_BUFFERS, zmem, zmem->alloc_size);
3319 return;
3320 }
3321 };
3322
3323 OSSharedPtr<OSData>
3324 OSKext::extractMkext2FileData(
3325 UInt8 * data,
3326 const char * name,
3327 uint32_t compressedSize,
3328 uint32_t fullSize)
3329 {
3330 OSSharedPtr<OSData> result;
3331 OSSharedPtr<OSData> uncompressedData; // release on error
3332
3333 uint8_t * uncompressedDataBuffer = NULL; // do not free
3334 unsigned long uncompressedSize;
3335 z_stream zstream;
3336 bool zstream_inited = false;
3337 int zlib_result;
3338
3339 /* If the file isn't compressed, we want to make a copy
3340 * so that we don't have the tie to the larger mkext file buffer any more.
3341 */
3342 if (!compressedSize) {
3343 uncompressedData = OSData::withBytes(data, fullSize);
3344 // xxx - no check for failure?
3345 result = uncompressedData;
3346 goto finish;
3347 }
3348
3349 if (KERN_SUCCESS != kmem_alloc(kernel_map,
3350 (vm_offset_t*)&uncompressedDataBuffer, fullSize, VM_KERN_MEMORY_OSKEXT)) {
3351 /* How's this for cheesy? The kernel is only asked to extract
3352 * kext plists so we tailor the log messages.
3353 */
3354 if (isKernel()) {
3355 OSKextLog(this,
3356 kOSKextLogErrorLevel |
3357 kOSKextLogArchiveFlag,
3358 "Allocation failure extracting %s from mkext.", name);
3359 } else {
3360 OSKextLog(this,
3361 kOSKextLogErrorLevel |
3362 kOSKextLogArchiveFlag,
3363 "Allocation failure extracting %s from mkext for kext %s.",
3364 name, getIdentifierCString());
3365 }
3366
3367 goto finish;
3368 }
3369 uncompressedData = OSData::withBytesNoCopy(uncompressedDataBuffer, fullSize);
3370 if (!uncompressedData) {
3371 if (isKernel()) {
3372 OSKextLog(this,
3373 kOSKextLogErrorLevel |
3374 kOSKextLogArchiveFlag,
3375 "Allocation failure extracting %s from mkext.", name);
3376 } else {
3377 OSKextLog(this,
3378 kOSKextLogErrorLevel |
3379 kOSKextLogArchiveFlag,
3380 "Allocation failure extracting %s from mkext for kext %s.",
3381 name, getIdentifierCString());
3382 }
3383 goto finish;
3384 }
3385 uncompressedData->setDeallocFunction(&osdata_kmem_free);
3386
3387 if (isKernel()) {
3388 OSKextLog(this,
3389 kOSKextLogDetailLevel |
3390 kOSKextLogArchiveFlag,
3391 "Kernel extracted %s from mkext - compressed size %d, uncompressed size %d.",
3392 name, compressedSize, fullSize);
3393 } else {
3394 OSKextLog(this,
3395 kOSKextLogDetailLevel |
3396 kOSKextLogArchiveFlag,
3397 "Kext %s extracted %s from mkext - compressed size %d, uncompressed size %d.",
3398 getIdentifierCString(), name, compressedSize, fullSize);
3399 }
3400
3401 bzero(&zstream, sizeof(zstream));
3402 zstream.next_in = (UInt8 *)data;
3403 zstream.avail_in = compressedSize;
3404
3405 zstream.next_out = uncompressedDataBuffer;
3406 zstream.avail_out = fullSize;
3407
3408 zstream.zalloc = z_alloc;
3409 zstream.zfree = z_free;
3410
3411 zlib_result = inflateInit(&zstream);
3412 if (Z_OK != zlib_result) {
3413 if (isKernel()) {
3414 OSKextLog(this,
3415 kOSKextLogErrorLevel |
3416 kOSKextLogArchiveFlag,
3417 "Mkext error; zlib inflateInit failed (%d) for %s.",
3418 zlib_result, name);
3419 } else {
3420 OSKextLog(this,
3421 kOSKextLogErrorLevel |
3422 kOSKextLogArchiveFlag,
3423 "Kext %s - mkext error; zlib inflateInit failed (%d) for %s .",
3424 getIdentifierCString(), zlib_result, name);
3425 }
3426 goto finish;
3427 } else {
3428 zstream_inited = true;
3429 }
3430
3431 zlib_result = inflate(&zstream, Z_FINISH);
3432
3433 if (zlib_result == Z_STREAM_END || zlib_result == Z_OK) {
3434 uncompressedSize = zstream.total_out;
3435 } else {
3436 if (isKernel()) {
3437 OSKextLog(this,
3438 kOSKextLogErrorLevel |
3439 kOSKextLogArchiveFlag,
3440 "Mkext error; zlib inflate failed (%d) for %s.",
3441 zlib_result, name);
3442 } else {
3443 OSKextLog(this,
3444 kOSKextLogErrorLevel |
3445 kOSKextLogArchiveFlag,
3446 "Kext %s - mkext error; zlib inflate failed (%d) for %s .",
3447 getIdentifierCString(), zlib_result, name);
3448 }
3449 if (zstream.msg) {
3450 OSKextLog(this,
3451 kOSKextLogErrorLevel |
3452 kOSKextLogArchiveFlag,
3453 "zlib error: %s.", zstream.msg);
3454 }
3455 goto finish;
3456 }
3457
3458 if (uncompressedSize != fullSize) {
3459 if (isKernel()) {
3460 OSKextLog(this,
3461 kOSKextLogErrorLevel |
3462 kOSKextLogArchiveFlag,
3463 "Mkext error; zlib inflate discrepancy for %s, "
3464 "uncompressed size != original size.", name);
3465 } else {
3466 OSKextLog(this,
3467 kOSKextLogErrorLevel |
3468 kOSKextLogArchiveFlag,
3469 "Kext %s - mkext error; zlib inflate discrepancy for %s, "
3470 "uncompressed size != original size.",
3471 getIdentifierCString(), name);
3472 }
3473 goto finish;
3474 }
3475
3476 result = os::move(uncompressedData);
3477
3478 finish:
3479 /* Don't bother checking return, nothing we can do on fail.
3480 */
3481 if (zstream_inited) {
3482 inflateEnd(&zstream);
3483 }
3484
3485 return result;
3486 }
3487
3488 /*********************************************************************
3489 *********************************************************************/
3490 /* static */
3491 OSReturn
3492 OSKext::loadFromMkext(
3493 OSKextLogSpec clientLogFilter,
3494 char * mkextBuffer,
3495 uint32_t mkextBufferLength,
3496 char ** logInfoOut,
3497 uint32_t * logInfoLengthOut)
3498 {
3499 OSReturn result = kOSReturnError;
3500 OSReturn tempResult = kOSReturnError;
3501
3502 OSSharedPtr<OSData> mkextData;
3503 OSSharedPtr<OSDictionary> mkextPlist;
3504
3505 OSSharedPtr<OSArray> logInfoArray;
3506 OSSharedPtr<OSSerialize> serializer;
3507
3508 OSString * predicate = NULL; // do not release
3509 OSDictionary * requestArgs = NULL; // do not release
3510
3511 OSString * kextIdentifier = NULL; // do not release
3512 OSNumber * startKextExcludeNum = NULL; // do not release
3513 OSNumber * startMatchingExcludeNum = NULL; // do not release
3514 OSBoolean * delayAutounloadBool = NULL; // do not release
3515 OSArray * personalityNames = NULL; // do not release
3516
3517 /* Default values for these two options: regular autounload behavior,
3518 * load all kexts, send no personalities.
3519 */
3520 Boolean delayAutounload = false;
3521 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
3522 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeAll;
3523
3524 IORecursiveLockLock(sKextLock);
3525
3526 if (logInfoOut) {
3527 *logInfoOut = NULL;
3528 *logInfoLengthOut = 0;
3529 }
3530
3531 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
3532
3533 OSKextLog(/* kext */ NULL,
3534 kOSKextLogDebugLevel |
3535 kOSKextLogIPCFlag,
3536 "Received kext load request from user space.");
3537
3538 /* Regardless of processing, the fact that we have gotten here means some
3539 * user-space program is up and talking to us, so we'll switch our kext
3540 * registration to reflect that.
3541 */
3542 if (!sUserLoadsActive) {
3543 OSKextLog(/* kext */ NULL,
3544 kOSKextLogProgressLevel |
3545 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
3546 "Switching to late startup (user-space) kext loading policy.");
3547
3548 sUserLoadsActive = true;
3549 }
3550
3551 if (!sLoadEnabled) {
3552 OSKextLog(/* kext */ NULL,
3553 kOSKextLogErrorLevel |
3554 kOSKextLogLoadFlag,
3555 "Kext loading is disabled.");
3556 result = kOSKextReturnDisabled;
3557 goto finish;
3558 }
3559
3560 /* Note that we do not set a dealloc function on this OSData
3561 * object! No references to it can remain after the loadFromMkext()
3562 * call since we are in a MIG function, and will vm_deallocate()
3563 * the buffer.
3564 */
3565 mkextData = OSData::withBytesNoCopy(mkextBuffer,
3566 mkextBufferLength);
3567 if (!mkextData) {
3568 OSKextLog(/* kext */ NULL,
3569 kOSKextLogErrorLevel |
3570 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3571 "Failed to create wrapper for kext load request.");
3572 result = kOSKextReturnNoMemory;
3573 goto finish;
3574 }
3575
3576 result = readMkext2Archive(mkextData.get(), mkextPlist, NULL);
3577 if (result != kOSReturnSuccess) {
3578 OSKextLog(/* kext */ NULL,
3579 kOSKextLogErrorLevel |
3580 kOSKextLogLoadFlag,
3581 "Failed to read kext load request.");
3582 goto finish;
3583 }
3584
3585 predicate = _OSKextGetRequestPredicate(mkextPlist.get());
3586 if (!predicate || !predicate->isEqualTo(kKextRequestPredicateLoad)) {
3587 OSKextLog(/* kext */ NULL,
3588 kOSKextLogErrorLevel |
3589 kOSKextLogLoadFlag,
3590 "Received kext load request with no predicate; skipping.");
3591 result = kOSKextReturnInvalidArgument;
3592 goto finish;
3593 }
3594
3595 requestArgs = OSDynamicCast(OSDictionary,
3596 mkextPlist->getObject(kKextRequestArgumentsKey));
3597 if (!requestArgs || !requestArgs->getCount()) {
3598 OSKextLog(/* kext */ NULL,
3599 kOSKextLogErrorLevel |
3600 kOSKextLogLoadFlag,
3601 "Received kext load request with no arguments.");
3602 result = kOSKextReturnInvalidArgument;
3603 goto finish;
3604 }
3605
3606 kextIdentifier = OSDynamicCast(OSString,
3607 requestArgs->getObject(kKextRequestArgumentBundleIdentifierKey));
3608
3609 if (!kextIdentifier) {
3610 OSKextLog(/* kext */ NULL,
3611 kOSKextLogErrorLevel |
3612 kOSKextLogLoadFlag,
3613 "Received kext load request with no kext identifier.");
3614 result = kOSKextReturnInvalidArgument;
3615 goto finish;
3616 }
3617
3618 startKextExcludeNum = OSDynamicCast(OSNumber,
3619 requestArgs->getObject(kKextRequestArgumentStartExcludeKey));
3620 startMatchingExcludeNum = OSDynamicCast(OSNumber,
3621 requestArgs->getObject(kKextRequestArgumentStartMatchingExcludeKey));
3622 delayAutounloadBool = OSDynamicCast(OSBoolean,
3623 requestArgs->getObject(kKextRequestArgumentDelayAutounloadKey));
3624 personalityNames = OSDynamicCast(OSArray,
3625 requestArgs->getObject(kKextRequestArgumentPersonalityNamesKey));
3626
3627 if (delayAutounloadBool) {
3628 delayAutounload = delayAutounloadBool->getValue();
3629 }
3630 if (startKextExcludeNum) {
3631 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
3632 }
3633 if (startMatchingExcludeNum) {
3634 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
3635 }
3636
3637 OSKextLog(/* kext */ NULL,
3638 kOSKextLogProgressLevel |
3639 kOSKextLogIPCFlag,
3640 "Received request from user space to load kext %s.",
3641 kextIdentifier->getCStringNoCopy());
3642
3643 /* Load the kext, with no deferral, since this is a load from outside
3644 * the kernel.
3645 * xxx - Would like a better way to handle the default values for the
3646 * xxx - start/match opt args.
3647 */
3648 result = OSKext::loadKextWithIdentifier(
3649 kextIdentifier,
3650 /* kextRef */ NULL,
3651 /* allowDefer */ false,
3652 delayAutounload,
3653 startKextExcludeLevel,
3654 startMatchingExcludeLevel,
3655 personalityNames);
3656 if (result != kOSReturnSuccess) {
3657 goto finish;
3658 }
3659 /* If the load came down from the IOKit daemon, it will shortly inform IOCatalogue
3660 * for matching via a separate IOKit calldown.
3661 */
3662
3663 finish:
3664
3665 /* Gather up the collected log messages for user space. Any
3666 * error messages past this call will not make it up as log messages
3667 * but will be in the system log.
3668 */
3669 logInfoArray = OSKext::clearUserSpaceLogFilter();
3670
3671 if (logInfoArray && logInfoOut && logInfoLengthOut) {
3672 tempResult = OSKext::serializeLogInfo(logInfoArray.get(),
3673 logInfoOut, logInfoLengthOut);
3674 if (tempResult != kOSReturnSuccess) {
3675 result = tempResult;
3676 }
3677 }
3678
3679 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ false);
3680
3681 IORecursiveLockUnlock(sKextLock);
3682
3683 /* Note: mkextDataObject will have been retained by every kext w/an
3684 * executable in it. That should all have been flushed out at the
3685 * and of the load operation, but you never know....
3686 */
3687 if (mkextData && mkextData->getRetainCount() > 1) {
3688 OSKextLog(/* kext */ NULL,
3689 kOSKextLogErrorLevel |
3690 kOSKextLogLoadFlag | kOSKextLogIPCFlag,
3691 "Kext load request buffer from user space still retained by a kext; "
3692 "probable memory leak.");
3693 }
3694
3695 return result;
3696 }
3697
3698 #endif // CONFIG_KXLD
3699
3700 /*********************************************************************
3701 *********************************************************************/
3702 /* static */
3703 OSReturn
3704 OSKext::serializeLogInfo(
3705 OSArray * logInfoArray,
3706 char ** logInfoOut,
3707 uint32_t * logInfoLengthOut)
3708 {
3709 OSReturn result = kOSReturnError;
3710 char * buffer = NULL;
3711 kern_return_t kmem_result = KERN_FAILURE;
3712 OSSharedPtr<OSSerialize> serializer;
3713 char * logInfo = NULL; // returned by reference
3714 uint32_t logInfoLength = 0;
3715
3716 if (!logInfoArray || !logInfoOut || !logInfoLengthOut) {
3717 OSKextLog(/* kext */ NULL,
3718 kOSKextLogErrorLevel |
3719 kOSKextLogIPCFlag,
3720 "Internal error; invalid arguments to OSKext::serializeLogInfo().");
3721 /* Bad programmer. */
3722 result = kOSKextReturnInvalidArgument;
3723 goto finish;
3724 }
3725
3726 serializer = OSSerialize::withCapacity(0);
3727 if (!serializer) {
3728 OSKextLog(/* kext */ NULL,
3729 kOSKextLogErrorLevel |
3730 kOSKextLogIPCFlag,
3731 "Failed to create serializer on log info for request from user space.");
3732 /* Incidental error; we're going to (try to) allow the request
3733 * itself to succeed. */
3734 }
3735
3736 if (!logInfoArray->serialize(serializer.get())) {
3737 OSKextLog(/* kext */ NULL,
3738 kOSKextLogErrorLevel |
3739 kOSKextLogIPCFlag,
3740 "Failed to serialize log info for request from user space.");
3741 /* Incidental error; we're going to (try to) allow the request
3742 * itself to succeed. */
3743 } else {
3744 logInfo = serializer->text();
3745 logInfoLength = serializer->getLength();
3746
3747 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer, round_page(logInfoLength), VM_KERN_MEMORY_OSKEXT);
3748 if (kmem_result != KERN_SUCCESS) {
3749 OSKextLog(/* kext */ NULL,
3750 kOSKextLogErrorLevel |
3751 kOSKextLogIPCFlag,
3752 "Failed to copy log info for request from user space.");
3753 /* Incidental error; we're going to (try to) allow the request
3754 * to succeed. */
3755 } else {
3756 /* 11981737 - clear uninitialized data in last page */
3757 bzero((void *)(buffer + logInfoLength),
3758 (round_page(logInfoLength) - logInfoLength));
3759 memcpy(buffer, logInfo, logInfoLength);
3760 *logInfoOut = buffer;
3761 *logInfoLengthOut = logInfoLength;
3762 }
3763 }
3764
3765 result = kOSReturnSuccess;
3766 finish:
3767 return result;
3768 }
3769
3770 #if PRAGMA_MARK
3771 #pragma mark Instance Management Methods
3772 #endif
3773 /*********************************************************************
3774 *********************************************************************/
3775 OSSharedPtr<OSKext>
3776 OSKext::lookupKextWithIdentifier(const char * kextIdentifier)
3777 {
3778 OSSharedPtr<OSKext> foundKext;
3779
3780 IORecursiveLockLock(sKextLock);
3781 foundKext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier)), OSRetain);
3782 IORecursiveLockUnlock(sKextLock);
3783
3784 return foundKext;
3785 }
3786
3787 /*********************************************************************
3788 *********************************************************************/
3789 OSSharedPtr<OSKext>
3790 OSKext::lookupKextWithIdentifier(OSString * kextIdentifier)
3791 {
3792 return OSKext::lookupKextWithIdentifier(kextIdentifier->getCStringNoCopy());
3793 }
3794
3795 /*********************************************************************
3796 *********************************************************************/
3797 OSSharedPtr<OSKext>
3798 OSKext::lookupKextWithLoadTag(uint32_t aTag)
3799 {
3800 OSSharedPtr<OSKext> foundKext; // returned
3801 uint32_t i, j;
3802 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3803 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3804
3805 IORecursiveLockLock(sKextLock);
3806
3807 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3808 for (i = 0; i < count[j]; i++) {
3809 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3810 if (thisKext->getLoadTag() == aTag) {
3811 foundKext.reset(thisKext, OSRetain);
3812 goto finish;
3813 }
3814 }
3815 }
3816
3817 finish:
3818 IORecursiveLockUnlock(sKextLock);
3819
3820 return foundKext;
3821 }
3822
3823 /*********************************************************************
3824 *********************************************************************/
3825 OSSharedPtr<OSKext>
3826 OSKext::lookupKextWithAddress(vm_address_t address)
3827 {
3828 OSSharedPtr<OSKext> foundKext; // returned
3829 uint32_t count, i;
3830 kmod_info_t *kmod_info;
3831 vm_address_t originalAddress;
3832 #if defined(__arm64__)
3833 uint64_t textExecBase;
3834 size_t textExecSize;
3835 #endif /* defined(__arm64__) */
3836
3837 originalAddress = address;
3838 #if __has_feature(ptrauth_calls)
3839 address = (vm_address_t)VM_KERNEL_STRIP_PTR(address);
3840 #endif /* __has_feature(ptrauth_calls) */
3841
3842 IORecursiveLockLock(sKextLock);
3843
3844 count = sLoadedKexts->getCount();
3845 for (i = 0; i < count; i++) {
3846 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
3847 if (thisKext == sKernelKext) {
3848 continue;
3849 }
3850 if (thisKext->kmod_info && thisKext->kmod_info->address) {
3851 kmod_info = thisKext->kmod_info;
3852 vm_address_t kext_start = kmod_info->address;
3853 vm_address_t kext_end = kext_start + kmod_info->size;
3854 if ((kext_start <= address) && (address < kext_end)) {
3855 foundKext.reset(thisKext, OSRetain);
3856 goto finish;
3857 }
3858 #if defined(__arm64__)
3859 textExecBase = (uintptr_t) getsegdatafromheader((kernel_mach_header_t *)kmod_info->address, "__TEXT_EXEC", &textExecSize);
3860 if ((textExecBase <= address) && (address < textExecBase + textExecSize)) {
3861 foundKext.reset(thisKext, OSRetain);
3862 goto finish;
3863 }
3864 #endif /* defined (__arm64__) */
3865 }
3866 }
3867 if ((address >= vm_kernel_stext) && (address < vm_kernel_etext)) {
3868 foundKext.reset(sKernelKext, OSRetain);
3869 goto finish;
3870 }
3871 /*
3872 * DriverKit userspace executables do not have a kernel linkedExecutable,
3873 * so we "fake" their address range with the LoadTag. We cannot use the ptrauth-stripped address
3874 * here, so use the original address passed to this method.
3875 *
3876 * This is supposed to be used for logging reasons only. When logd
3877 * calls this function it ors the address with FIREHOSE_TRACEPOINT_PC_KERNEL_MASK, so we
3878 * remove it here before checking it against the LoadTag.
3879 * Also we need to remove FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT set when emitting the log line.
3880 */
3881
3882 address = originalAddress & ~(FIREHOSE_TRACEPOINT_PC_KERNEL_MASK | FIREHOSE_TRACEPOINT_PC_DYNAMIC_BIT);
3883 count = sLoadedDriverKitKexts->getCount();
3884 for (i = 0; i < count; i++) {
3885 OSKext * thisKext = OSDynamicCast(OSKext, sLoadedDriverKitKexts->getObject(i));
3886 if (thisKext->getLoadTag() == address) {
3887 foundKext.reset(thisKext, OSRetain);
3888 }
3889 }
3890
3891 finish:
3892 IORecursiveLockUnlock(sKextLock);
3893
3894 return foundKext;
3895 }
3896
3897 OSSharedPtr<OSData>
3898 OSKext::copyKextUUIDForAddress(OSNumber *address)
3899 {
3900 OSSharedPtr<OSData> uuid;
3901 OSSharedPtr<OSKext> kext;
3902
3903 if (!address) {
3904 return NULL;
3905 }
3906
3907 #if CONFIG_MACF
3908 /* Is the calling process allowed to query kext info? */
3909 if (current_task() != kernel_task) {
3910 int macCheckResult = 0;
3911 kauth_cred_t cred = NULL;
3912
3913 cred = kauth_cred_get_with_ref();
3914 macCheckResult = mac_kext_check_query(cred);
3915 kauth_cred_unref(&cred);
3916
3917 if (macCheckResult != 0) {
3918 OSKextLog(/* kext */ NULL,
3919 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
3920 "Failed to query kext UUID (MAC policy error 0x%x).",
3921 macCheckResult);
3922 return NULL;
3923 }
3924 }
3925 #endif
3926
3927 uintptr_t slidAddress = ml_static_slide((uintptr_t)address->unsigned64BitValue());
3928 if (slidAddress != 0) {
3929 kext = lookupKextWithAddress(slidAddress);
3930 if (kext) {
3931 uuid = kext->copyTextUUID();
3932 }
3933 }
3934
3935 if (!uuid) {
3936 /*
3937 * If we still don't have a UUID, then we failed to match the slid + stripped address with
3938 * a kext. This might have happened because the log message came from a dext.
3939 *
3940 * Try again with the original address.
3941 */
3942 kext = lookupKextWithAddress((vm_address_t)address->unsigned64BitValue());
3943 if (kext && kext->isDriverKit()) {
3944 uuid = kext->copyTextUUID();
3945 }
3946 }
3947
3948 return uuid;
3949 }
3950
3951 /*********************************************************************
3952 *********************************************************************/
3953 OSSharedPtr<OSKext>
3954 OSKext::lookupKextWithUUID(uuid_t wanted)
3955 {
3956 OSSharedPtr<OSKext> foundKext; // returned
3957 uint32_t j, i;
3958 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
3959 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
3960
3961
3962 IORecursiveLockLock(sKextLock);
3963
3964 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
3965 for (i = 0; i < count[j]; i++) {
3966 OSKext * thisKext = NULL;
3967
3968 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
3969 if (!thisKext) {
3970 continue;
3971 }
3972
3973 OSSharedPtr<OSData> uuid_data = thisKext->copyUUID();
3974 if (!uuid_data) {
3975 continue;
3976 }
3977
3978 uuid_t uuid;
3979 memcpy(&uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
3980
3981 if (0 == uuid_compare(wanted, uuid)) {
3982 foundKext.reset(thisKext, OSRetain);
3983 goto finish;
3984 }
3985 }
3986 }
3987 finish:
3988 IORecursiveLockUnlock(sKextLock);
3989
3990 return foundKext;
3991 }
3992
3993
3994
3995
3996 /*********************************************************************
3997 *********************************************************************/
3998 /* static */
3999 bool
4000 OSKext::isKextWithIdentifierLoaded(const char * kextIdentifier)
4001 {
4002 bool result = false;
4003 OSKext * foundKext = NULL; // returned
4004
4005 IORecursiveLockLock(sKextLock);
4006
4007 foundKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
4008 if (foundKext && foundKext->isLoaded()) {
4009 result = true;
4010 }
4011
4012 IORecursiveLockUnlock(sKextLock);
4013
4014 return result;
4015 }
4016
4017 /*********************************************************************
4018 * xxx - should spawn a separate thread so a kext can safely have
4019 * xxx - itself unloaded.
4020 *********************************************************************/
4021 /* static */
4022 OSReturn
4023 OSKext::removeKext(
4024 OSKext * aKext,
4025 #if CONFIG_EMBEDDED
4026 __unused
4027 #endif
4028 bool terminateServicesAndRemovePersonalitiesFlag)
4029 {
4030 #if CONFIG_EMBEDDED
4031 OSKextLog(aKext,
4032 kOSKextLogErrorLevel |
4033 kOSKextLogKextBookkeepingFlag,
4034 "removeKext() called for %s, not supported on embedded",
4035 aKext->getIdentifier() ? aKext->getIdentifierCString() : "unknown kext");
4036
4037 return kOSReturnSuccess;
4038 #else /* CONFIG_EMBEDDED */
4039
4040 OSReturn result = kOSKextReturnInUse;
4041 OSKext * checkKext = NULL; // do not release
4042 #if CONFIG_MACF
4043 int macCheckResult = 0;
4044 kauth_cred_t cred = NULL;
4045 #endif
4046
4047 IORecursiveLockLock(sKextLock);
4048
4049 /* If the kext has no identifier, it failed to init
4050 * so isn't in sKextsByID and it isn't loaded.
4051 */
4052 if (!aKext->getIdentifier()) {
4053 result = kOSReturnSuccess;
4054 goto finish;
4055 }
4056
4057 checkKext = OSDynamicCast(OSKext,
4058 sKextsByID->getObject(aKext->getIdentifier()));
4059 if (checkKext != aKext) {
4060 result = kOSKextReturnNotFound;
4061 goto finish;
4062 }
4063
4064 if (aKext->isLoaded()) {
4065 #if CONFIG_MACF
4066 if (current_task() != kernel_task) {
4067 cred = kauth_cred_get_with_ref();
4068 macCheckResult = mac_kext_check_unload(cred, aKext->getIdentifierCString());
4069 kauth_cred_unref(&cred);
4070 }
4071
4072 if (macCheckResult != 0) {
4073 result = kOSReturnError;
4074 OSKextLog(aKext,
4075 kOSKextLogErrorLevel |
4076 kOSKextLogKextBookkeepingFlag,
4077 "Failed to remove kext %s (MAC policy error 0x%x).",
4078 aKext->getIdentifierCString(), macCheckResult);
4079 goto finish;
4080 }
4081 #endif
4082
4083 /* make sure there are no resource requests in flight - 17187548 */
4084 if (aKext->countRequestCallbacks()) {
4085 goto finish;
4086 }
4087
4088 /* If we are terminating, send the request to the IOCatalogue
4089 * (which will actually call us right back but that's ok we have
4090 * a recursive lock don't you know) but do not ask the IOCatalogue
4091 * to call back with an unload, we'll do that right here.
4092 */
4093 if (terminateServicesAndRemovePersonalitiesFlag) {
4094 result = gIOCatalogue->terminateDriversForModule(
4095 aKext->getIdentifierCString(), /* unload */ false);
4096 if (result != kOSReturnSuccess) {
4097 OSKextLog(aKext,
4098 kOSKextLogErrorLevel |
4099 kOSKextLogKextBookkeepingFlag,
4100 "Can't remove kext %s; services failed to terminate - 0x%x.",
4101 aKext->getIdentifierCString(), result);
4102 goto finish;
4103 }
4104 }
4105
4106 result = aKext->unload();
4107 if (result != kOSReturnSuccess) {
4108 goto finish;
4109 }
4110 }
4111
4112 /* Remove personalities as requested. This is a bit redundant for a loaded
4113 * kext as IOCatalogue::terminateDriversForModule() removes driver
4114 * personalities, but it doesn't restart matching, which we always want
4115 * coming from here, and OSKext::removePersonalitiesFromCatalog() ensures
4116 * that happens.
4117 */
4118 if (terminateServicesAndRemovePersonalitiesFlag) {
4119 aKext->removePersonalitiesFromCatalog();
4120 }
4121
4122 if (aKext->isInFileset()) {
4123 OSKextLog(aKext,
4124 kOSKextLogProgressLevel |
4125 kOSKextLogKextBookkeepingFlag,
4126 "Fileset kext %s unloaded.",
4127 aKext->getIdentifierCString());
4128 } else {
4129 OSKextLog(aKext,
4130 kOSKextLogProgressLevel |
4131 kOSKextLogKextBookkeepingFlag,
4132 "Removing kext %s.",
4133 aKext->getIdentifierCString());
4134
4135 sKextsByID->removeObject(aKext->getIdentifier());
4136 }
4137 result = kOSReturnSuccess;
4138
4139 finish:
4140 IORecursiveLockUnlock(sKextLock);
4141 return result;
4142 #endif /* CONFIG_EMBEDDED */
4143 }
4144
4145 /*********************************************************************
4146 *********************************************************************/
4147 /* static */
4148 OSReturn
4149 OSKext::removeKextWithIdentifier(
4150 const char * kextIdentifier,
4151 bool terminateServicesAndRemovePersonalitiesFlag)
4152 {
4153 OSReturn result = kOSReturnError;
4154
4155 IORecursiveLockLock(sKextLock);
4156
4157 OSKext * aKext = OSDynamicCast(OSKext,
4158 sKextsByID->getObject(kextIdentifier));
4159 if (!aKext) {
4160 result = kOSKextReturnNotFound;
4161 OSKextLog(/* kext */ NULL,
4162 kOSKextLogErrorLevel |
4163 kOSKextLogKextBookkeepingFlag,
4164 "Can't remove kext %s - not found.",
4165 kextIdentifier);
4166 goto finish;
4167 }
4168
4169 result = OSKext::removeKext(aKext,
4170 terminateServicesAndRemovePersonalitiesFlag);
4171
4172 finish:
4173 IORecursiveLockUnlock(sKextLock);
4174
4175 return result;
4176 }
4177
4178 /*********************************************************************
4179 *********************************************************************/
4180 /* static */
4181 OSReturn
4182 OSKext::removeKextWithLoadTag(
4183 OSKextLoadTag loadTag,
4184 bool terminateServicesAndRemovePersonalitiesFlag)
4185 {
4186 OSReturn result = kOSReturnError;
4187 OSKext * foundKext = NULL;
4188 uint32_t i, j;
4189 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
4190 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
4191
4192
4193 IORecursiveLockLock(sKextLock);
4194
4195 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
4196 for (i = 0; i < count[j]; i++) {
4197 OSKext * thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
4198 if (thisKext->loadTag == loadTag) {
4199 foundKext = thisKext;
4200 break;
4201 }
4202 }
4203 }
4204
4205 if (!foundKext) {
4206 result = kOSKextReturnNotFound;
4207 OSKextLog(/* kext */ NULL,
4208 kOSKextLogErrorLevel |
4209 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
4210 "Can't remove kext with load tag %d - not found.",
4211 loadTag);
4212 goto finish;
4213 }
4214
4215 result = OSKext::removeKext(foundKext,
4216 terminateServicesAndRemovePersonalitiesFlag);
4217
4218 finish:
4219 IORecursiveLockUnlock(sKextLock);
4220
4221 return result;
4222 }
4223
4224 /*********************************************************************
4225 *********************************************************************/
4226 OSSharedPtr<OSDictionary>
4227 OSKext::copyKexts(void)
4228 {
4229 OSSharedPtr<OSDictionary> result;
4230
4231 IORecursiveLockLock(sKextLock);
4232 result = OSDynamicPtrCast<OSDictionary>(sKextsByID->copyCollection());
4233 IORecursiveLockUnlock(sKextLock);
4234
4235 return result;
4236 }
4237
4238 /*********************************************************************
4239 *********************************************************************/
4240 #define BOOTER_KEXT_PREFIX "Driver-"
4241
4242 typedef struct _DeviceTreeBuffer {
4243 uint32_t paddr;
4244 uint32_t length;
4245 } _DeviceTreeBuffer;
4246
4247 /*********************************************************************
4248 * Create a dictionary of excluded kexts from the given booter data.
4249 *********************************************************************/
4250 /* static */
4251 void
4252 OSKext::createExcludeListFromBooterData(
4253 OSDictionary * theDictionary,
4254 OSCollectionIterator * theIterator )
4255 {
4256 OSString * deviceTreeName = NULL; // do not release
4257 const _DeviceTreeBuffer * deviceTreeBuffer = NULL; // do not release
4258 char * booterDataPtr = NULL; // do not release
4259 _BooterKextFileInfo * kextFileInfo = NULL; // do not release
4260 char * infoDictAddr = NULL; // do not release
4261 OSSharedPtr<OSObject> parsedXML;
4262 OSDictionary * theInfoDict = NULL; // do not release
4263
4264 theIterator->reset();
4265
4266 /* look for AppleKextExcludeList.kext */
4267 while ((deviceTreeName =
4268 OSDynamicCast(OSString, theIterator->getNextObject()))) {
4269 const char * devTreeNameCString;
4270 OSData * deviceTreeEntry; // do not release
4271 OSString * myBundleID; // do not release
4272
4273 deviceTreeEntry =
4274 OSDynamicCast(OSData, theDictionary->getObject(deviceTreeName));
4275 if (!deviceTreeEntry) {
4276 continue;
4277 }
4278
4279 /* Make sure it is a kext */
4280 devTreeNameCString = deviceTreeName->getCStringNoCopy();
4281 if (strncmp(devTreeNameCString, BOOTER_KEXT_PREFIX,
4282 (sizeof(BOOTER_KEXT_PREFIX) - 1)) != 0) {
4283 OSKextLog(NULL,
4284 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4285 "\"%s\" not a kext",
4286 devTreeNameCString);
4287 continue;
4288 }
4289
4290 deviceTreeBuffer = (const _DeviceTreeBuffer *)
4291 deviceTreeEntry->getBytesNoCopy(0, sizeof(deviceTreeBuffer));
4292 if (!deviceTreeBuffer) {
4293 continue;
4294 }
4295
4296 booterDataPtr = (char *)ml_static_ptovirt(deviceTreeBuffer->paddr);
4297 if (!booterDataPtr) {
4298 continue;
4299 }
4300
4301 kextFileInfo = (_BooterKextFileInfo *) booterDataPtr;
4302 if (!kextFileInfo->infoDictPhysAddr ||
4303 !kextFileInfo->infoDictLength) {
4304 continue;
4305 }
4306
4307 infoDictAddr = (char *)
4308 ml_static_ptovirt(kextFileInfo->infoDictPhysAddr);
4309 if (!infoDictAddr) {
4310 continue;
4311 }
4312
4313 parsedXML = OSUnserializeXML(infoDictAddr);
4314 if (!parsedXML) {
4315 continue;
4316 }
4317
4318 theInfoDict = OSDynamicCast(OSDictionary, parsedXML.get());
4319 if (!theInfoDict) {
4320 continue;
4321 }
4322
4323 myBundleID =
4324 OSDynamicCast(OSString,
4325 theInfoDict->getObject(kCFBundleIdentifierKey));
4326 if (myBundleID &&
4327 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4328 boolean_t updated = updateExcludeList(theInfoDict);
4329 if (!updated) {
4330 /* 25322874 */
4331 panic("Missing OSKextExcludeList dictionary\n");
4332 }
4333 break;
4334 }
4335 } // while ( (deviceTreeName = ...) )
4336
4337 return;
4338 }
4339
4340 /*********************************************************************
4341 * Create a dictionary of excluded kexts from the given prelink
4342 * info (kernelcache).
4343 *********************************************************************/
4344 /* static */
4345 void
4346 OSKext::createExcludeListFromPrelinkInfo( OSArray * theInfoArray )
4347 {
4348 OSDictionary * myInfoDict = NULL; // do not release
4349 OSString * myBundleID; // do not release
4350 u_int i;
4351
4352 /* Find the Apple Kext Exclude List. */
4353 for (i = 0; i < theInfoArray->getCount(); i++) {
4354 myInfoDict = OSDynamicCast(OSDictionary, theInfoArray->getObject(i));
4355 if (!myInfoDict) {
4356 continue;
4357 }
4358 myBundleID =
4359 OSDynamicCast(OSString,
4360 myInfoDict->getObject(kCFBundleIdentifierKey));
4361 if (myBundleID &&
4362 strcmp( myBundleID->getCStringNoCopy(), kIOExcludeListBundleID ) == 0) {
4363 boolean_t updated = updateExcludeList(myInfoDict);
4364 if (!updated) {
4365 /* 25322874 */
4366 panic("Missing OSKextExcludeList dictionary\n");
4367 }
4368 break;
4369 }
4370 } // for (i = 0; i < theInfoArray->getCount()...
4371
4372 return;
4373 }
4374
4375 /* static */
4376 boolean_t
4377 OSKext::updateExcludeList(OSDictionary *infoDict)
4378 {
4379 OSDictionary *myTempDict = NULL; // do not free
4380 OSString *myTempString = NULL; // do not free
4381 OSKextVersion newVersion = 0;
4382 boolean_t updated = false;
4383
4384 if (!infoDict) {
4385 return false;
4386 }
4387
4388 myTempDict = OSDynamicCast(OSDictionary, infoDict->getObject("OSKextExcludeList"));
4389 if (!myTempDict) {
4390 return false;
4391 }
4392
4393 myTempString = OSDynamicCast(OSString, infoDict->getObject(kCFBundleVersionKey));
4394 if (!myTempString) {
4395 return false;
4396 }
4397
4398 newVersion = OSKextParseVersionString(myTempString->getCStringNoCopy());
4399 if (newVersion == 0) {
4400 return false;
4401 }
4402
4403 IORecursiveLockLock(sKextLock);
4404
4405 if (newVersion > sExcludeListVersion) {
4406 sExcludeListByID = OSDictionary::withDictionary(myTempDict, 0);
4407 sExcludeListVersion = newVersion;
4408 updated = true;
4409 }
4410
4411 IORecursiveLockUnlock(sKextLock);
4412 return updated;
4413 }
4414
4415 #if PRAGMA_MARK
4416 #pragma mark Accessors
4417 #endif
4418 /*********************************************************************
4419 *********************************************************************/
4420 const OSSymbol *
4421 OSKext::getIdentifier(void)
4422 {
4423 return bundleID.get();
4424 }
4425
4426 /*********************************************************************
4427 * A kext must have a bundle identifier to even survive initialization;
4428 * this is guaranteed to exist past then.
4429 *********************************************************************/
4430 const char *
4431 OSKext::getIdentifierCString(void)
4432 {
4433 return bundleID->getCStringNoCopy();
4434 }
4435
4436 /*********************************************************************
4437 *********************************************************************/
4438 OSKextVersion
4439 OSKext::getVersion(void)
4440 {
4441 return version;
4442 }
4443
4444 /*********************************************************************
4445 *********************************************************************/
4446 OSKextVersion
4447 OSKext::getCompatibleVersion(void)
4448 {
4449 return compatibleVersion;
4450 }
4451
4452 /*********************************************************************
4453 *********************************************************************/
4454 bool
4455 OSKext::isLibrary(void)
4456 {
4457 return getCompatibleVersion() > 0;
4458 }
4459
4460 /*********************************************************************
4461 *********************************************************************/
4462 bool
4463 OSKext::isCompatibleWithVersion(OSKextVersion aVersion)
4464 {
4465 if ((compatibleVersion > -1 && version > -1) &&
4466 (compatibleVersion <= version && aVersion <= version)) {
4467 return true;
4468 }
4469 return false;
4470 }
4471
4472 /*********************************************************************
4473 *********************************************************************/
4474 bool
4475 OSKext::declaresExecutable(void)
4476 {
4477 if (isDriverKit()) {
4478 return false;
4479 }
4480 return getPropertyForHostArch(kCFBundleExecutableKey) != NULL;
4481 }
4482
4483 /*********************************************************************
4484 *********************************************************************/
4485 OSData *
4486 OSKext::getExecutable(void)
4487 {
4488 OSData * result = NULL;
4489 OSSharedPtr<OSData> extractedExecutable;
4490
4491 if (flags.builtin) {
4492 return sKernelKext->linkedExecutable.get();
4493 }
4494
4495 result = OSDynamicCast(OSData, infoDict->getObject(_kOSKextExecutableKey));
4496 if (result) {
4497 return result;
4498 }
4499
4500 #if CONFIG_KXLD
4501 OSData * mkextExecutableRef = NULL; // do not release
4502 mkextExecutableRef = OSDynamicCast(OSData,
4503 getPropertyForHostArch(_kOSKextMkextExecutableReferenceKey));
4504
4505 if (mkextExecutableRef) {
4506 MkextEntryRef * mkextEntryRef = (MkextEntryRef *)
4507 mkextExecutableRef->getBytesNoCopy();
4508 uint32_t mkextVersion = MKEXT_GET_VERSION(mkextEntryRef->mkext);
4509 if (mkextVersion == MKEXT_VERS_2) {
4510 mkext2_file_entry * fileinfo =
4511 (mkext2_file_entry *)mkextEntryRef->fileinfo;
4512 uint32_t compressedSize = MKEXT2_GET_ENTRY_COMPSIZE(fileinfo);
4513 uint32_t fullSize = MKEXT2_GET_ENTRY_FULLSIZE(fileinfo);
4514 extractedExecutable = extractMkext2FileData(
4515 MKEXT2_GET_ENTRY_DATA(fileinfo), "executable",
4516 compressedSize, fullSize);
4517 } else {
4518 OSKextLog(this, kOSKextLogErrorLevel |
4519 kOSKextLogArchiveFlag,
4520 "Kext %s - unknown mkext version 0x%x for executable.",
4521 getIdentifierCString(), mkextVersion);
4522 }
4523
4524 /* Regardless of success, remove the mkext executable,
4525 * and drop one reference on the mkext. (setExecutable() does not
4526 * replace, it removes, or panics if asked to replace.)
4527 */
4528 infoDict->removeObject(_kOSKextMkextExecutableReferenceKey);
4529 infoDict->removeObject(_kOSKextExecutableExternalDataKey);
4530
4531 if (extractedExecutable && extractedExecutable->getLength()) {
4532 if (!setExecutable(extractedExecutable.get())) {
4533 goto finish;
4534 }
4535 result = extractedExecutable.get();
4536 } else {
4537 goto finish;
4538 }
4539 }
4540
4541 finish:
4542 #endif // CONFIG_KXLD
4543 return result;
4544 }
4545
4546 /*********************************************************************
4547 *********************************************************************/
4548 bool
4549 OSKext::isInterface(void)
4550 {
4551 return flags.interface;
4552 }
4553
4554 /*********************************************************************
4555 *********************************************************************/
4556 bool
4557 OSKext::isKernel(void)
4558 {
4559 return this == sKernelKext;
4560 }
4561
4562 /*********************************************************************
4563 *********************************************************************/
4564 bool
4565 OSKext::isKernelComponent(void)
4566 {
4567 return flags.kernelComponent ? true : false;
4568 }
4569
4570 /*********************************************************************
4571 *********************************************************************/
4572 bool
4573 OSKext::isExecutable(void)
4574 {
4575 return !isKernel() && !isInterface() && declaresExecutable();
4576 }
4577
4578 /*********************************************************************
4579 * We might want to check this recursively for all dependencies,
4580 * since a subtree of dependencies could get loaded before we hit
4581 * a dependency that isn't safe-boot-loadable.
4582 *
4583 * xxx - Might want to return false if OSBundleEnableKextLogging or
4584 * OSBundleDebugLevel
4585 * or IOKitDebug is nonzero too (we used to do that, but I don't see
4586 * the point except it's usually development drivers, which might
4587 * cause panics on startup, that have those properties). Heh; could
4588 * use a "kx" boot-arg!
4589 *********************************************************************/
4590 bool
4591 OSKext::isLoadableInSafeBoot(void)
4592 {
4593 bool result = false;
4594 OSString * required = NULL; // do not release
4595
4596 if (isKernel()) {
4597 result = true;
4598 goto finish;
4599 }
4600
4601 if (isDriverKit()) {
4602 result = true;
4603 goto finish;
4604 }
4605
4606 required = OSDynamicCast(OSString,
4607 getPropertyForHostArch(kOSBundleRequiredKey));
4608 if (!required) {
4609 goto finish;
4610 }
4611 if (required->isEqualTo(kOSBundleRequiredRoot) ||
4612 required->isEqualTo(kOSBundleRequiredLocalRoot) ||
4613 required->isEqualTo(kOSBundleRequiredNetworkRoot) ||
4614 required->isEqualTo(kOSBundleRequiredSafeBoot) ||
4615 required->isEqualTo(kOSBundleRequiredConsole)) {
4616 result = true;
4617 }
4618
4619 finish:
4620 return result;
4621 }
4622
4623 /*********************************************************************
4624 *********************************************************************/
4625 bool
4626 OSKext::isPrelinked(void)
4627 {
4628 return flags.prelinked ? true : false;
4629 }
4630
4631 /*********************************************************************
4632 *********************************************************************/
4633 bool
4634 OSKext::isLoaded(void)
4635 {
4636 return flags.loaded ? true : false;
4637 }
4638
4639 /*********************************************************************
4640 *********************************************************************/
4641 bool
4642 OSKext::isStarted(void)
4643 {
4644 return flags.started ? true : false;
4645 }
4646
4647 /*********************************************************************
4648 *********************************************************************/
4649 bool
4650 OSKext::isCPPInitialized(void)
4651 {
4652 return flags.CPPInitialized;
4653 }
4654
4655 /*********************************************************************
4656 *********************************************************************/
4657 void
4658 OSKext::setCPPInitialized(bool initialized)
4659 {
4660 flags.CPPInitialized = initialized;
4661 }
4662
4663 /*********************************************************************
4664 *********************************************************************/
4665 uint32_t
4666 OSKext::getLoadTag(void)
4667 {
4668 return loadTag;
4669 }
4670
4671 /*********************************************************************
4672 *********************************************************************/
4673 void
4674 OSKext::getSizeInfo(uint32_t *loadSize, uint32_t *wiredSize)
4675 {
4676 if (linkedExecutable) {
4677 *loadSize = linkedExecutable->getLength();
4678
4679 /* If we have a kmod_info struct, calculated the wired size
4680 * from that. Otherwise it's the full load size.
4681 */
4682 if (kmod_info) {
4683 *wiredSize = *loadSize - (uint32_t)kmod_info->hdr_size;
4684 } else {
4685 *wiredSize = *loadSize;
4686 }
4687 } else {
4688 *wiredSize = 0;
4689 *loadSize = 0;
4690 }
4691 }
4692
4693 /*********************************************************************
4694 *********************************************************************/
4695 OSSharedPtr<OSData>
4696 OSKext::copyUUID(void)
4697 {
4698 OSSharedPtr<OSData> result;
4699 OSData * theExecutable = NULL; // do not release
4700 const kernel_mach_header_t * header;
4701
4702 /* An interface kext doesn't have a linked executable with an LC_UUID,
4703 * we create one when it's linked.
4704 */
4705 if (interfaceUUID) {
4706 result = interfaceUUID;
4707 goto finish;
4708 }
4709
4710 if (flags.builtin || isInterface()) {
4711 return sKernelKext->copyUUID();
4712 }
4713
4714 if (isDriverKit() && infoDict) {
4715 return driverKitUUID;
4716 }
4717
4718 /* For real kexts, try to get the UUID from the linked executable,
4719 * or if is hasn't been linked yet, the unrelocated executable.
4720 */
4721 theExecutable = linkedExecutable.get();
4722 if (!theExecutable) {
4723 theExecutable = getExecutable();
4724 }
4725
4726 if (!theExecutable) {
4727 goto finish;
4728 }
4729
4730 header = (const kernel_mach_header_t *)theExecutable->getBytesNoCopy();
4731 result = copyMachoUUID(header);
4732
4733 finish:
4734 return result;
4735 }
4736
4737 /*********************************************************************
4738 *********************************************************************/
4739 OSSharedPtr<OSData>
4740 OSKext::copyTextUUID(void)
4741 {
4742 if (flags.builtin) {
4743 return copyMachoUUID((const kernel_mach_header_t *)kmod_info->address);
4744 }
4745 return copyUUID();
4746 }
4747
4748 /*********************************************************************
4749 *********************************************************************/
4750 OSSharedPtr<OSData>
4751 OSKext::copyMachoUUID(const kernel_mach_header_t * header)
4752 {
4753 OSSharedPtr<OSData> result;
4754 const struct load_command * load_cmd = NULL;
4755 const struct uuid_command * uuid_cmd = NULL;
4756 uint32_t i;
4757
4758 load_cmd = (const struct load_command *)&header[1];
4759
4760 if (header->magic != MH_MAGIC_KERNEL) {
4761 OSKextLog(NULL,
4762 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4763 "%s: bad header %p",
4764 __func__,
4765 header);
4766 goto finish;
4767 }
4768
4769 for (i = 0; i < header->ncmds; i++) {
4770 if (load_cmd->cmd == LC_UUID) {
4771 uuid_cmd = (struct uuid_command *)load_cmd;
4772 result = OSData::withBytes(uuid_cmd->uuid, sizeof(uuid_cmd->uuid));
4773 goto finish;
4774 }
4775 load_cmd = (struct load_command *)((caddr_t)load_cmd + load_cmd->cmdsize);
4776 }
4777
4778 finish:
4779 return result;
4780 }
4781
4782 void
4783 OSKext::setDriverKitUUID(OSData *uuid)
4784 {
4785 if (!OSCompareAndSwapPtr(nullptr, uuid, &driverKitUUID)) {
4786 OSSafeReleaseNULL(uuid);
4787 }
4788 }
4789
4790 /*********************************************************************
4791 *********************************************************************/
4792 #if defined (__arm__)
4793 #include <arm/arch.h>
4794 #endif
4795
4796 #if defined (__x86_64__)
4797 #define ARCHNAME "x86_64"
4798 #elif defined (__arm64__)
4799 #define ARCHNAME "arm64"
4800 #elif defined (__arm__)
4801
4802 #if defined (__ARM_ARCH_7S__)
4803 #define ARCHNAME "armv7s"
4804 #elif defined (__ARM_ARCH_7F__)
4805 #define ARCHNAME "armv7f"
4806 #elif defined (__ARM_ARCH_7K__)
4807 #define ARCHNAME "armv7k"
4808 #elif defined (_ARM_ARCH_7) /* umbrella for all remaining */
4809 #define ARCHNAME "armv7"
4810 #elif defined (_ARM_ARCH_6) /* umbrella for all armv6 */
4811 #define ARCHNAME "armv6"
4812 #endif
4813
4814 #elif defined (__arm64__)
4815 #define ARCHNAME "arm64"
4816 #else
4817 #error architecture not supported
4818 #endif
4819
4820 #define ARCH_SEPARATOR_CHAR '_'
4821
4822 static char *
4823 makeHostArchKey(const char * key, size_t * keySizeOut)
4824 {
4825 char * result = NULL;
4826 size_t keyLength = strlen(key);
4827 size_t keySize;
4828
4829 /* Add 1 for the ARCH_SEPARATOR_CHAR, and 1 for the '\0'.
4830 */
4831 keySize = 1 + 1 + keyLength + strlen(ARCHNAME);
4832 result = (char *)kheap_alloc_tag(KHEAP_TEMP, keySize,
4833 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
4834
4835 if (!result) {
4836 goto finish;
4837 }
4838 strlcpy(result, key, keySize);
4839 result[keyLength++] = ARCH_SEPARATOR_CHAR;
4840 result[keyLength] = '\0';
4841 strlcat(result, ARCHNAME, keySize);
4842 *keySizeOut = keySize;
4843
4844 finish:
4845 return result;
4846 }
4847
4848 /*********************************************************************
4849 *********************************************************************/
4850 OSObject *
4851 OSKext::getPropertyForHostArch(const char * key)
4852 {
4853 OSObject * result = NULL;// do not release
4854 size_t hostArchKeySize = 0;
4855 char * hostArchKey = NULL;// must kfree
4856
4857 if (!key || !infoDict) {
4858 goto finish;
4859 }
4860
4861 /* Some properties are not allowed to be arch-variant:
4862 * - Any CFBundle... property.
4863 * - OSBundleIsInterface.
4864 * - OSKernelResource.
4865 */
4866 if (STRING_HAS_PREFIX(key, "OS") ||
4867 STRING_HAS_PREFIX(key, "IO")) {
4868 hostArchKey = makeHostArchKey(key, &hostArchKeySize);
4869 if (!hostArchKey) {
4870 OSKextLog(/* kext (this isn't about a kext) */ NULL,
4871 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
4872 "Allocation failure.");
4873 goto finish;
4874 }
4875 result = infoDict->getObject(hostArchKey);
4876 }
4877
4878 if (!result) {
4879 result = infoDict->getObject(key);
4880 }
4881
4882 finish:
4883 if (hostArchKey) {
4884 kheap_free(KHEAP_TEMP, hostArchKey, hostArchKeySize);
4885 }
4886 return result;
4887 }
4888
4889 #if PRAGMA_MARK
4890 #pragma mark Load/Start/Stop/Unload
4891 #endif
4892
4893 #define isWhiteSpace(c) ((c) == ' ' || (c) == '\t' || (c) == '\r' || (c) == ',' || (c) == '\n')
4894
4895 /*********************************************************************
4896 * sExcludeListByID is a dictionary with keys / values of:
4897 * key = bundleID string of kext we will not allow to load
4898 * value = version string(s) of the kext that is to be denied loading.
4899 * The version strings can be comma delimited. For example if kext
4900 * com.foocompany.fookext has two versions that we want to deny
4901 * loading then the version strings might look like:
4902 * 1.0.0, 1.0.1
4903 * If the current fookext has a version of 1.0.0 OR 1.0.1 we will
4904 * not load the kext.
4905 *
4906 * Value may also be in the form of "LE 2.0.0" (version numbers
4907 * less than or equal to 2.0.0 will not load) or "LT 2.0.0" (version
4908 * number less than 2.0.0 will not load)
4909 *
4910 * NOTE - we cannot use the characters "<=" or "<" because we have code
4911 * that serializes plists and treats '<' as a special character.
4912 *********************************************************************/
4913 bool
4914 OSKext::isInExcludeList(void)
4915 {
4916 OSString * versionString = NULL; // do not release
4917 char * versionCString = NULL; // do not free
4918 size_t i;
4919 boolean_t wantLessThan = false;
4920 boolean_t wantLessThanEqualTo = false;
4921 boolean_t isInExcludeList = true;
4922 char myBuffer[32];
4923
4924 IORecursiveLockLock(sKextLock);
4925
4926 if (!sExcludeListByID) {
4927 isInExcludeList = false;
4928 } else {
4929 /* look up by bundleID in our exclude list and if found get version
4930 * string (or strings) that we will not allow to load
4931 */
4932 versionString = OSDynamicCast(OSString, sExcludeListByID->getObject(bundleID.get()));
4933 if (versionString == NULL || versionString->getLength() > (sizeof(myBuffer) - 1)) {
4934 isInExcludeList = false;
4935 }
4936 }
4937
4938 IORecursiveLockUnlock(sKextLock);
4939
4940 if (!isInExcludeList) {
4941 return false;
4942 }
4943
4944 /* parse version strings */
4945 versionCString = (char *) versionString->getCStringNoCopy();
4946
4947 /* look for "LT" or "LE" form of version string, must be in first two
4948 * positions.
4949 */
4950 if (*versionCString == 'L' && *(versionCString + 1) == 'T') {
4951 wantLessThan = true;
4952 versionCString += 2;
4953 } else if (*versionCString == 'L' && *(versionCString + 1) == 'E') {
4954 wantLessThanEqualTo = true;
4955 versionCString += 2;
4956 }
4957
4958 for (i = 0; *versionCString != 0x00; versionCString++) {
4959 /* skip whitespace */
4960 if (isWhiteSpace(*versionCString)) {
4961 continue;
4962 }
4963
4964 /* peek ahead for version string separator or null terminator */
4965 if (*(versionCString + 1) == ',' || *(versionCString + 1) == 0x00) {
4966 /* OK, we have a version string */
4967 myBuffer[i++] = *versionCString;
4968 myBuffer[i] = 0x00;
4969
4970 OSKextVersion excludeVers;
4971 excludeVers = OSKextParseVersionString(myBuffer);
4972
4973 if (wantLessThanEqualTo) {
4974 if (version <= excludeVers) {
4975 return true;
4976 }
4977 } else if (wantLessThan) {
4978 if (version < excludeVers) {
4979 return true;
4980 }
4981 } else if (version == excludeVers) {
4982 return true;
4983 }
4984
4985 /* reset for the next (if any) version string */
4986 i = 0;
4987 wantLessThan = false;
4988 wantLessThanEqualTo = false;
4989 } else {
4990 /* save valid version character */
4991 myBuffer[i++] = *versionCString;
4992
4993 /* make sure bogus version string doesn't overrun local buffer */
4994 if (i >= sizeof(myBuffer)) {
4995 break;
4996 }
4997 }
4998 }
4999
5000 return false;
5001 }
5002
5003 /*********************************************************************
5004 * sNonLoadableKextsByID is a dictionary with keys / values of:
5005 * key = bundleID string of kext we will not allow to load
5006 * value = boolean (true == loadable, false == not loadable)
5007 *
5008 * Only kexts which are in the AuxKC will be marked as "not loadble,"
5009 * i.e., the value for the kext's bundleID will be false. All kexts in
5010 * the primary and system KCs will always be marked as "loadable."
5011 *
5012 * This list ultimately comes from kexts which have been uninstalled
5013 * in user space by deleting the kext from disk, but which have not
5014 * yet been removed from the AuxKC. Because the user could choose to
5015 * re-install the exact same version of the kext, we need to keep
5016 * a dictionary of boolean values so that user space only needs to
5017 * keep a simple list of "uninstalled" or "missing" bundles. When
5018 * a bundle is re-installed, the iokit daemon can use the
5019 * AucKCBundleAvailable predicate to set the individual kext's
5020 * availability to true.
5021 *********************************************************************/
5022 bool
5023 OSKext::isLoadable(void)
5024 {
5025 bool isLoadable = true;
5026
5027 if (kc_type != KCKindAuxiliary) {
5028 /* this filtering only applies to kexts in the auxkc */
5029 return true;
5030 }
5031
5032 IORecursiveLockLock(sKextLock);
5033
5034 if (sNonLoadableKextsByID) {
5035 /* look up by bundleID in our exclude list and if found get version
5036 * string (or strings) that we will not allow to load
5037 */
5038 OSBoolean *loadableVal;
5039 loadableVal = OSDynamicCast(OSBoolean, sNonLoadableKextsByID->getObject(bundleID.get()));
5040 if (loadableVal && !loadableVal->getValue()) {
5041 isLoadable = false;
5042 }
5043 }
5044 IORecursiveLockUnlock(sKextLock);
5045
5046 return isLoadable;
5047 }
5048
5049 /*********************************************************************
5050 *********************************************************************/
5051 /* static */
5052 OSReturn
5053 OSKext::loadKextWithIdentifier(
5054 const char * kextIdentifierCString,
5055 Boolean allowDeferFlag,
5056 Boolean delayAutounloadFlag,
5057 OSKextExcludeLevel startOpt,
5058 OSKextExcludeLevel startMatchingOpt,
5059 OSArray * personalityNames)
5060 {
5061 OSReturn result = kOSReturnError;
5062 OSSharedPtr<OSString> kextIdentifier;
5063
5064 kextIdentifier = OSString::withCString(kextIdentifierCString);
5065 if (!kextIdentifier) {
5066 result = kOSKextReturnNoMemory;
5067 goto finish;
5068 }
5069 result = OSKext::loadKextWithIdentifier(kextIdentifier.get(),
5070 NULL /* kextRef */,
5071 allowDeferFlag, delayAutounloadFlag,
5072 startOpt, startMatchingOpt, personalityNames);
5073
5074 finish:
5075 return result;
5076 }
5077
5078 OSReturn
5079 OSKext::loadKextWithIdentifier(
5080 OSString * kextIdentifier,
5081 OSSharedPtr<OSObject> &kextRef,
5082 Boolean allowDeferFlag,
5083 Boolean delayAutounloadFlag,
5084 OSKextExcludeLevel startOpt,
5085 OSKextExcludeLevel startMatchingOpt,
5086 OSArray * personalityNames)
5087 {
5088 OSObject * kextRefRaw = NULL;
5089 OSReturn result;
5090
5091 result = loadKextWithIdentifier(kextIdentifier,
5092 &kextRefRaw,
5093 allowDeferFlag,
5094 delayAutounloadFlag,
5095 startOpt,
5096 startMatchingOpt,
5097 personalityNames);
5098 if ((kOSReturnSuccess == result) && kextRefRaw) {
5099 kextRef.reset(kextRefRaw, OSNoRetain);
5100 }
5101 return result;
5102 }
5103
5104 /*********************************************************************
5105 *********************************************************************/
5106 OSReturn
5107 OSKext::loadKextWithIdentifier(
5108 OSString * kextIdentifier,
5109 OSObject ** kextRef,
5110 Boolean allowDeferFlag,
5111 Boolean delayAutounloadFlag,
5112 OSKextExcludeLevel startOpt,
5113 OSKextExcludeLevel startMatchingOpt,
5114 OSArray * personalityNames)
5115 {
5116 OSReturn result = kOSReturnError;
5117 OSReturn pingResult = kOSReturnError;
5118 OSKext * theKext = NULL; // do not release
5119 OSSharedPtr<OSDictionary> loadRequest;
5120 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5121
5122 if (kextRef) {
5123 *kextRef = NULL;
5124 }
5125
5126 IORecursiveLockLock(sKextLock);
5127
5128 if (!kextIdentifier) {
5129 result = kOSKextReturnInvalidArgument;
5130 goto finish;
5131 }
5132
5133 OSKext::recordIdentifierRequest(kextIdentifier);
5134
5135 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
5136 if (!theKext) {
5137 if (!allowDeferFlag) {
5138 OSKextLog(/* kext */ NULL,
5139 kOSKextLogErrorLevel |
5140 kOSKextLogLoadFlag,
5141 "Can't load kext %s - not found.",
5142 kextIdentifier->getCStringNoCopy());
5143 goto finish;
5144 }
5145
5146 if (!sKernelRequestsEnabled) {
5147 OSKextLog(theKext,
5148 kOSKextLogErrorLevel |
5149 kOSKextLogLoadFlag,
5150 "Can't load kext %s - requests to user space are disabled.",
5151 kextIdentifier->getCStringNoCopy());
5152 result = kOSKextReturnDisabled;
5153 goto finish;
5154 }
5155
5156 /* Create a new request unless one is already sitting
5157 * in sKernelRequests for this bundle identifier
5158 */
5159 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5160 if (!sPostedKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5161 result = _OSKextCreateRequest(kKextRequestPredicateRequestLoad,
5162 loadRequest);
5163 if (result != kOSReturnSuccess) {
5164 goto finish;
5165 }
5166 if (!_OSKextSetRequestArgument(loadRequest.get(),
5167 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
5168 result = kOSKextReturnNoMemory;
5169 goto finish;
5170 }
5171 if (!sKernelRequests->setObject(loadRequest.get())) {
5172 result = kOSKextReturnNoMemory;
5173 goto finish;
5174 }
5175
5176 if (!sPostedKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5177 result = kOSKextReturnNoMemory;
5178 goto finish;
5179 }
5180
5181 OSKextLog(theKext,
5182 kOSKextLogDebugLevel |
5183 kOSKextLogLoadFlag,
5184 "Kext %s not found; queued load request to user space.",
5185 kextIdentifier->getCStringNoCopy());
5186 }
5187
5188 pingResult = OSKext::pingIOKitDaemon();
5189 if (pingResult == kOSKextReturnDisabled) {
5190 OSKextLog(/* kext */ NULL,
5191 ((sPrelinkBoot) ? kOSKextLogDebugLevel : kOSKextLogErrorLevel) |
5192 kOSKextLogLoadFlag,
5193 "Kext %s might not load - " kIOKitDaemonName " is currently unavailable.",
5194 kextIdentifier->getCStringNoCopy());
5195 }
5196
5197 result = kOSKextReturnDeferred;
5198 goto finish;
5199 }
5200
5201 result = theKext->load(startOpt, startMatchingOpt, personalityNames);
5202
5203 if (result != kOSReturnSuccess) {
5204 OSKextLog(theKext,
5205 kOSKextLogErrorLevel |
5206 kOSKextLogLoadFlag,
5207 "Failed to load kext %s (error 0x%x).",
5208 kextIdentifier->getCStringNoCopy(), (int)result);
5209
5210 if (theKext->kc_type == KCKindUnknown) {
5211 OSKext::removeKext(theKext,
5212 /* terminateService/removePersonalities */ true);
5213 }
5214 goto finish;
5215 }
5216
5217 if (delayAutounloadFlag) {
5218 OSKextLog(theKext,
5219 kOSKextLogProgressLevel |
5220 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5221 "Setting delayed autounload for %s.",
5222 kextIdentifier->getCStringNoCopy());
5223 theKext->flags.delayAutounload = 1;
5224 }
5225
5226 finish:
5227 if ((kOSReturnSuccess == result) && kextRef) {
5228 *kextRef = theKext;
5229 theKext->matchingRefCount++;
5230 theKext->retain();
5231 }
5232
5233 IORecursiveLockUnlock(sKextLock);
5234
5235 return result;
5236 }
5237
5238 /*********************************************************************
5239 *********************************************************************/
5240 /* static */
5241 OSReturn
5242 OSKext::loadKextFromKC(OSKext *theKext, OSDictionary *requestDict)
5243 {
5244 OSReturn result = kOSReturnError;
5245
5246 OSBoolean *delayAutounloadBool = NULL; // do not release
5247 OSNumber *startKextExcludeNum = NULL; // do not release
5248 OSNumber *startMatchingExcludeNum = NULL; // do not release
5249 OSArray *personalityNames = NULL; // do not release
5250
5251 /*
5252 * Default values for these options:
5253 * regular autounload behavior
5254 * start the kext
5255 * send all personalities to the catalog
5256 */
5257 Boolean delayAutounload = false;
5258 OSKextExcludeLevel startKextExcludeLevel = kOSKextExcludeNone;
5259 OSKextExcludeLevel startMatchingExcludeLevel = kOSKextExcludeNone;
5260
5261 IORecursiveLockLock(sKextLock);
5262
5263 OSKextLog(/* kext */ NULL,
5264 kOSKextLogDebugLevel |
5265 kOSKextLogIPCFlag,
5266 "Received kext KC load request from user space.");
5267
5268 /* Regardless of processing, the fact that we have gotten here means some
5269 * user-space program is up and talking to us, so we'll switch our kext
5270 * registration to reflect that.
5271 */
5272 if (!sUserLoadsActive) {
5273 OSKextLog(/* kext */ NULL,
5274 kOSKextLogProgressLevel |
5275 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5276 "Switching to late startup (user-space) kext loading policy.");
5277 sUserLoadsActive = true;
5278 }
5279
5280 delayAutounloadBool = OSDynamicCast(OSBoolean,
5281 _OSKextGetRequestArgument(requestDict,
5282 kKextRequestArgumentDelayAutounloadKey));
5283 startKextExcludeNum = OSDynamicCast(OSNumber,
5284 _OSKextGetRequestArgument(requestDict,
5285 kKextRequestArgumentStartExcludeKey));
5286 startMatchingExcludeNum = OSDynamicCast(OSNumber,
5287 _OSKextGetRequestArgument(requestDict,
5288 kKextRequestArgumentStartMatchingExcludeKey));
5289 personalityNames = OSDynamicCast(OSArray,
5290 _OSKextGetRequestArgument(requestDict,
5291 kKextRequestArgumentPersonalityNamesKey));
5292
5293 if (delayAutounloadBool) {
5294 delayAutounload = delayAutounloadBool->getValue();
5295 }
5296 if (startKextExcludeNum) {
5297 startKextExcludeLevel = startKextExcludeNum->unsigned8BitValue();
5298 }
5299 if (startMatchingExcludeNum) {
5300 startMatchingExcludeLevel = startMatchingExcludeNum->unsigned8BitValue();
5301 }
5302
5303 OSKextLog(/* kext */ NULL,
5304 kOSKextLogProgressLevel |
5305 kOSKextLogIPCFlag,
5306 "Received request from user space to load KC kext %s.",
5307 theKext->getIdentifierCString());
5308
5309 /* this could be in the Auxiliary KC, so record the load request */
5310 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, theKext->getIdentifier()));
5311
5312 /*
5313 * Load the kext
5314 */
5315 result = theKext->load(startKextExcludeLevel,
5316 startMatchingExcludeLevel, personalityNames);
5317
5318 if (result != kOSReturnSuccess) {
5319 OSKextLog(theKext,
5320 kOSKextLogErrorLevel |
5321 kOSKextLogLoadFlag,
5322 "Failed to load kext %s (error 0x%x).",
5323 theKext->getIdentifierCString(), (int)result);
5324
5325 OSKext::removeKext(theKext,
5326 /* terminateService/removePersonalities */ true);
5327 goto finish;
5328 } else {
5329 OSKextLog(theKext,
5330 kOSKextLogProgressLevel |
5331 kOSKextLogLoadFlag,
5332 "Kext %s Loaded successfully from %s KC",
5333 theKext->getIdentifierCString(), theKext->getKCTypeString());
5334 }
5335
5336 if (delayAutounload) {
5337 OSKextLog(theKext,
5338 kOSKextLogProgressLevel |
5339 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5340 "Setting delayed autounload for %s.",
5341 theKext->getIdentifierCString());
5342 theKext->flags.delayAutounload = 1;
5343 }
5344
5345 finish:
5346 IORecursiveLockUnlock(sKextLock);
5347
5348 return result;
5349 }
5350
5351 /*********************************************************************
5352 *********************************************************************/
5353 /* static */
5354 OSReturn
5355 OSKext::loadCodelessKext(OSString *kextIdentifier, OSDictionary *requestDict)
5356 {
5357 OSReturn result = kOSReturnError;
5358 OSDictionary *anInfoDict = NULL; // do not release
5359
5360 anInfoDict = OSDynamicCast(OSDictionary,
5361 _OSKextGetRequestArgument(requestDict,
5362 kKextRequestArgumentCodelessInfoKey));
5363 if (anInfoDict == NULL) {
5364 OSKextLog(/* kext */ NULL,
5365 kOSKextLogErrorLevel |
5366 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5367 "Missing 'Codeless Kext Info' dictionary in codeless kext load request of %s.",
5368 kextIdentifier->getCStringNoCopy());
5369 return kOSKextReturnInvalidArgument;
5370 }
5371
5372 IORecursiveLockLock(sKextLock);
5373
5374 OSKextLog(/* kext */ NULL,
5375 kOSKextLogProgressLevel |
5376 kOSKextLogIPCFlag,
5377 "Received request from user space to load codeless kext %s.",
5378 kextIdentifier->getCStringNoCopy());
5379
5380 {
5381 // instantiate a new kext, and don't hold a reference
5382 // (the kext subsystem will hold one implicitly)
5383 OSSharedPtr<OSKext> newKext = OSKext::withCodelessInfo(anInfoDict);
5384 if (!newKext) {
5385 OSKextLog(/* kext */ NULL,
5386 kOSKextLogErrorLevel |
5387 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5388 "Could not instantiate codeless kext.");
5389 result = kOSKextReturnNotLoadable;
5390 goto finish;
5391 }
5392 if (!kextIdentifier->isEqualTo(newKext->getIdentifierCString())) {
5393 OSKextLog(/* kext */ NULL,
5394 kOSKextLogErrorLevel |
5395 kOSKextLogGeneralFlag | kOSKextLogLoadFlag,
5396 "Codeless kext identifiers don't match '%s' != '%s'",
5397 kextIdentifier->getCStringNoCopy(), newKext->getIdentifierCString());
5398
5399 OSKext::removeKext(newKext.get(), false);
5400 result = kOSKextReturnInvalidArgument;
5401 goto finish;
5402 }
5403
5404 /* Record the request for the codeless kext */
5405 OSKext::recordIdentifierRequest(OSDynamicCast(OSString, newKext->getIdentifier()));
5406
5407 result = kOSReturnSuccess;
5408 /* Send the kext's personalities to the IOCatalog. This is an explicit load. */
5409 result = newKext->sendPersonalitiesToCatalog(true, NULL);
5410 }
5411
5412 finish:
5413 IORecursiveLockUnlock(sKextLock);
5414
5415 return result;
5416 }
5417
5418 /*********************************************************************
5419 *********************************************************************/
5420 /* static */
5421 void
5422 OSKext::dropMatchingReferences(
5423 OSSet * kexts)
5424 {
5425 IORecursiveLockLock(sKextLock);
5426 kexts->iterateObjects(^bool (OSObject * obj) {
5427 OSKext * thisKext = OSDynamicCast(OSKext, obj);
5428 if (!thisKext) {
5429 return false;
5430 }
5431 thisKext->matchingRefCount--;
5432 return false;
5433 });
5434 IORecursiveLockUnlock(sKextLock);
5435 }
5436
5437 /*********************************************************************
5438 *********************************************************************/
5439 /* static */
5440 void
5441 OSKext::recordIdentifierRequest(
5442 OSString * kextIdentifier)
5443 {
5444 OSSharedPtr<const OSSymbol> kextIdentifierSymbol;
5445 bool fail = false;
5446
5447 if (!sAllKextLoadIdentifiers || !kextIdentifier) {
5448 goto finish;
5449 }
5450
5451 kextIdentifierSymbol = OSSymbol::withString(kextIdentifier);
5452 if (!kextIdentifierSymbol) {
5453 // xxx - this is really a basic alloc failure
5454 fail = true;
5455 goto finish;
5456 }
5457
5458 IORecursiveLockLock(sKextLock);
5459 if (!sAllKextLoadIdentifiers->containsObject(kextIdentifierSymbol.get())) {
5460 if (!sAllKextLoadIdentifiers->setObject(kextIdentifierSymbol.get())) {
5461 fail = true;
5462 } else {
5463 // xxx - need to find a way to associate this whole func w/the kext
5464 OSKextLog(/* kext */ NULL,
5465 // xxx - check level
5466 kOSKextLogStepLevel |
5467 kOSKextLogArchiveFlag,
5468 "Recorded kext %s as a candidate for inclusion in prelinked kernel.",
5469 kextIdentifier->getCStringNoCopy());
5470 }
5471 }
5472 IORecursiveLockUnlock(sKextLock);
5473
5474 finish:
5475
5476 if (fail) {
5477 OSKextLog(/* kext */ NULL,
5478 kOSKextLogErrorLevel |
5479 kOSKextLogArchiveFlag,
5480 "Failed to record kext %s as a candidate for inclusion in prelinked kernel.",
5481 kextIdentifier->getCStringNoCopy());
5482 }
5483 return;
5484 }
5485
5486 /*********************************************************************
5487 *********************************************************************/
5488 OSReturn
5489 OSKext::load(
5490 OSKextExcludeLevel startOpt,
5491 OSKextExcludeLevel startMatchingOpt,
5492 OSArray * personalityNames)
5493 {
5494 OSReturn result = kOSReturnError;
5495 OSKextExcludeLevel dependenciesStartOpt = startOpt;
5496 OSKextExcludeLevel dependenciesStartMatchingOpt = startMatchingOpt;
5497 unsigned int i, count;
5498 Boolean alreadyLoaded = false;
5499 OSKext * lastLoadedKext = NULL; // do not release
5500
5501 if (isInExcludeList()) {
5502 OSKextLog(this,
5503 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5504 kOSKextLogLoadFlag,
5505 "Kext %s is in exclude list, not loadable",
5506 getIdentifierCString());
5507
5508 result = kOSKextReturnNotLoadable;
5509 goto finish;
5510 }
5511 if (!isLoadable()) {
5512 OSKextLog(this,
5513 kOSKextLogErrorLevel | kOSKextLogGeneralFlag |
5514 kOSKextLogLoadFlag,
5515 "Kext %s is not loadable",
5516 getIdentifierCString());
5517
5518 result = kOSKextReturnNotLoadable;
5519 goto finish;
5520 }
5521
5522 if (isLoaded()) {
5523 alreadyLoaded = true;
5524 result = kOSReturnSuccess;
5525
5526 OSKextLog(this,
5527 kOSKextLogDebugLevel |
5528 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
5529 "Kext %s is already loaded.",
5530 getIdentifierCString());
5531 goto loaded;
5532 }
5533
5534 #if CONFIG_MACF && XNU_TARGET_OS_OSX
5535 #if CONFIG_KXLD
5536 if (current_task() != kernel_task) {
5537 #else
5538 /*
5539 * On non-kxld systems, only check the mac-hook for kexts in the
5540 * Pageable and Aux KCs. This means on Apple silicon devices that
5541 * the mac hook will only be useful to block 3rd party kexts.
5542 *
5543 * Note that this should _not_ be called on kexts loaded from the
5544 * kernel bootstrap thread as the kernel proc's cred struct is not
5545 * yet initialized! This won't happen on macOS because all the kexts
5546 * in the BootKC are self-contained and their kc_type = KCKindPrimary.
5547 */
5548 if (kc_type != KCKindPrimary && kc_type != KCKindUnknown) {
5549 #endif /* CONFIG_KXLD */
5550 int macCheckResult = 0;
5551 kauth_cred_t cred = NULL;
5552
5553 cred = kauth_cred_get_with_ref();
5554 macCheckResult = mac_kext_check_load(cred, getIdentifierCString());
5555 kauth_cred_unref(&cred);
5556
5557 if (macCheckResult != 0) {
5558 result = kOSReturnError;
5559 OSKextLog(this,
5560 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5561 "Failed to load kext %s (MAC policy error 0x%x).",
5562 getIdentifierCString(), macCheckResult);
5563 goto finish;
5564 }
5565 }
5566 #endif
5567
5568 if (!sLoadEnabled) {
5569 OSKextLog(this,
5570 kOSKextLogErrorLevel |
5571 kOSKextLogLoadFlag,
5572 "Kext loading is disabled (attempt to load kext %s).",
5573 getIdentifierCString());
5574 result = kOSKextReturnDisabled;
5575 goto finish;
5576 }
5577
5578 /* If we've pushed the next available load tag to the invalid value,
5579 * we can't load any more kexts.
5580 */
5581 if (sNextLoadTag == kOSKextInvalidLoadTag) {
5582 OSKextLog(this,
5583 kOSKextLogErrorLevel |
5584 kOSKextLogLoadFlag,
5585 "Can't load kext %s - no more load tags to assign.",
5586 getIdentifierCString());
5587 result = kOSKextReturnNoResources;
5588 goto finish;
5589 }
5590
5591 /* This is a bit of a hack, because we shouldn't be handling
5592 * personalities within the load function.
5593 */
5594 if (!declaresExecutable()) {
5595 /* There is a special case where a non-executable kext can be loaded: the
5596 * AppleKextExcludeList. Detect that special kext by bundle identifier and
5597 * load its metadata into the global data structures, if appropriate
5598 */
5599 if (strcmp(getIdentifierCString(), kIOExcludeListBundleID) == 0) {
5600 boolean_t updated = updateExcludeList(infoDict.get());
5601 if (updated) {
5602 OSKextLog(this,
5603 kOSKextLogDebugLevel | kOSKextLogLoadFlag,
5604 "KextExcludeList was updated to version: %lld", sExcludeListVersion);
5605 }
5606 }
5607
5608 if (isDriverKit()) {
5609 if (loadTag == 0) {
5610 sLoadedDriverKitKexts->setObject(this);
5611 loadTag = sNextLoadTag++;
5612 }
5613 }
5614 result = kOSReturnSuccess;
5615 goto loaded;
5616 }
5617
5618 /* Are we in safe boot?
5619 */
5620 if (sSafeBoot && !isLoadableInSafeBoot()) {
5621 OSKextLog(this,
5622 kOSKextLogErrorLevel |
5623 kOSKextLogLoadFlag,
5624 "Can't load kext %s - not loadable during safe boot.",
5625 getIdentifierCString());
5626 result = kOSKextReturnBootLevel;
5627 goto finish;
5628 }
5629
5630 OSKextLog(this,
5631 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
5632 "Loading kext %s.",
5633 getIdentifierCString());
5634
5635 #if !VM_MAPPED_KEXTS
5636 if (isPrelinked() == false) {
5637 OSKextLog(this,
5638 kOSKextLogErrorLevel |
5639 kOSKextLogLoadFlag,
5640 "Can't load kext %s - not in a kext collection.",
5641 getIdentifierCString());
5642 result = kOSKextReturnDisabled;
5643 goto finish;
5644 }
5645 #endif /* defined(__x86_64__) */
5646
5647 #if CONFIG_KXLD
5648 if (!sKxldContext) {
5649 kern_return_t kxldResult;
5650 kxldResult = kxld_create_context(&sKxldContext, &kern_allocate,
5651 &kxld_log_callback, /* Flags */ (KXLDFlags) 0,
5652 /* cputype */ 0, /* cpusubtype */ 0, /* page size */ 0);
5653 if (kxldResult) {
5654 OSKextLog(this,
5655 kOSKextLogErrorLevel |
5656 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
5657 "Can't load kext %s - failed to create link context.",
5658 getIdentifierCString());
5659 result = kOSKextReturnNoMemory;
5660 goto finish;
5661 }
5662 }
5663 #endif // CONFIG_KXLD
5664
5665 /* We only need to resolve dependencies once for the whole graph, but
5666 * resolveDependencies will just return if there's no work to do, so it's
5667 * safe to call it more than once.
5668 */
5669 if (!resolveDependencies()) {
5670 // xxx - check resolveDependencies() for log msg
5671 OSKextLog(this,
5672 kOSKextLogErrorLevel |
5673 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5674 "Can't load kext %s - failed to resolve library dependencies.",
5675 getIdentifierCString());
5676 result = kOSKextReturnDependencies;
5677 goto finish;
5678 }
5679
5680 /* If we are excluding just the kext being loaded now (and not its
5681 * dependencies), drop the exclusion level to none so dependencies
5682 * start and/or add their personalities.
5683 */
5684 if (dependenciesStartOpt == kOSKextExcludeKext) {
5685 dependenciesStartOpt = kOSKextExcludeNone;
5686 }
5687
5688 if (dependenciesStartMatchingOpt == kOSKextExcludeKext) {
5689 dependenciesStartMatchingOpt = kOSKextExcludeNone;
5690 }
5691
5692 /* Load the dependencies, recursively.
5693 */
5694 count = getNumDependencies();
5695 for (i = 0; i < count; i++) {
5696 OSKext * dependency = OSDynamicCast(OSKext,
5697 dependencies->getObject(i));
5698 if (dependency == NULL) {
5699 OSKextLog(this,
5700 kOSKextLogErrorLevel |
5701 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5702 "Internal error loading kext %s; dependency disappeared.",
5703 getIdentifierCString());
5704 result = kOSKextReturnInternalError;
5705 goto finish;
5706 }
5707
5708 /* Dependencies must be started accorting to the opt,
5709 * but not given the personality names of the main kext.
5710 */
5711 result = dependency->load(dependenciesStartOpt,
5712 dependenciesStartMatchingOpt,
5713 /* personalityNames */ NULL);
5714 if (result != KERN_SUCCESS) {
5715 OSKextLog(this,
5716 kOSKextLogErrorLevel |
5717 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
5718 "Dependency %s of kext %s failed to load.",
5719 dependency->getIdentifierCString(),
5720 getIdentifierCString());
5721
5722 OSKext::removeKext(dependency,
5723 /* terminateService/removePersonalities */ true);
5724 result = kOSKextReturnDependencyLoadError;
5725
5726 goto finish;
5727 }
5728 }
5729
5730 result = loadExecutable();
5731 if (result != KERN_SUCCESS) {
5732 goto finish;
5733 }
5734
5735 pendingPgoHead.next = &pendingPgoHead;
5736 pendingPgoHead.prev = &pendingPgoHead;
5737
5738 // The kernel PRNG is not initialized when the first kext is
5739 // loaded, so use early random
5740 uuid_generate_early_random(instance_uuid);
5741 account = IONew(OSKextAccount, 1);
5742 if (!account) {
5743 result = KERN_MEMORY_ERROR;
5744 goto finish;
5745 }
5746 bzero(account, sizeof(*account));
5747 account->loadTag = kmod_info->id;
5748 account->site.refcount = 0;
5749 account->site.flags = VM_TAG_KMOD;
5750 account->kext = this;
5751 if (gIOSurfaceIdentifier == bundleID) {
5752 vm_tag_alloc(&account->site);
5753 gIOSurfaceTag = account->site.tag;
5754 }
5755
5756 flags.loaded = true;
5757
5758 /* Add the kext to the list of loaded kexts and update the kmod_info
5759 * struct to point to that of the last loaded kext (which is the way
5760 * it's always been done, though I'd rather do them in order now).
5761 */
5762 lastLoadedKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
5763 sLoadedKexts->setObject(this);
5764
5765 /* Keep the kernel itself out of the kmod list.
5766 */
5767 if (lastLoadedKext->isKernel()) {
5768 lastLoadedKext = NULL;
5769 }
5770
5771 if (lastLoadedKext) {
5772 kmod_info->next = lastLoadedKext->kmod_info;
5773 }
5774
5775 notifyKextLoadObservers(this, kmod_info);
5776
5777 /* Make the global kmod list point at the just-loaded kext. Note that the
5778 * __kernel__ kext isn't in this list, as it wasn't before SnowLeopard,
5779 * although we do report it in kextstat these days by using the newer
5780 * OSArray of loaded kexts, which does contain it.
5781 *
5782 * (The OSKext object representing the kernel doesn't even have a kmod_info
5783 * struct, though I suppose we could stick a pointer to it from the
5784 * static struct in OSRuntime.cpp.)
5785 */
5786 kmod = kmod_info;
5787
5788 /* Save the list of loaded kexts in case we panic.
5789 */
5790 OSKext::saveLoadedKextPanicList();
5791
5792 if (isExecutable()) {
5793 OSKext::updateLoadedKextSummaries();
5794 savePanicString(/* isLoading */ true);
5795
5796 #if CONFIG_DTRACE
5797 registerWithDTrace();
5798 #else
5799 jettisonLinkeditSegment();
5800 #endif /* CONFIG_DTRACE */
5801
5802 #if !VM_MAPPED_KEXTS
5803 /* If there is a page (or more) worth of padding after the end
5804 * of the last data section but before the end of the data segment
5805 * then free it in the same manner the LinkeditSegment is freed
5806 */
5807 jettisonDATASegmentPadding();
5808 #endif
5809 }
5810
5811 loaded:
5812 if (isExecutable() && !flags.started) {
5813 if (startOpt == kOSKextExcludeNone) {
5814 result = start();
5815 if (result != kOSReturnSuccess) {
5816 OSKextLog(this,
5817 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
5818 "Kext %s start failed (result 0x%x).",
5819 getIdentifierCString(), result);
5820 result = kOSKextReturnStartStopError;
5821 }
5822 }
5823 }
5824
5825 /* If not excluding matching, send the personalities to the kernel.
5826 * This never affects the result of the load operation.
5827 * This is a bit of a hack, because we shouldn't be handling
5828 * personalities within the load function.
5829 */
5830 if (result == kOSReturnSuccess && startMatchingOpt == kOSKextExcludeNone) {
5831 result = sendPersonalitiesToCatalog(true, personalityNames);
5832 }
5833
5834 finish:
5835
5836 if (result != kOSReturnSuccess) {
5837 OSKextLog(this,
5838 kOSKextLogErrorLevel |
5839 kOSKextLogLoadFlag,
5840 "Kext %s failed to load (0x%x).",
5841 getIdentifierCString(), (int)result);
5842 } else if (!alreadyLoaded) {
5843 OSKextLog(this,
5844 kOSKextLogProgressLevel |
5845 kOSKextLogLoadFlag,
5846 "Kext %s loaded.",
5847 getIdentifierCString());
5848
5849 queueKextNotification(kKextRequestPredicateLoadNotification,
5850 OSDynamicCast(OSString, bundleID.get()));
5851 }
5852 return result;
5853 }
5854
5855 #if CONFIG_KXLD
5856 /*********************************************************************
5857 *
5858 *********************************************************************/
5859 static char *
5860 strdup(const char * string)
5861 {
5862 char * result = NULL;
5863 size_t size;
5864
5865 if (!string) {
5866 goto finish;
5867 }
5868
5869 size = 1 + strlen(string);
5870 result = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, size,
5871 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
5872 if (!result) {
5873 goto finish;
5874 }
5875
5876 memcpy(result, string, size);
5877
5878 finish:
5879 return result;
5880 }
5881 #endif // CONFIG_KXLD
5882
5883 /*********************************************************************
5884 *
5885 *********************************************************************/
5886
5887 kernel_section_t *
5888 OSKext::lookupSection(const char *segname, const char *secname)
5889 {
5890 kernel_section_t * found_section = NULL;
5891 kernel_mach_header_t * mh = NULL;
5892 kernel_segment_command_t * seg = NULL;
5893 kernel_section_t * sec = NULL;
5894
5895 if (!linkedExecutable) {
5896 return NULL;
5897 }
5898
5899 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5900
5901 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5902 if (0 != strncmp(seg->segname, segname, sizeof(seg->segname))) {
5903 continue;
5904 }
5905
5906 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5907 if (0 == strncmp(sec->sectname, secname, sizeof(sec->sectname))) {
5908 found_section = sec;
5909 goto out;
5910 }
5911 }
5912 }
5913
5914 out:
5915 return found_section;
5916 }
5917
5918 /*********************************************************************
5919 *
5920 *********************************************************************/
5921
5922 OSReturn
5923 OSKext::slidePrelinkedExecutable(bool doCoalescedSlides)
5924 {
5925 OSReturn result = kOSKextReturnBadData;
5926 kernel_mach_header_t * mh = NULL;
5927 kernel_segment_command_t * seg = NULL;
5928 kernel_segment_command_t * linkeditSeg = NULL;
5929 kernel_section_t * sec = NULL;
5930 char * linkeditBase = NULL;
5931 bool haveLinkeditBase = false;
5932 char * relocBase = NULL;
5933 bool haveRelocBase = false;
5934 struct dysymtab_command * dysymtab = NULL;
5935 struct linkedit_data_command * segmentSplitInfo = NULL;
5936 struct symtab_command * symtab = NULL;
5937 kernel_nlist_t * sym = NULL;
5938 struct relocation_info * reloc = NULL;
5939 uint32_t i = 0;
5940 int reloc_size;
5941 vm_offset_t new_kextsize;
5942
5943 if (linkedExecutable == NULL || flags.builtin) {
5944 result = kOSReturnSuccess;
5945 goto finish;
5946 }
5947
5948 mh = (kernel_mach_header_t *)linkedExecutable->getBytesNoCopy();
5949 if (kernel_mach_header_is_in_fileset(mh)) {
5950 // kexts in filesets are slid as part of collection sliding
5951 result = kOSReturnSuccess;
5952 goto finish;
5953 }
5954
5955 segmentSplitInfo = (struct linkedit_data_command *) getcommandfromheader(mh, LC_SEGMENT_SPLIT_INFO);
5956
5957 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
5958 if (!seg->vmaddr) {
5959 continue;
5960 }
5961
5962 seg->vmaddr = ml_static_slide(seg->vmaddr);
5963
5964 #if KASLR_KEXT_DEBUG
5965 IOLog("kaslr: segname %s unslid 0x%lx slid 0x%lx \n",
5966 seg->segname,
5967 (unsigned long)ml_static_unslide(seg->vmaddr),
5968 (unsigned long)seg->vmaddr);
5969 #endif
5970
5971 if (!haveRelocBase) {
5972 relocBase = (char *) seg->vmaddr;
5973 haveRelocBase = true;
5974 }
5975 if (!strcmp(seg->segname, "__LINKEDIT")) {
5976 linkeditBase = (char *) seg->vmaddr - seg->fileoff;
5977 haveLinkeditBase = true;
5978 linkeditSeg = seg;
5979 }
5980 for (sec = firstsect(seg); sec != NULL; sec = nextsect(seg, sec)) {
5981 sec->addr = ml_static_slide(sec->addr);
5982
5983 #if KASLR_KEXT_DEBUG
5984 IOLog("kaslr: sectname %s unslid 0x%lx slid 0x%lx \n",
5985 sec->sectname,
5986 (unsigned long)ml_static_unslide(sec->addr),
5987 (unsigned long)sec->addr);
5988 #endif
5989 }
5990 }
5991
5992 dysymtab = (struct dysymtab_command *) getcommandfromheader(mh, LC_DYSYMTAB);
5993
5994 symtab = (struct symtab_command *) getcommandfromheader(mh, LC_SYMTAB);
5995
5996 if (symtab != NULL && doCoalescedSlides == false) {
5997 /* Some pseudo-kexts have symbol tables without segments.
5998 * Ignore them. */
5999 if (symtab->nsyms > 0 && haveLinkeditBase) {
6000 sym = (kernel_nlist_t *) (linkeditBase + symtab->symoff);
6001 for (i = 0; i < symtab->nsyms; i++) {
6002 if (sym[i].n_type & N_STAB) {
6003 continue;
6004 }
6005 sym[i].n_value = ml_static_slide(sym[i].n_value);
6006
6007 #if KASLR_KEXT_DEBUG
6008 #define MAX_SYMS_TO_LOG 5
6009 if (i < MAX_SYMS_TO_LOG) {
6010 IOLog("kaslr: LC_SYMTAB unslid 0x%lx slid 0x%lx \n",
6011 (unsigned long)ml_static_unslide(sym[i].n_value),
6012 (unsigned long)sym[i].n_value);
6013 }
6014 #endif
6015 }
6016 }
6017 }
6018
6019 if (dysymtab != NULL && doCoalescedSlides == false) {
6020 if (dysymtab->nextrel > 0) {
6021 OSKextLog(this,
6022 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6023 kOSKextLogLinkFlag,
6024 "Sliding kext %s: External relocations found.",
6025 getIdentifierCString());
6026 goto finish;
6027 }
6028
6029 if (dysymtab->nlocrel > 0) {
6030 if (!haveLinkeditBase) {
6031 OSKextLog(this,
6032 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6033 kOSKextLogLinkFlag,
6034 "Sliding kext %s: No linkedit segment.",
6035 getIdentifierCString());
6036 goto finish;
6037 }
6038
6039 if (!haveRelocBase) {
6040 OSKextLog(this,
6041 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6042 kOSKextLogLinkFlag,
6043 #if __x86_64__
6044 "Sliding kext %s: No writable segments.",
6045 #else
6046 "Sliding kext %s: No segments.",
6047 #endif
6048 getIdentifierCString());
6049 goto finish;
6050 }
6051
6052 reloc = (struct relocation_info *) (linkeditBase + dysymtab->locreloff);
6053 reloc_size = dysymtab->nlocrel * sizeof(struct relocation_info);
6054
6055 for (i = 0; i < dysymtab->nlocrel; i++) {
6056 if (reloc[i].r_extern != 0
6057 || reloc[i].r_type != 0
6058 || reloc[i].r_length != (sizeof(void *) == 8 ? 3 : 2)
6059 ) {
6060 OSKextLog(this,
6061 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6062 kOSKextLogLinkFlag,
6063 "Sliding kext %s: Unexpected relocation found.",
6064 getIdentifierCString());
6065 goto finish;
6066 }
6067 if (reloc[i].r_pcrel != 0) {
6068 continue;
6069 }
6070 uintptr_t *relocAddr = (uintptr_t*)(relocBase + reloc[i].r_address);
6071 *relocAddr = ml_static_slide(*relocAddr);
6072
6073 #if KASLR_KEXT_DEBUG
6074 #define MAX_DYSYMS_TO_LOG 5
6075 if (i < MAX_DYSYMS_TO_LOG) {
6076 IOLog("kaslr: LC_DYSYMTAB unslid 0x%lx slid 0x%lx \n",
6077 (unsigned long)ml_static_unslide(*((uintptr_t *)(relocAddr))),
6078 (unsigned long)*((uintptr_t *)(relocBase + reloc[i].r_address)));
6079 }
6080 #endif
6081 }
6082
6083 /* We should free these relocations, not just delete the reference to them.
6084 * <rdar://problem/10535549> Free relocations from PIE kexts.
6085 *
6086 * For now, we do not free LINKEDIT for kexts with split segments.
6087 */
6088 new_kextsize = round_page(kmod_info->size - reloc_size);
6089 if (new_kextsize > UINT_MAX) {
6090 OSKextLog(this,
6091 kOSKextLogErrorLevel | kOSKextLogLoadFlag |
6092 kOSKextLogLinkFlag,
6093 "Kext %s: new kext size is too large.",
6094 getIdentifierCString());
6095 goto finish;
6096 }
6097 if (((kmod_info->size - new_kextsize) > PAGE_SIZE) && (!segmentSplitInfo)) {
6098 vm_offset_t endofkext = kmod_info->address + kmod_info->size;
6099 vm_offset_t new_endofkext = kmod_info->address + new_kextsize;
6100 vm_offset_t endofrelocInfo = (vm_offset_t) (((uint8_t *)reloc) + reloc_size);
6101 size_t bytes_remaining = endofkext - endofrelocInfo;
6102 OSSharedPtr<OSData> new_osdata;
6103
6104 /* fix up symbol offsets if they are after the dsymtab local relocs */
6105 if (symtab) {
6106 if (dysymtab->locreloff < symtab->symoff) {
6107 symtab->symoff -= reloc_size;
6108 }
6109 if (dysymtab->locreloff < symtab->stroff) {
6110 symtab->stroff -= reloc_size;
6111 }
6112 }
6113 if (dysymtab->locreloff < dysymtab->extreloff) {
6114 dysymtab->extreloff -= reloc_size;
6115 }
6116
6117 /* move data behind reloc info down to new offset */
6118 if (endofrelocInfo < endofkext) {
6119 memcpy(reloc, (void *)endofrelocInfo, bytes_remaining);
6120 }
6121
6122 /* Create a new OSData for the smaller kext object and reflect
6123 * new linkedit segment size.
6124 */
6125 linkeditSeg->vmsize = round_page(linkeditSeg->vmsize - reloc_size);
6126 linkeditSeg->filesize = linkeditSeg->vmsize;
6127
6128 new_osdata = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)new_kextsize);
6129 if (new_osdata) {
6130 /* Fix up kmod info and linkedExecutable.
6131 */
6132 kmod_info->size = new_kextsize;
6133 #if VM_MAPPED_KEXTS
6134 new_osdata->setDeallocFunction(osdata_kext_free);
6135 #else
6136 new_osdata->setDeallocFunction(osdata_phys_free);
6137 #endif
6138 linkedExecutable->setDeallocFunction(NULL);
6139 linkedExecutable = os::move(new_osdata);
6140
6141 #if VM_MAPPED_KEXTS
6142 kext_free(new_endofkext, (endofkext - new_endofkext));
6143 #else
6144 ml_static_mfree(new_endofkext, (endofkext - new_endofkext));
6145 #endif
6146 }
6147 }
6148 dysymtab->nlocrel = 0;
6149 dysymtab->locreloff = 0;
6150 }
6151 }
6152
6153 result = kOSReturnSuccess;
6154 finish:
6155 return result;
6156 }
6157
6158 /*********************************************************************
6159 * called only by load()
6160 *********************************************************************/
6161 OSReturn
6162 OSKext::loadExecutable()
6163 {
6164 OSReturn result = kOSReturnError;
6165 OSSharedPtr<OSArray> linkDependencies;
6166 uint32_t num_kmod_refs = 0;
6167 OSData * theExecutable = NULL; // do not release
6168 OSString * versString = NULL; // do not release
6169 const char * versCString = NULL; // do not free
6170 const char * string = NULL; // do not free
6171
6172 #if CONFIG_KXLD
6173 unsigned int i;
6174 uint32_t numDirectDependencies = 0;
6175 kern_return_t kxldResult;
6176 KXLDDependency * kxlddeps = NULL; // must kfree
6177 uint32_t num_kxlddeps = 0;
6178 struct mach_header ** kxldHeaderPtr = NULL; // do not free
6179 struct mach_header * kxld_header = NULL; // xxx - need to free here?
6180 #endif // CONFIG_KXLD
6181
6182 /* We need the version string for a variety of bits below.
6183 */
6184 versString = OSDynamicCast(OSString,
6185 getPropertyForHostArch(kCFBundleVersionKey));
6186 if (!versString) {
6187 goto finish;
6188 }
6189 versCString = versString->getCStringNoCopy();
6190
6191 if (isKernelComponent()) {
6192 if (STRING_HAS_PREFIX(versCString, KERNEL_LIB_PREFIX)) {
6193 if (strncmp(versCString, KERNEL6_VERSION, strlen(KERNEL6_VERSION))) {
6194 OSKextLog(this,
6195 kOSKextLogErrorLevel |
6196 kOSKextLogLoadFlag,
6197 "Kernel component %s has incorrect version %s; "
6198 "expected %s.",
6199 getIdentifierCString(),
6200 versCString, KERNEL6_VERSION);
6201 result = kOSKextReturnInternalError;
6202 goto finish;
6203 } else if (strcmp(versCString, osrelease)) {
6204 OSKextLog(this,
6205 kOSKextLogErrorLevel |
6206 kOSKextLogLoadFlag,
6207 "Kernel component %s has incorrect version %s; "
6208 "expected %s.",
6209 getIdentifierCString(),
6210 versCString, osrelease);
6211 result = kOSKextReturnInternalError;
6212 goto finish;
6213 }
6214 }
6215 }
6216
6217 #if defined(__x86_64__) || defined(__i386__)
6218 if (flags.resetSegmentsFromVnode) {
6219 /* Fixup the chains and slide the mach headers */
6220 kernel_mach_header_t *mh = (kernel_mach_header_t *)kmod_info->address;
6221
6222 if (i386_slide_individual_kext(mh, PE_get_kc_slide(kc_type)) != KERN_SUCCESS) {
6223 result = kOSKextReturnValidation;
6224 goto finish;
6225 }
6226 }
6227 #endif //(__x86_64__) || defined(__i386__)
6228
6229 if (isPrelinked()) {
6230 goto register_kmod;
6231 }
6232
6233 /* <rdar://problem/21444003> all callers must be entitled */
6234 if (FALSE == IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement)) {
6235 OSKextLog(this,
6236 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6237 "Not entitled to link kext '%s'",
6238 getIdentifierCString());
6239 result = kOSKextReturnNotPrivileged;
6240 goto finish;
6241 }
6242
6243 theExecutable = getExecutable();
6244 if (!theExecutable) {
6245 if (declaresExecutable()) {
6246 OSKextLog(this,
6247 kOSKextLogErrorLevel |
6248 kOSKextLogLoadFlag,
6249 "Can't load kext %s - executable is missing.",
6250 getIdentifierCString());
6251 result = kOSKextReturnValidation;
6252 goto finish;
6253 }
6254 goto register_kmod;
6255 }
6256
6257 if (isInterface()) {
6258 OSSharedPtr<OSData> executableCopy = OSData::withData(theExecutable);
6259 if (executableCopy) {
6260 setLinkedExecutable(executableCopy.get());
6261 }
6262 goto register_kmod;
6263 }
6264
6265 #if CONFIG_KXLD
6266 numDirectDependencies = getNumDependencies();
6267
6268 if (flags.hasBleedthrough) {
6269 linkDependencies = dependencies;
6270 } else {
6271 linkDependencies = OSArray::withArray(dependencies.get());
6272 if (!linkDependencies) {
6273 OSKextLog(this,
6274 kOSKextLogErrorLevel |
6275 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6276 "Can't allocate link dependencies to load kext %s.",
6277 getIdentifierCString());
6278 goto finish;
6279 }
6280
6281 for (i = 0; i < numDirectDependencies; ++i) {
6282 OSKext * dependencyKext = OSDynamicCast(OSKext,
6283 dependencies->getObject(i));
6284 dependencyKext->addBleedthroughDependencies(linkDependencies.get());
6285 }
6286 }
6287
6288 num_kxlddeps = linkDependencies->getCount();
6289 if (!num_kxlddeps) {
6290 OSKextLog(this,
6291 kOSKextLogErrorLevel |
6292 kOSKextLogLoadFlag | kOSKextLogDependenciesFlag,
6293 "Can't load kext %s - it has no library dependencies.",
6294 getIdentifierCString());
6295 goto finish;
6296 }
6297
6298 kxlddeps = (KXLDDependency *)kalloc_tag(num_kxlddeps * sizeof(*kxlddeps), VM_KERN_MEMORY_OSKEXT);
6299 if (!kxlddeps) {
6300 OSKextLog(this,
6301 kOSKextLogErrorLevel |
6302 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6303 "Can't allocate link context to load kext %s.",
6304 getIdentifierCString());
6305 goto finish;
6306 }
6307 bzero(kxlddeps, num_kxlddeps * sizeof(*kxlddeps));
6308
6309 for (i = 0; i < num_kxlddeps; ++i) {
6310 OSKext * dependency = OSDynamicCast(OSKext, linkDependencies->getObject(i));
6311
6312 if (dependency->isInterface()) {
6313 OSKext *interfaceTargetKext = NULL; //do not release
6314 OSData * interfaceTarget = NULL; //do not release
6315
6316 if (dependency->isKernelComponent()) {
6317 interfaceTargetKext = sKernelKext;
6318 interfaceTarget = sKernelKext->linkedExecutable.get();
6319 } else {
6320 interfaceTargetKext = OSDynamicCast(OSKext,
6321 dependency->dependencies->getObject(0));
6322
6323 interfaceTarget = interfaceTargetKext->linkedExecutable.get();
6324 }
6325
6326 if (!interfaceTarget) {
6327 // panic?
6328 goto finish;
6329 }
6330
6331 /* The names set here aren't actually logged yet <rdar://problem/7941514>,
6332 * it will be useful to have them in the debugger.
6333 * strdup() failing isn't critical right here so we don't check that.
6334 */
6335 kxlddeps[i].kext = (u_char *) interfaceTarget->getBytesNoCopy();
6336 kxlddeps[i].kext_size = interfaceTarget->getLength();
6337 kxlddeps[i].kext_name = strdup(interfaceTargetKext->getIdentifierCString());
6338
6339 if (dependency->linkedExecutable != NULL) {
6340 kxlddeps[i].interface = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6341 kxlddeps[i].interface_size = dependency->linkedExecutable->getLength();
6342 } else {
6343 kxlddeps[i].interface = (u_char *) NULL;
6344 kxlddeps[i].interface_size = 0;
6345 }
6346 kxlddeps[i].interface_name = strdup(dependency->getIdentifierCString());
6347 } else {
6348 kxlddeps[i].kext = (u_char *) dependency->linkedExecutable->getBytesNoCopy();
6349 kxlddeps[i].kext_size = dependency->linkedExecutable->getLength();
6350 kxlddeps[i].kext_name = strdup(dependency->getIdentifierCString());
6351 }
6352
6353 kxlddeps[i].is_direct_dependency = (i < numDirectDependencies);
6354 }
6355
6356 kxldHeaderPtr = &kxld_header;
6357
6358 #if DEBUG
6359 OSKextLog(this,
6360 kOSKextLogExplicitLevel |
6361 kOSKextLogLoadFlag | kOSKextLogLinkFlag,
6362 "Kext %s - calling kxld_link_file:\n"
6363 " kxld_context: %p\n"
6364 " executable: %p executable_length: %d\n"
6365 " user_data: %p\n"
6366 " kxld_dependencies: %p num_dependencies: %d\n"
6367 " kxld_header_ptr: %p kmod_info_ptr: %p\n",
6368 getIdentifierCString(), sKxldContext,
6369 theExecutable->getBytesNoCopy(), theExecutable->getLength(),
6370 this, kxlddeps, num_kxlddeps,
6371 kxldHeaderPtr, &kmod_info);
6372 #endif
6373
6374 /* After this call, the linkedExecutable instance variable
6375 * should exist.
6376 */
6377 kxldResult = kxld_link_file(sKxldContext,
6378 (u_char *)theExecutable->getBytesNoCopy(),
6379 theExecutable->getLength(),
6380 getIdentifierCString(), this, kxlddeps, num_kxlddeps,
6381 (u_char **)kxldHeaderPtr, (kxld_addr_t *)&kmod_info);
6382
6383 if (kxldResult != KERN_SUCCESS) {
6384 // xxx - add kxldResult here?
6385 OSKextLog(this,
6386 kOSKextLogErrorLevel |
6387 kOSKextLogLoadFlag,
6388 "Can't load kext %s - link failed.",
6389 getIdentifierCString());
6390 result = kOSKextReturnLinkError;
6391 goto finish;
6392 }
6393
6394 /* We've written data & instructions into kernel memory, so flush the data
6395 * cache and invalidate the instruction cache.
6396 * I/D caches are coherent on x86
6397 */
6398 #if !defined(__i386__) && !defined(__x86_64__)
6399 flush_dcache(kmod_info->address, kmod_info->size, false);
6400 invalidate_icache(kmod_info->address, kmod_info->size, false);
6401 #endif
6402
6403 #else // !CONFIG_KXLD
6404 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6405 "Refusing to link non-prelinked kext: %s (no kxld support)", getIdentifierCString());
6406 result = kOSKextReturnLinkError;
6407 goto finish;
6408 #endif // CONFIG_KXLD
6409
6410 register_kmod:
6411
6412 if (isInterface()) {
6413 /* Whip up a fake kmod_info entry for the interface kext.
6414 */
6415 kmod_info = (kmod_info_t *)kalloc_tag(sizeof(kmod_info_t), VM_KERN_MEMORY_OSKEXT);
6416 if (!kmod_info) {
6417 result = KERN_MEMORY_ERROR;
6418 goto finish;
6419 }
6420
6421 /* A pseudokext has almost nothing in its kmod_info struct.
6422 */
6423 bzero(kmod_info, sizeof(kmod_info_t));
6424
6425 kmod_info->info_version = KMOD_INFO_VERSION;
6426
6427 /* An interface kext doesn't have a linkedExecutable, so save a
6428 * copy of the UUID out of the original executable via copyUUID()
6429 * while we still have the original executable.
6430 */
6431 interfaceUUID = copyUUID();
6432 }
6433
6434 kmod_info->id = loadTag = sNextLoadTag++;
6435 kmod_info->reference_count = 0; // KMOD_DECL... sets it to -1 (invalid).
6436
6437 /* Stamp the bundle ID and version from the OSKext over anything
6438 * resident inside the kmod_info.
6439 */
6440 string = getIdentifierCString();
6441 strlcpy(kmod_info->name, string, sizeof(kmod_info->name));
6442
6443 string = versCString;
6444 strlcpy(kmod_info->version, string, sizeof(kmod_info->version));
6445
6446 /* Add the dependencies' kmod_info structs as kmod_references.
6447 */
6448 num_kmod_refs = getNumDependencies();
6449 if (num_kmod_refs) {
6450 kmod_info->reference_list = (kmod_reference_t *)kalloc_tag(
6451 num_kmod_refs * sizeof(kmod_reference_t), VM_KERN_MEMORY_OSKEXT);
6452 if (!kmod_info->reference_list) {
6453 result = KERN_MEMORY_ERROR;
6454 goto finish;
6455 }
6456 bzero(kmod_info->reference_list,
6457 num_kmod_refs * sizeof(kmod_reference_t));
6458 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
6459 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
6460 OSKext * refKext = OSDynamicCast(OSKext, dependencies->getObject(refIndex));
6461 ref->info = refKext->kmod_info;
6462 ref->info->reference_count++;
6463
6464 if (refIndex + 1 < num_kmod_refs) {
6465 ref->next = kmod_info->reference_list + refIndex + 1;
6466 }
6467 }
6468 }
6469
6470 if (kmod_info->hdr_size > UINT32_MAX) {
6471 OSKextLog(this,
6472 kOSKextLogErrorLevel |
6473 kOSKextLogLoadFlag,
6474 #if __LP64__
6475 "Kext %s header size is too large (%lu > UINT32_MAX).",
6476 #else
6477 "Kext %s header size is too large (%u > UINT32_MAX).",
6478 #endif
6479 kmod_info->name,
6480 kmod_info->hdr_size);
6481 result = KERN_FAILURE;
6482 goto finish;
6483 }
6484
6485 if (kmod_info->size > UINT32_MAX) {
6486 OSKextLog(this,
6487 kOSKextLogErrorLevel |
6488 kOSKextLogLoadFlag,
6489 #if __LP64__
6490 "Kext %s size is too large (%lu > UINT32_MAX).",
6491 #else
6492 "Kext %s size is too large (%u > UINT32_MAX).",
6493 #endif
6494 kmod_info->name,
6495 kmod_info->size);
6496 result = KERN_FAILURE;
6497 goto finish;
6498 }
6499
6500 if (!isInterface() && linkedExecutable) {
6501 OSKextLog(this,
6502 kOSKextLogProgressLevel |
6503 kOSKextLogLoadFlag,
6504 "Kext %s executable loaded; %u pages at 0x%lx (load tag %u).",
6505 kmod_info->name,
6506 (unsigned)kmod_info->size / PAGE_SIZE,
6507 (unsigned long)ml_static_unslide(kmod_info->address),
6508 (unsigned)kmod_info->id);
6509 }
6510
6511 /* VM protections and wiring for the Aux KC are done at collection loading time */
6512 if (kc_type != KCKindAuxiliary || flags.resetSegmentsFromVnode) {
6513 /* if prelinked and primary KC, VM protections are already set */
6514 result = setVMAttributes(!isPrelinked() || flags.resetSegmentsFromVnode, true);
6515 if (result != KERN_SUCCESS) {
6516 goto finish;
6517 }
6518 }
6519
6520 #if KASAN
6521 if (linkedExecutable) {
6522 kasan_load_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(),
6523 linkedExecutable->getLength(), getIdentifierCString());
6524 }
6525 #else
6526 if (lookupSection(KASAN_GLOBAL_SEGNAME, KASAN_GLOBAL_SECTNAME)) {
6527 OSKextLog(this,
6528 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
6529 "KASAN: cannot load KASAN-ified kext %s on a non-KASAN kernel\n",
6530 getIdentifierCString()
6531 );
6532 result = KERN_FAILURE;
6533 goto finish;
6534 }
6535 #endif
6536
6537 result = kOSReturnSuccess;
6538
6539 finish:
6540
6541 #if CONFIG_KXLD
6542 /* Clear up locally allocated dependency info.
6543 */
6544 for (i = 0; i < num_kxlddeps; ++i) {
6545 size_t size;
6546
6547 if (kxlddeps[i].kext_name) {
6548 size = 1 + strlen(kxlddeps[i].kext_name);
6549 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].kext_name, size);
6550 }
6551 if (kxlddeps[i].interface_name) {
6552 size = 1 + strlen(kxlddeps[i].interface_name);
6553 kheap_free(KHEAP_DATA_BUFFERS, kxlddeps[i].interface_name, size);
6554 }
6555 }
6556 if (kxlddeps) {
6557 kfree(kxlddeps, (num_kxlddeps * sizeof(*kxlddeps)));
6558 }
6559 #endif // CONFIG_KXLD
6560
6561 /* We no longer need the unrelocated executable (which the linker
6562 * has altered anyhow).
6563 */
6564 setExecutable(NULL);
6565
6566 if (result != kOSReturnSuccess) {
6567 OSKextLog(this,
6568 kOSKextLogErrorLevel |
6569 kOSKextLogLoadFlag,
6570 "Failed to load executable for kext %s.",
6571 getIdentifierCString());
6572
6573 if (kmod_info && kmod_info->reference_list) {
6574 kfree(kmod_info->reference_list,
6575 num_kmod_refs * sizeof(kmod_reference_t));
6576 }
6577 if (isInterface()) {
6578 kfree(kmod_info, sizeof(kmod_info_t));
6579 kmod_info = NULL;
6580 }
6581 if (kc_type == KCKindUnknown) {
6582 kmod_info = NULL;
6583 if (linkedExecutable) {
6584 linkedExecutable.reset();
6585 }
6586 }
6587 }
6588
6589 return result;
6590 }
6591
6592 #if VM_MAPPED_KEXTS
6593 /* static */
6594 void
6595 OSKext::jettisonFileSetLinkeditSegment(kernel_mach_header_t *mh)
6596 {
6597 kernel_segment_command_t *linkeditseg = NULL;
6598
6599 linkeditseg = getsegbynamefromheader(mh, SEG_LINKEDIT);
6600 assert(linkeditseg != NULL);
6601
6602 /* BootKC on x86_64 is not vm mapped */
6603 ml_static_mfree(linkeditseg->vmaddr, linkeditseg->vmsize);
6604
6605 OSKextLog(/* kext */ NULL,
6606 kOSKextLogProgressLevel |
6607 kOSKextLogGeneralFlag,
6608 "Jettisoning fileset Linkedit segments from vmaddr %llx with size %llu",
6609 linkeditseg->vmaddr, linkeditseg->vmsize);
6610 }
6611 #endif /* VM_MAPPED_KEXTS */
6612
6613 /*********************************************************************
6614 * The linkedit segment is used by the kext linker for dependency
6615 * resolution, and by dtrace for probe initialization. We can free it
6616 * for non-library kexts, since no kexts depend on non-library kexts
6617 * by definition, once dtrace has been initialized.
6618 *********************************************************************/
6619 void
6620 OSKext::jettisonLinkeditSegment(void)
6621 {
6622 kernel_mach_header_t * machhdr = (kernel_mach_header_t *)kmod_info->address;
6623 kernel_segment_command_t * linkedit = NULL;
6624 vm_offset_t start;
6625 vm_size_t linkeditsize, kextsize;
6626 OSSharedPtr<OSData> data;
6627
6628 if (isInFileset()) {
6629 return;
6630 }
6631
6632 #if NO_KEXTD
6633 /* We can free symbol tables for all embedded kexts because we don't
6634 * support runtime kext linking.
6635 */
6636 if (sKeepSymbols || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6637 #else
6638 if (sKeepSymbols || isLibrary() || !isExecutable() || !linkedExecutable || flags.jettisonLinkeditSeg) {
6639 #endif
6640 goto finish;
6641 }
6642
6643 /* Find the linkedit segment. If it's not the last segment, then freeing
6644 * it will fragment the kext into multiple VM regions, which OSKext is not
6645 * designed to handle, so we'll have to skip it.
6646 */
6647 linkedit = getsegbynamefromheader(machhdr, SEG_LINKEDIT);
6648 if (!linkedit) {
6649 goto finish;
6650 }
6651
6652 if (round_page(kmod_info->address + kmod_info->size) !=
6653 round_page(linkedit->vmaddr + linkedit->vmsize)) {
6654 goto finish;
6655 }
6656
6657 /* Create a new OSData for the smaller kext object.
6658 */
6659 linkeditsize = round_page(linkedit->vmsize);
6660 kextsize = kmod_info->size - linkeditsize;
6661 start = linkedit->vmaddr;
6662
6663 if (kextsize > UINT_MAX) {
6664 goto finish;
6665 }
6666 data = OSData::withBytesNoCopy((void *)kmod_info->address, (unsigned int)kextsize);
6667 if (!data) {
6668 goto finish;
6669 }
6670
6671 /* Fix the kmod info and linkedExecutable.
6672 */
6673 kmod_info->size = kextsize;
6674
6675 #if VM_MAPPED_KEXTS
6676 data->setDeallocFunction(osdata_kext_free);
6677 #else
6678 data->setDeallocFunction(osdata_phys_free);
6679 #endif
6680 linkedExecutable->setDeallocFunction(NULL);
6681 linkedExecutable = os::move(data);
6682 flags.jettisonLinkeditSeg = 1;
6683
6684 /* Free the linkedit segment.
6685 */
6686 #if VM_MAPPED_KEXTS
6687 kext_free(start, linkeditsize);
6688 #else
6689 ml_static_mfree(start, linkeditsize);
6690 #endif
6691
6692 finish:
6693 return;
6694 }
6695
6696 /*********************************************************************
6697 * If there are whole pages that are unused betweem the last section
6698 * of the DATA segment and the end of the DATA segment then we can free
6699 * them
6700 *********************************************************************/
6701 void
6702 OSKext::jettisonDATASegmentPadding(void)
6703 {
6704 kernel_mach_header_t * mh;
6705 kernel_segment_command_t * dataSeg;
6706 kernel_section_t * sec, * lastSec;
6707 vm_offset_t dataSegEnd, lastSecEnd;
6708 vm_size_t padSize;
6709
6710 if (flags.builtin) {
6711 return;
6712 }
6713 mh = (kernel_mach_header_t *)kmod_info->address;
6714
6715 if (isInFileset()) {
6716 return;
6717 }
6718
6719 dataSeg = getsegbynamefromheader(mh, SEG_DATA);
6720 if (dataSeg == NULL) {
6721 return;
6722 }
6723
6724 lastSec = NULL;
6725 sec = firstsect(dataSeg);
6726 while (sec != NULL) {
6727 lastSec = sec;
6728 sec = nextsect(dataSeg, sec);
6729 }
6730
6731 if (lastSec == NULL) {
6732 return;
6733 }
6734
6735 if ((dataSeg->vmaddr != round_page(dataSeg->vmaddr)) ||
6736 (dataSeg->vmsize != round_page(dataSeg->vmsize))) {
6737 return;
6738 }
6739
6740 dataSegEnd = dataSeg->vmaddr + dataSeg->vmsize;
6741 lastSecEnd = round_page(lastSec->addr + lastSec->size);
6742
6743 if (dataSegEnd <= lastSecEnd) {
6744 return;
6745 }
6746
6747 padSize = dataSegEnd - lastSecEnd;
6748
6749 if (padSize >= PAGE_SIZE) {
6750 #if VM_MAPPED_KEXTS
6751 kext_free(lastSecEnd, padSize);
6752 #else
6753 ml_static_mfree(lastSecEnd, padSize);
6754 #endif
6755 }
6756 }
6757
6758 /*********************************************************************
6759 *********************************************************************/
6760 void
6761 OSKext::setLinkedExecutable(OSData * anExecutable)
6762 {
6763 if (linkedExecutable) {
6764 panic("Attempt to set linked executable on kext "
6765 "that already has one (%s).\n",
6766 getIdentifierCString());
6767 }
6768 linkedExecutable.reset(anExecutable, OSRetain);
6769 return;
6770 }
6771
6772 #if CONFIG_DTRACE
6773 /*********************************************************************
6774 * Go through all loaded kexts and tell them to register with dtrace.
6775 * The instance method only registers if necessary.
6776 *********************************************************************/
6777 /* static */
6778 void
6779 OSKext::registerKextsWithDTrace(void)
6780 {
6781 uint32_t count = sLoadedKexts->getCount();
6782 uint32_t i;
6783
6784 IORecursiveLockLock(sKextLock);
6785
6786 for (i = 0; i < count; i++) {
6787 OSKext * thisKext = NULL; // do not release
6788
6789 thisKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
6790 if (!thisKext || !thisKext->isExecutable()) {
6791 continue;
6792 }
6793
6794 thisKext->registerWithDTrace();
6795 }
6796
6797 IORecursiveLockUnlock(sKextLock);
6798
6799 return;
6800 }
6801
6802 extern "C" {
6803 extern int (*dtrace_modload)(struct kmod_info *, uint32_t);
6804 extern int (*dtrace_modunload)(struct kmod_info *);
6805 };
6806
6807 /*********************************************************************
6808 *********************************************************************/
6809 void
6810 OSKext::registerWithDTrace(void)
6811 {
6812 /* Register kext with dtrace. A dtrace_modload failure should not
6813 * prevent a kext from loading, so we ignore the return code.
6814 */
6815 if (!flags.dtraceInitialized && (dtrace_modload != NULL)) {
6816 uint32_t modflag = 0;
6817 OSObject * forceInit = getPropertyForHostArch("OSBundleForceDTraceInit");
6818
6819 #if VM_MAPPED_KEXTS
6820 if (!sKeepSymbols && kc_type == KCKindPrimary) {
6821 if (forceInit == kOSBooleanTrue) {
6822 /* Make sure the kext is not from the Boot KC */
6823 panic("OSBundleForceDTraceInit key specified for the Boot KC kext : %s", getIdentifierCString());
6824 } else {
6825 /* Linkedit segment of the Boot KC is gone, make sure fbt_provide_module don't use kernel symbols */
6826 modflag |= KMOD_DTRACE_NO_KERNEL_SYMS;
6827 }
6828 }
6829 #endif /* VM_MAPPED_KEXTS */
6830 if (forceInit == kOSBooleanTrue) {
6831 modflag |= KMOD_DTRACE_FORCE_INIT;
6832 }
6833 if (flags.builtin) {
6834 modflag |= KMOD_DTRACE_STATIC_KEXT;
6835 }
6836
6837 (void)(*dtrace_modload)(kmod_info, modflag);
6838 flags.dtraceInitialized = true;
6839 jettisonLinkeditSegment();
6840 }
6841 return;
6842 }
6843 /*********************************************************************
6844 *********************************************************************/
6845 void
6846 OSKext::unregisterWithDTrace(void)
6847 {
6848 /* Unregister kext with dtrace. A dtrace_modunload failure should not
6849 * prevent a kext from loading, so we ignore the return code.
6850 */
6851 if (flags.dtraceInitialized && (dtrace_modunload != NULL)) {
6852 (void)(*dtrace_modunload)(kmod_info);
6853 flags.dtraceInitialized = false;
6854 }
6855 return;
6856 }
6857 #endif /* CONFIG_DTRACE */
6858
6859
6860 /*********************************************************************
6861 * called only by loadExecutable()
6862 *********************************************************************/
6863 #if !VM_MAPPED_KEXTS
6864 #if defined(__arm__) || defined(__arm64__)
6865 static inline kern_return_t
6866 OSKext_protect(
6867 kernel_mach_header_t *kext_mh,
6868 vm_map_t map,
6869 vm_map_offset_t start,
6870 vm_map_offset_t end,
6871 vm_prot_t new_prot,
6872 boolean_t set_max,
6873 kc_kind_t kc_type)
6874 {
6875 #pragma unused(kext_mh,map,kc_type)
6876 assert(map == kernel_map); // we can handle KEXTs arising from the PRELINK segment and no others
6877 assert(start <= end);
6878 if (start >= end) {
6879 return KERN_SUCCESS; // Punt segments of length zero (e.g., headers) or less (i.e., blunders)
6880 } else if (set_max) {
6881 return KERN_SUCCESS; // Punt set_max, as there's no mechanism to record that state
6882 } else {
6883 return ml_static_protect(start, end - start, new_prot);
6884 }
6885 }
6886
6887 static inline kern_return_t
6888 OSKext_wire(
6889 kernel_mach_header_t *kext_mh,
6890 vm_map_t map,
6891 vm_map_offset_t start,
6892 vm_map_offset_t end,
6893 vm_prot_t access_type,
6894 boolean_t user_wire,
6895 kc_kind_t kc_type)
6896 {
6897 #pragma unused(kext_mh,map,start,end,access_type,user_wire,kc_type)
6898 return KERN_SUCCESS; // No-op as PRELINK kexts are cemented into physical memory at boot
6899 }
6900 #else
6901 #error Unrecognized architecture
6902 #endif
6903 #else
6904 static inline kern_return_t
6905 OSKext_protect(
6906 kernel_mach_header_t *kext_mh,
6907 vm_map_t map,
6908 vm_map_offset_t start,
6909 vm_map_offset_t end,
6910 vm_prot_t new_prot,
6911 boolean_t set_max,
6912 kc_kind_t kc_type)
6913 {
6914 if (start == end) { // 10538581
6915 return KERN_SUCCESS;
6916 }
6917 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6918 /*
6919 * XXX: This will probably need to be different for AuxKC and
6920 * pageableKC!
6921 */
6922 return ml_static_protect(start, end - start, new_prot);
6923 }
6924 return vm_map_protect(map, start, end, new_prot, set_max);
6925 }
6926
6927 static inline kern_return_t
6928 OSKext_wire(
6929 kernel_mach_header_t *kext_mh,
6930 vm_map_t map,
6931 vm_map_offset_t start,
6932 vm_map_offset_t end,
6933 vm_prot_t access_type,
6934 boolean_t user_wire,
6935 kc_kind_t kc_type)
6936 {
6937 if (kernel_mach_header_is_in_fileset(kext_mh) && kc_type == KCKindPrimary) {
6938 /* TODO: we may need to hook this for the pageableKC */
6939 return KERN_SUCCESS;
6940 }
6941 return vm_map_wire_kernel(map, start, end, access_type, VM_KERN_MEMORY_KEXT, user_wire);
6942 }
6943 #endif
6944
6945 OSReturn
6946 OSKext::setVMAttributes(bool protect, bool wire)
6947 {
6948 vm_map_t kext_map = NULL;
6949 kernel_segment_command_t * seg = NULL;
6950 vm_map_offset_t start_protect = 0;
6951 vm_map_offset_t start_wire = 0;
6952 vm_map_offset_t end_protect = 0;
6953 vm_map_offset_t end_wire = 0;
6954 OSReturn result = kOSReturnError;
6955
6956 if (isInterface() || !declaresExecutable() || flags.builtin) {
6957 result = kOSReturnSuccess;
6958 goto finish;
6959 }
6960
6961 /* Get the kext's vm map */
6962 kext_map = kext_get_vm_map(kmod_info);
6963 if (!kext_map) {
6964 result = KERN_MEMORY_ERROR;
6965 goto finish;
6966 }
6967
6968 #if !VM_MAPPED_KEXTS
6969 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO)) {
6970 /* This is a split kext in a prelinked kernelcache; we'll let the
6971 * platform code take care of protecting it. It is already wired.
6972 */
6973 /* TODO: Should this still allow protections for the first segment
6974 * to go through, in the event that we have a mix of split and
6975 * unsplit kexts?
6976 */
6977 result = KERN_SUCCESS;
6978 goto finish;
6979 }
6980
6981 if (isInFileset() && kc_type != KCKindPageable) {
6982 // kexts in filesets have protections setup as part of collection loading
6983 result = KERN_SUCCESS;
6984 goto finish;
6985 }
6986 #endif
6987
6988 /* Protect the headers as read-only; they do not need to be wired */
6989 result = (protect) ? OSKext_protect((kernel_mach_header_t *)kmod_info->address,
6990 kext_map, kmod_info->address,
6991 kmod_info->address + kmod_info->hdr_size, VM_PROT_READ, TRUE, kc_type)
6992 : KERN_SUCCESS;
6993 if (result != KERN_SUCCESS) {
6994 goto finish;
6995 }
6996
6997 /* Set the VM protections and wire down each of the segments */
6998 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
6999 while (seg) {
7000 #if __arm__
7001 /* We build all ARM kexts, so we can ensure they are aligned */
7002 assert((seg->vmaddr & PAGE_MASK) == 0);
7003 assert((seg->vmsize & PAGE_MASK) == 0);
7004 #endif
7005
7006 /*
7007 * For the non page aligned segments, the range calculation for protection
7008 * and wiring differ as follows:
7009 *
7010 * Protection: The non page aligned data at the start or at the end of the
7011 * segment is excluded from the protection. This exclusion is needed to make
7012 * sure OSKext_protect is not called twice on same page, if the page is shared
7013 * between two segments.
7014 *
7015 * Wiring: The non page aligned data at the start or at the end of the
7016 * segment is included in the wiring range, this inclusion is needed to make sure
7017 * all the data of the segment is wired.
7018 */
7019 start_protect = round_page(seg->vmaddr);
7020 end_protect = trunc_page(seg->vmaddr + seg->vmsize);
7021
7022 start_wire = trunc_page(seg->vmaddr);
7023 end_wire = round_page(seg->vmaddr + seg->vmsize);
7024
7025 /*
7026 * Linkedit and Linkinfo for the Pageable KC and the Aux KC are shared
7027 * across kexts and data from kexts is not page aligned
7028 */
7029 if (protect && (end_protect > start_protect) &&
7030 ((strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0 &&
7031 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) != 0) ||
7032 (kc_type != KCKindPageable && kc_type != KCKindAuxiliary))) {
7033 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7034 kext_map, start_protect, end_protect, seg->maxprot, TRUE, kc_type);
7035 if (result != KERN_SUCCESS) {
7036 OSKextLog(this,
7037 kOSKextLogErrorLevel |
7038 kOSKextLogLoadFlag,
7039 "Kext %s failed to set maximum VM protections "
7040 "for segment %s - 0x%x.",
7041 getIdentifierCString(), seg->segname, (int)result);
7042 goto finish;
7043 }
7044
7045 result = OSKext_protect((kernel_mach_header_t *)kmod_info->address,
7046 kext_map, start_protect, end_protect, seg->initprot, FALSE, kc_type);
7047 if (result != KERN_SUCCESS) {
7048 OSKextLog(this,
7049 kOSKextLogErrorLevel |
7050 kOSKextLogLoadFlag,
7051 "Kext %s failed to set initial VM protections "
7052 "for segment %s - 0x%x.",
7053 getIdentifierCString(), seg->segname, (int)result);
7054 goto finish;
7055 }
7056 }
7057
7058 if (segmentShouldBeWired(seg) && wire) {
7059 result = OSKext_wire((kernel_mach_header_t *)kmod_info->address,
7060 kext_map, start_wire, end_wire, seg->initprot, FALSE, kc_type);
7061 if (result != KERN_SUCCESS) {
7062 goto finish;
7063 }
7064 }
7065
7066 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7067 }
7068
7069 finish:
7070 return result;
7071 }
7072
7073 /*********************************************************************
7074 *********************************************************************/
7075 boolean_t
7076 OSKext::segmentShouldBeWired(kernel_segment_command_t *seg)
7077 {
7078 return sKeepSymbols || (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) &&
7079 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)));
7080 }
7081
7082 /*********************************************************************
7083 *********************************************************************/
7084 OSReturn
7085 OSKext::validateKextMapping(bool startFlag)
7086 {
7087 OSReturn result = kOSReturnError;
7088 const char * whichOp = startFlag ? "start" : "stop";
7089 kern_return_t kern_result = 0;
7090 vm_map_t kext_map = NULL;
7091 kernel_segment_command_t * seg = NULL;
7092 mach_vm_address_t address = 0;
7093 mach_vm_size_t size = 0;
7094 uint32_t depth = 0;
7095 uint64_t kext_segbase = 0;
7096 uint64_t kext_segsize = 0;
7097 mach_msg_type_number_t count;
7098 vm_region_submap_short_info_data_64_t info;
7099 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
7100
7101 if (flags.builtin) {
7102 return kOSReturnSuccess;
7103 }
7104
7105 count = VM_REGION_SUBMAP_SHORT_INFO_COUNT_64;
7106 bzero(&info, sizeof(info));
7107
7108 // xxx - do we need a distinct OSReturn value for these or is "bad data"
7109 // xxx - sufficient?
7110
7111 /* Verify that the kmod_info and start/stop pointers are non-NULL.
7112 */
7113 if (!kmod_info) {
7114 OSKextLog(this,
7115 kOSKextLogErrorLevel |
7116 kOSKextLogLoadFlag,
7117 "Kext %s - NULL kmod_info pointer.",
7118 getIdentifierCString());
7119 result = kOSKextReturnBadData;
7120 goto finish;
7121 }
7122
7123 if (startFlag) {
7124 address = (mach_vm_address_t)kmod_info->start;
7125 } else {
7126 address = (mach_vm_address_t)kmod_info->stop;
7127 }
7128
7129 if (!address) {
7130 OSKextLog(this,
7131 kOSKextLogErrorLevel |
7132 kOSKextLogLoadFlag,
7133 "Kext %s - NULL module %s pointer.",
7134 getIdentifierCString(), whichOp);
7135 result = kOSKextReturnBadData;
7136 goto finish;
7137 }
7138
7139 kext_map = kext_get_vm_map(kmod_info);
7140 depth = (kernel_map == kext_map) ? 1 : 2;
7141 if (isInFileset()) {
7142 #if defined(HAS_APPLE_PAC)
7143 address = (mach_vm_address_t)ptrauth_auth_data((void*)address, ptrauth_key_function_pointer, 0);
7144 #endif /* defined(HAS_APPLE_PAC) */
7145 }
7146
7147 /* Verify that the start/stop function lies within the kext's address range.
7148 */
7149 if (getcommandfromheader((kernel_mach_header_t *)kmod_info->address, LC_SEGMENT_SPLIT_INFO) ||
7150 isInFileset()) {
7151 /* This will likely be how we deal with split kexts; walk the segments to
7152 * check that the function lies inside one of the segments of this kext.
7153 */
7154 for (seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7155 seg != NULL;
7156 seg = nextsegfromheader((kernel_mach_header_t *)kmod_info->address, seg)) {
7157 if ((address >= seg->vmaddr) && address < (seg->vmaddr + seg->vmsize)) {
7158 kext_segbase = seg->vmaddr;
7159 kext_segsize = seg->vmsize;
7160 break;
7161 }
7162 }
7163
7164 if (!seg) {
7165 OSKextLog(this,
7166 kOSKextLogErrorLevel |
7167 kOSKextLogLoadFlag,
7168 "Kext %s module %s pointer is outside of kext range "
7169 "(%s %p - kext starts at %p).",
7170 getIdentifierCString(),
7171 whichOp,
7172 whichOp,
7173 (void *)(((uintptr_t)address) - kext_slide),
7174 (void *)(((uintptr_t)kmod_info->address) - kext_slide));
7175 result = kOSKextReturnBadData;
7176 goto finish;
7177 }
7178
7179 seg = NULL;
7180 } else {
7181 if (address < kmod_info->address + kmod_info->hdr_size ||
7182 kmod_info->address + kmod_info->size <= address) {
7183 OSKextLog(this,
7184 kOSKextLogErrorLevel |
7185 kOSKextLogLoadFlag,
7186 "Kext %s module %s pointer is outside of kext range "
7187 "(%s %p - kext at %p-%p).",
7188 getIdentifierCString(),
7189 whichOp,
7190 whichOp,
7191 (void *)(((uintptr_t)address) - kext_slide),
7192 (void *)(((uintptr_t)kmod_info->address) - kext_slide),
7193 (void *)((((uintptr_t)kmod_info->address) - kext_slide) + kmod_info->size));
7194 result = kOSKextReturnBadData;
7195 goto finish;
7196 }
7197 }
7198
7199 /* Only do these checks before calling the start function;
7200 * If anything goes wrong with the mapping while the kext is running,
7201 * we'll likely have panicked well before any attempt to stop the kext.
7202 */
7203 if (startFlag) {
7204 if (!isInFileset() || kc_type != KCKindPrimary) {
7205 /*
7206 * Verify that the start/stop function is executable.
7207 */
7208 kern_result = mach_vm_region_recurse(kernel_map, &address, &size, &depth,
7209 (vm_region_recurse_info_t)&info, &count);
7210 if (kern_result != KERN_SUCCESS) {
7211 OSKextLog(this,
7212 kOSKextLogErrorLevel |
7213 kOSKextLogLoadFlag,
7214 "Kext %s - bad %s pointer %p.",
7215 getIdentifierCString(),
7216 whichOp, (void *)ml_static_unslide(address));
7217 result = kOSKextReturnBadData;
7218 goto finish;
7219 }
7220 } else {
7221 /*
7222 * Since kexts loaded from the primary KC are held in memory
7223 * allocated by efiboot, we cannot use mach_vm_region_recurse() to
7224 * discover that memory's protection flags. Instead, we need to
7225 * get that information from the kernel pmap itself. Above, we
7226 * (potentially) saved the size of the segment in which the address
7227 * in question was located. If we have a non-zero size, verify
7228 * that all pages in the (address, address + kext_segsize) range
7229 * are marked executable. If we somehow did not record the size
7230 * (or the base) just verify the single page that includes the address.
7231 */
7232 if (kext_segbase == 0 || kext_segsize == 0) {
7233 kext_segbase = address & ~(uint64_t)PAGE_MASK;
7234 kext_segsize = PAGE_SIZE;
7235 }
7236 }
7237
7238 #if VM_MAPPED_KEXTS
7239 if (((!isInFileset() || kc_type != KCKindPrimary) && !(info.protection & VM_PROT_EXECUTE)) ||
7240 ((isInFileset() && kc_type == KCKindPrimary) &&
7241 ml_static_verify_page_protections(kext_segbase, kext_segsize, VM_PROT_EXECUTE) != KERN_SUCCESS)) {
7242 OSKextLog(this,
7243 kOSKextLogErrorLevel |
7244 kOSKextLogLoadFlag,
7245 "Kext %s - memory region containing module %s function "
7246 "is not executable.",
7247 getIdentifierCString(), whichOp);
7248 result = kOSKextReturnBadData;
7249 goto finish;
7250 }
7251 #endif
7252
7253 /* Verify that the kext's segments are backed by physical memory.
7254 */
7255 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7256 while (seg) {
7257 if (!verifySegmentMapping(seg)) {
7258 result = kOSKextReturnBadData;
7259 goto finish;
7260 }
7261
7262 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7263 }
7264 }
7265
7266 result = kOSReturnSuccess;
7267 finish:
7268 return result;
7269 }
7270
7271 /*********************************************************************
7272 *********************************************************************/
7273 boolean_t
7274 OSKext::verifySegmentMapping(kernel_segment_command_t *seg)
7275 {
7276 mach_vm_address_t address = 0;
7277
7278 if (seg->vmsize > UINT32_MAX) {
7279 return false;
7280 }
7281
7282 if (!segmentShouldBeWired(seg)) {
7283 return true;
7284 }
7285
7286 for (address = seg->vmaddr;
7287 address < round_page(seg->vmaddr + seg->vmsize);
7288 address += PAGE_SIZE) {
7289 if (!pmap_find_phys(kernel_pmap, (vm_offset_t)address)) {
7290 OSKextLog(this,
7291 kOSKextLogErrorLevel |
7292 kOSKextLogLoadFlag,
7293 "Kext %s - page %p is not backed by physical memory.",
7294 getIdentifierCString(),
7295 (void *)address);
7296 return false;
7297 }
7298 }
7299
7300 return true;
7301 }
7302
7303 /*********************************************************************
7304 *********************************************************************/
7305 static void
7306 OSKextLogKextInfo(OSKext *aKext, uint64_t address, uint64_t size, firehose_tracepoint_code_t code)
7307 {
7308 uint64_t stamp = 0;
7309 firehose_tracepoint_id_u trace_id;
7310 struct firehose_trace_uuid_info_s uuid_info_s;
7311 firehose_trace_uuid_info_t uuid_info = &uuid_info_s;
7312 size_t uuid_info_len = sizeof(struct firehose_trace_uuid_info_s);
7313 OSSharedPtr<OSData> uuid_data;
7314
7315 stamp = firehose_tracepoint_time(firehose_activity_flags_default);
7316 trace_id.ftid_value = FIREHOSE_TRACE_ID_MAKE(firehose_tracepoint_namespace_metadata, _firehose_tracepoint_type_metadata_kext, (firehose_tracepoint_flags_t)0, code);
7317
7318 uuid_data = aKext->copyTextUUID();
7319 if (uuid_data) {
7320 memcpy(uuid_info->ftui_uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_info->ftui_uuid));
7321 }
7322
7323 uuid_info->ftui_size = size;
7324 if (aKext->isDriverKit()) {
7325 uuid_info->ftui_address = address;
7326 } else {
7327 uuid_info->ftui_address = ml_static_unslide(address);
7328 }
7329 firehose_trace_metadata(firehose_stream_metadata, trace_id, stamp, uuid_info, uuid_info_len);
7330 return;
7331 }
7332
7333 void
7334 OSKext::OSKextLogDriverKitInfoLoad(OSKext *kext)
7335 {
7336 OSKextLogKextInfo(kext, kext->getLoadTag(), 1, firehose_tracepoint_code_load);
7337 }
7338
7339 /*********************************************************************
7340 *********************************************************************/
7341 OSReturn
7342 OSKext::start(bool startDependenciesFlag)
7343 {
7344 OSReturn result = kOSReturnError;
7345 kern_return_t (* startfunc)(kmod_info_t *, void *);
7346 unsigned int i, count;
7347 void * kmodStartData = NULL;
7348
7349 if (isStarted() || isInterface() || isKernelComponent()) {
7350 result = kOSReturnSuccess;
7351 goto finish;
7352 }
7353
7354 if (!isLoaded()) {
7355 OSKextLog(this,
7356 kOSKextLogErrorLevel |
7357 kOSKextLogLoadFlag,
7358 "Attempt to start nonloaded kext %s.",
7359 getIdentifierCString());
7360 result = kOSKextReturnInvalidArgument;
7361 goto finish;
7362 }
7363
7364 if (!sLoadEnabled) {
7365 OSKextLog(this,
7366 kOSKextLogErrorLevel |
7367 kOSKextLogLoadFlag,
7368 "Kext loading is disabled (attempt to start kext %s).",
7369 getIdentifierCString());
7370 result = kOSKextReturnDisabled;
7371 goto finish;
7372 }
7373
7374 result = validateKextMapping(/* start? */ true);
7375 if (result != kOSReturnSuccess) {
7376 goto finish;
7377 }
7378
7379 startfunc = kmod_info->start;
7380
7381 count = getNumDependencies();
7382 for (i = 0; i < count; i++) {
7383 OSKext * dependency = OSDynamicCast(OSKext, dependencies->getObject(i));
7384 if (dependency == NULL) {
7385 OSKextLog(this,
7386 kOSKextLogErrorLevel |
7387 kOSKextLogLoadFlag,
7388 "Kext %s start - internal error, dependency disappeared.",
7389 getIdentifierCString());
7390 goto finish;
7391 }
7392 if (!dependency->isStarted()) {
7393 if (startDependenciesFlag) {
7394 OSReturn dependencyResult =
7395 dependency->start(startDependenciesFlag);
7396 if (dependencyResult != KERN_SUCCESS) {
7397 OSKextLog(this,
7398 kOSKextLogErrorLevel |
7399 kOSKextLogLoadFlag,
7400 "Kext %s start - dependency %s failed to start (error 0x%x).",
7401 getIdentifierCString(),
7402 dependency->getIdentifierCString(),
7403 dependencyResult);
7404 goto finish;
7405 }
7406 } else {
7407 OSKextLog(this,
7408 kOSKextLogErrorLevel |
7409 kOSKextLogLoadFlag,
7410 "Not starting %s - dependency %s not started yet.",
7411 getIdentifierCString(),
7412 dependency->getIdentifierCString());
7413 result = kOSKextReturnStartStopError; // xxx - make new return?
7414 goto finish;
7415 }
7416 }
7417 }
7418
7419 OSKextLog(this,
7420 kOSKextLogDetailLevel |
7421 kOSKextLogLoadFlag,
7422 "Kext %s calling module start function.",
7423 getIdentifierCString());
7424
7425 flags.starting = 1;
7426
7427 // Drop a log message so logd can grab the needed information to decode this kext
7428 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_load);
7429 result = OSRuntimeInitializeCPP(this);
7430 if (result == KERN_SUCCESS) {
7431 result = startfunc(kmod_info, kmodStartData);
7432 }
7433
7434 flags.starting = 0;
7435
7436 /* On success overlap the setting of started/starting. On failure just
7437 * clear starting.
7438 */
7439 if (result == KERN_SUCCESS) {
7440 flags.started = 1;
7441
7442 // xxx - log start error from kernel?
7443 OSKextLog(this,
7444 kOSKextLogProgressLevel |
7445 kOSKextLogLoadFlag,
7446 "Kext %s is now started.",
7447 getIdentifierCString());
7448 } else {
7449 invokeOrCancelRequestCallbacks(
7450 /* result not actually used */ kOSKextReturnStartStopError,
7451 /* invokeFlag */ false);
7452 OSKextLog(this,
7453 kOSKextLogWarningLevel |
7454 kOSKextLogLoadFlag,
7455 "Kext %s did not start (return code 0x%x).",
7456 getIdentifierCString(), result);
7457 }
7458
7459 finish:
7460 return result;
7461 }
7462
7463 /*********************************************************************
7464 *********************************************************************/
7465 /* static */
7466 bool
7467 OSKext::canUnloadKextWithIdentifier(
7468 OSString * kextIdentifier,
7469 bool checkClassesFlag)
7470 {
7471 bool result = false;
7472 OSKext * aKext = NULL; // do not release
7473
7474 IORecursiveLockLock(sKextLock);
7475
7476 aKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
7477
7478 if (!aKext) {
7479 goto finish; // can't unload what's not loaded
7480 }
7481
7482 if (aKext->isLoaded()) {
7483 if (aKext->getRetainCount() > kOSKextMinLoadedRetainCount) {
7484 goto finish;
7485 }
7486 if (checkClassesFlag && aKext->hasOSMetaClassInstances()) {
7487 goto finish;
7488 }
7489 }
7490
7491 result = true;
7492
7493 finish:
7494 IORecursiveLockUnlock(sKextLock);
7495 return result;
7496 }
7497
7498 /*********************************************************************
7499 *********************************************************************/
7500 OSReturn
7501 OSKext::stop(void)
7502 {
7503 OSReturn result = kOSReturnError;
7504 kern_return_t (*stopfunc)(kmod_info_t *, void *);
7505
7506 if (!isStarted() || isInterface()) {
7507 result = kOSReturnSuccess;
7508 goto finish;
7509 }
7510
7511 if (!isLoaded()) {
7512 OSKextLog(this,
7513 kOSKextLogErrorLevel |
7514 kOSKextLogLoadFlag,
7515 "Attempt to stop nonloaded kext %s.",
7516 getIdentifierCString());
7517 result = kOSKextReturnInvalidArgument;
7518 goto finish;
7519 }
7520
7521 /* Refuse to stop if we have clients or instances. It is up to
7522 * the caller to make sure those aren't true.
7523 */
7524 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7525 OSKextLog(this,
7526 kOSKextLogErrorLevel |
7527 kOSKextLogLoadFlag,
7528 "Kext %s - C++ instances; can't stop.",
7529 getIdentifierCString());
7530 result = kOSKextReturnInUse;
7531 goto finish;
7532 }
7533
7534 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7535 OSKextLog(this,
7536 kOSKextLogErrorLevel |
7537 kOSKextLogLoadFlag,
7538 "Kext %s - has references (linkage or tracking object); "
7539 "can't stop.",
7540 getIdentifierCString());
7541 result = kOSKextReturnInUse;
7542 goto finish;
7543 }
7544
7545 /* Note: If validateKextMapping fails on the stop & unload path,
7546 * we are in serious trouble and a kernel panic is likely whether
7547 * we stop & unload the kext or not.
7548 */
7549 result = validateKextMapping(/* start? */ false);
7550 if (result != kOSReturnSuccess) {
7551 goto finish;
7552 }
7553
7554 stopfunc = kmod_info->stop;
7555 if (stopfunc) {
7556 OSKextLog(this,
7557 kOSKextLogDetailLevel |
7558 kOSKextLogLoadFlag,
7559 "Kext %s calling module stop function.",
7560 getIdentifierCString());
7561
7562 flags.stopping = 1;
7563
7564 result = stopfunc(kmod_info, /* userData */ NULL);
7565 if (result == KERN_SUCCESS) {
7566 result = OSRuntimeFinalizeCPP(this);
7567 }
7568
7569 flags.stopping = 0;
7570
7571 if (result == KERN_SUCCESS) {
7572 flags.started = 0;
7573
7574 OSKextLog(this,
7575 kOSKextLogDetailLevel |
7576 kOSKextLogLoadFlag,
7577 "Kext %s is now stopped and ready to unload.",
7578 getIdentifierCString());
7579 } else {
7580 OSKextLog(this,
7581 kOSKextLogErrorLevel |
7582 kOSKextLogLoadFlag,
7583 "Kext %s did not stop (return code 0x%x).",
7584 getIdentifierCString(), result);
7585 result = kOSKextReturnStartStopError;
7586 }
7587 }
7588
7589 finish:
7590 // Drop a log message so logd can update this kext's metadata
7591 OSKextLogKextInfo(this, kmod_info->address, kmod_info->size, firehose_tracepoint_code_unload);
7592 return result;
7593 }
7594
7595 /*********************************************************************
7596 *********************************************************************/
7597 OSReturn
7598 OSKext::unload(void)
7599 {
7600 OSReturn result = kOSReturnError;
7601 unsigned int index;
7602 uint32_t num_kmod_refs = 0;
7603 OSKextAccount * freeAccount;
7604 bool in_fileset = false;
7605
7606 if (!sUnloadEnabled) {
7607 OSKextLog(this,
7608 kOSKextLogErrorLevel |
7609 kOSKextLogLoadFlag,
7610 "Kext unloading is disabled (%s).",
7611 this->getIdentifierCString());
7612
7613 result = kOSKextReturnDisabled;
7614 goto finish;
7615 }
7616
7617 // cache this result so we don't need to access the kmod_info after
7618 // it's been potentially free'd
7619 in_fileset = isInFileset();
7620
7621 /* Refuse to unload if we have clients or instances. It is up to
7622 * the caller to make sure those aren't true.
7623 */
7624 if (getRetainCount() > kOSKextMinLoadedRetainCount) {
7625 // xxx - Don't log under errors? this is more of an info thing
7626 OSKextLog(this,
7627 kOSKextLogErrorLevel |
7628 kOSKextLogKextBookkeepingFlag,
7629 "Can't unload kext %s; outstanding references (linkage or tracking object).",
7630 getIdentifierCString());
7631 result = kOSKextReturnInUse;
7632 goto finish;
7633 }
7634
7635 if (isDriverKit()) {
7636 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7637 if (index != (unsigned int)-1) {
7638 sLoadedDriverKitKexts->removeObject(index);
7639 OSKextLogKextInfo(this, loadTag, 1, firehose_tracepoint_code_unload);
7640 loadTag = 0;
7641 }
7642 }
7643
7644 if (!isLoaded()) {
7645 result = kOSReturnSuccess;
7646 goto finish;
7647 }
7648
7649 if (isKernelComponent()) {
7650 result = kOSKextReturnInvalidArgument;
7651 goto finish;
7652 }
7653
7654 if (metaClasses && !OSMetaClass::removeClasses(metaClasses.get())) {
7655 OSKextLog(this,
7656 kOSKextLogErrorLevel |
7657 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
7658 "Can't unload kext %s; classes have instances:",
7659 getIdentifierCString());
7660 reportOSMetaClassInstances(kOSKextLogErrorLevel |
7661 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag);
7662 result = kOSKextReturnInUse;
7663 goto finish;
7664 }
7665
7666 /* Note that the kext is unloading before running any code that
7667 * might be in the kext (request callbacks, module stop function).
7668 * We will deny certain requests made against a kext in the process
7669 * of unloading.
7670 */
7671 flags.unloading = 1;
7672
7673 /* Update the string describing the last kext to unload in case we panic.
7674 */
7675 savePanicString(/* isLoading */ false);
7676
7677 if (isStarted()) {
7678 result = stop();
7679 if (result != KERN_SUCCESS) {
7680 OSKextLog(this,
7681 kOSKextLogErrorLevel |
7682 kOSKextLogLoadFlag,
7683 "Kext %s can't unload - module stop returned 0x%x.",
7684 getIdentifierCString(), (unsigned)result);
7685 result = kOSKextReturnStartStopError;
7686 goto finish;
7687 }
7688 }
7689
7690 OSKextLog(this,
7691 kOSKextLogProgressLevel |
7692 kOSKextLogLoadFlag,
7693 "Kext %s unloading.",
7694 getIdentifierCString());
7695
7696 {
7697 struct list_head *p;
7698 struct list_head *prev;
7699 struct list_head *next;
7700 for (p = pendingPgoHead.next; p != &pendingPgoHead; p = next) {
7701 OSKextGrabPgoStruct *s = container_of(p, OSKextGrabPgoStruct, list_head);
7702 s->err = OSKextGrabPgoDataLocked(this, s->metadata, instance_uuid, s->pSize, s->pBuffer, s->bufferSize);
7703 prev = p->prev;
7704 next = p->next;
7705 prev->next = next;
7706 next->prev = prev;
7707 p->prev = p;
7708 p->next = p;
7709 IORecursiveLockWakeup(sKextLock, s, false);
7710 }
7711 }
7712
7713
7714 /* Even if we don't call the stop function, we want to be sure we
7715 * have no OSMetaClass references before unloading the kext executable
7716 * from memory. OSMetaClasses may have pointers into the kext executable
7717 * and that would cause a panic on OSKext::free() when metaClasses is freed.
7718 */
7719 if (metaClasses) {
7720 metaClasses->flushCollection();
7721 }
7722 (void) OSRuntimeFinalizeCPP(this);
7723
7724 /* Remove the kext from the list of loaded kexts, patch the gap
7725 * in the kmod_info_t linked list, and reset "kmod" to point to the
7726 * last loaded kext that isn't the fake kernel kext (sKernelKext).
7727 */
7728 index = sLoadedKexts->getNextIndexOfObject(this, 0);
7729 if (index != (unsigned int)-1) {
7730 sLoadedKexts->removeObject(index);
7731
7732 OSKext * nextKext = OSDynamicCast(OSKext,
7733 sLoadedKexts->getObject(index));
7734
7735 if (nextKext) {
7736 if (index > 0) {
7737 OSKext * gapKext = OSDynamicCast(OSKext,
7738 sLoadedKexts->getObject(index - 1));
7739
7740 nextKext->kmod_info->next = gapKext->kmod_info;
7741 } else { /* index == 0 */
7742 nextKext->kmod_info->next = NULL;
7743 }
7744 }
7745
7746 OSKext * lastKext = OSDynamicCast(OSKext, sLoadedKexts->getLastObject());
7747 if (lastKext && !lastKext->isKernel()) {
7748 kmod = lastKext->kmod_info;
7749 } else {
7750 kmod = NULL; // clear the global kmod variable
7751 }
7752 }
7753
7754 /* Clear out the kmod references that we're keeping for compatibility
7755 * with current panic backtrace code & kgmacros.
7756 * xxx - will want to update those bits sometime and remove this.
7757 */
7758 num_kmod_refs = getNumDependencies();
7759 if (num_kmod_refs && kmod_info && kmod_info->reference_list) {
7760 for (uint32_t refIndex = 0; refIndex < num_kmod_refs; refIndex++) {
7761 kmod_reference_t * ref = &(kmod_info->reference_list[refIndex]);
7762 ref->info->reference_count--;
7763 }
7764 kfree(kmod_info->reference_list,
7765 num_kmod_refs * sizeof(kmod_reference_t));
7766 }
7767
7768 #if CONFIG_DTRACE
7769 unregisterWithDTrace();
7770 #endif /* CONFIG_DTRACE */
7771
7772 notifyKextUnloadObservers(this);
7773
7774 freeAccount = NULL;
7775 IOSimpleLockLock(sKextAccountsLock);
7776 account->kext = NULL;
7777 if (account->site.tag) {
7778 account->site.flags |= VM_TAG_UNLOAD;
7779 } else {
7780 freeAccount = account;
7781 }
7782 IOSimpleLockUnlock(sKextAccountsLock);
7783 if (freeAccount) {
7784 IODelete(freeAccount, OSKextAccount, 1);
7785 }
7786
7787 /* Unwire and free the linked executable.
7788 */
7789 if (linkedExecutable) {
7790 #if KASAN
7791 kasan_unload_kext((vm_offset_t)linkedExecutable->getBytesNoCopy(), linkedExecutable->getLength());
7792 #endif
7793
7794 #if VM_MAPPED_KEXTS
7795 if (!isInterface() && (!in_fileset || flags.resetSegmentsFromVnode)) {
7796 kernel_segment_command_t *seg = NULL;
7797 vm_map_t kext_map = kext_get_vm_map(kmod_info);
7798
7799 if (!kext_map) {
7800 OSKextLog(this,
7801 kOSKextLogErrorLevel |
7802 kOSKextLogLoadFlag,
7803 "Failed to free kext %s; couldn't find the kext map.",
7804 getIdentifierCString());
7805 result = kOSKextReturnInternalError;
7806 goto finish;
7807 }
7808
7809 OSKextLog(this,
7810 kOSKextLogProgressLevel |
7811 kOSKextLogLoadFlag,
7812 "Kext %s unwiring and unmapping linked executable.",
7813 getIdentifierCString());
7814
7815 seg = firstsegfromheader((kernel_mach_header_t *)kmod_info->address);
7816 while (seg) {
7817 if (segmentShouldBeWired(seg)) {
7818 vm_map_offset_t start_wire = trunc_page(seg->vmaddr);
7819 vm_map_offset_t end_wire = round_page(seg->vmaddr + seg->vmsize);
7820
7821 result = vm_map_unwire(kext_map, start_wire,
7822 end_wire, FALSE);
7823 if (result != KERN_SUCCESS) {
7824 OSKextLog(this,
7825 kOSKextLogErrorLevel |
7826 kOSKextLogLoadFlag,
7827 "Failed to unwire kext %s.",
7828 getIdentifierCString());
7829 result = kOSKextReturnInternalError;
7830 goto finish;
7831 }
7832 }
7833
7834 seg = nextsegfromheader((kernel_mach_header_t *) kmod_info->address, seg);
7835 }
7836 #if defined(__x86_64__) || defined(__i386__)
7837 if (in_fileset && flags.resetSegmentsFromVnode) {
7838 IORecursiveLockLock(sKextLock);
7839 resetKCFileSetSegments();
7840 IORecursiveLockUnlock(sKextLock);
7841 }
7842 #endif // (__x86_64__) || defined(__i386__)
7843 }
7844 #endif /* VM_MAPPED_KEXTS */
7845 if (flags.resetSegmentsFromImmutableCopy) {
7846 result = resetMutableSegments();
7847 if (result != kOSReturnSuccess) {
7848 OSKextLog(this,
7849 kOSKextLogErrorLevel |
7850 kOSKextLogLoadFlag,
7851 "Failed to reset kext %s.",
7852 getIdentifierCString());
7853 result = kOSKextReturnInternalError;
7854 goto finish;
7855 }
7856 }
7857 if (kc_type == KCKindUnknown) {
7858 linkedExecutable.reset();
7859 }
7860 }
7861
7862 /* An interface kext has a fake kmod_info that was allocated,
7863 * so we have to free it.
7864 */
7865 if (isInterface()) {
7866 kfree(kmod_info, sizeof(kmod_info_t));
7867 kmod_info = NULL;
7868 }
7869
7870 if (!in_fileset) {
7871 kmod_info = NULL;
7872 }
7873
7874 flags.loaded = false;
7875 flushDependencies();
7876
7877 /* save a copy of the bundle ID for us to check when deciding to
7878 * rebuild the kernel cache file. If a kext was already in the kernel
7879 * cache and unloaded then later loaded we do not need to rebuild the
7880 * kernel cache. 9055303
7881 */
7882 if (isPrelinked()) {
7883 if (!_OSKextInUnloadedPrelinkedKexts(bundleID.get())) {
7884 IORecursiveLockLock(sKextLock);
7885 if (sUnloadedPrelinkedKexts) {
7886 sUnloadedPrelinkedKexts->setObject(bundleID.get());
7887 }
7888 IORecursiveLockUnlock(sKextLock);
7889 }
7890 }
7891
7892 OSKextLog(this,
7893 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
7894 "Kext %s unloaded.", getIdentifierCString());
7895
7896 queueKextNotification(kKextRequestPredicateUnloadNotification,
7897 OSDynamicCast(OSString, bundleID.get()));
7898
7899 finish:
7900 OSKext::saveLoadedKextPanicList();
7901 OSKext::updateLoadedKextSummaries();
7902
7903 flags.unloading = 0;
7904 return result;
7905 }
7906
7907 /*********************************************************************
7908 * Assumes sKextLock is held.
7909 *********************************************************************/
7910 /* static */
7911 OSReturn
7912 OSKext::queueKextNotification(
7913 const char * notificationName,
7914 OSString * kextIdentifier)
7915 {
7916 OSReturn result = kOSReturnError;
7917 OSSharedPtr<OSDictionary> loadRequest;
7918
7919 if (!kextIdentifier) {
7920 result = kOSKextReturnInvalidArgument;
7921 goto finish;
7922 }
7923
7924 /* Create a new request unless one is already sitting
7925 * in sKernelRequests for this bundle identifier
7926 */
7927 result = _OSKextCreateRequest(notificationName, loadRequest);
7928 if (result != kOSReturnSuccess) {
7929 goto finish;
7930 }
7931 if (!_OSKextSetRequestArgument(loadRequest.get(),
7932 kKextRequestArgumentBundleIdentifierKey, kextIdentifier)) {
7933 result = kOSKextReturnNoMemory;
7934 goto finish;
7935 }
7936 if (!sKernelRequests->setObject(loadRequest.get())) {
7937 result = kOSKextReturnNoMemory;
7938 goto finish;
7939 }
7940
7941 /* We might want to only queue the notification if the IOKit daemon is active,
7942 * but that wouldn't work for embedded. Note that we don't care if
7943 * the ping immediately succeeds here so don't do anything with the
7944 * result of this call.
7945 */
7946 OSKext::pingIOKitDaemon();
7947
7948 result = kOSReturnSuccess;
7949
7950 finish:
7951 return result;
7952 }
7953
7954
7955 #if CONFIG_KXLD
7956 /*********************************************************************
7957 *********************************************************************/
7958 static void
7959 _OSKextConsiderDestroyingLinkContext(
7960 __unused thread_call_param_t p0,
7961 __unused thread_call_param_t p1)
7962 {
7963 /* Take multiple locks in the correct order.
7964 */
7965 IORecursiveLockLock(sKextLock);
7966 IORecursiveLockLock(sKextInnerLock);
7967
7968 /* The first time we destroy the kxldContext is in the first
7969 * OSKext::considerUnloads() call, which sets sConsiderUnloadsCalled
7970 * before calling this function. Thereafter any call to this function
7971 * will actually destroy the context.
7972 */
7973 if (sConsiderUnloadsCalled && sKxldContext) {
7974 kxld_destroy_context(sKxldContext);
7975 sKxldContext = NULL;
7976 }
7977
7978 /* Free the thread_call that was allocated to execute this function.
7979 */
7980 if (sDestroyLinkContextThread) {
7981 if (!thread_call_free(sDestroyLinkContextThread)) {
7982 OSKextLog(/* kext */ NULL,
7983 kOSKextLogErrorLevel |
7984 kOSKextLogGeneralFlag,
7985 "thread_call_free() failed for kext link context.");
7986 }
7987 sDestroyLinkContextThread = NULL;
7988 }
7989
7990 IORecursiveLockUnlock(sKextInnerLock);
7991 IORecursiveLockUnlock(sKextLock);
7992
7993 return;
7994 }
7995
7996 /*********************************************************************
7997 * Destroying the kxldContext requires checking variables under both
7998 * sKextInnerLock and sKextLock, so we do it on a separate thread
7999 * to avoid deadlocks with IOService, with which OSKext has a reciprocal
8000 * call relationship.
8001 *
8002 * This function must be invoked with sKextInnerLock held.
8003 * Do not call any function that takes sKextLock here!
8004 *********************************************************************/
8005 /* static */
8006 void
8007 OSKext::considerDestroyingLinkContext(void)
8008 {
8009 IORecursiveLockLock(sKextInnerLock);
8010
8011 /* If we have already queued a thread to destroy the link context,
8012 * don't bother resetting; that thread will take care of it.
8013 */
8014 if (sDestroyLinkContextThread) {
8015 goto finish;
8016 }
8017
8018 /* The function to be invoked in the thread will deallocate
8019 * this thread_call, so don't share it around.
8020 */
8021 sDestroyLinkContextThread = thread_call_allocate(
8022 &_OSKextConsiderDestroyingLinkContext, NULL);
8023 if (!sDestroyLinkContextThread) {
8024 OSKextLog(/* kext */ NULL,
8025 kOSKextLogErrorLevel | kOSKextLogGeneralFlag | kOSKextLogLinkFlag,
8026 "Can't create thread to destroy kext link context.");
8027 goto finish;
8028 }
8029
8030 thread_call_enter(sDestroyLinkContextThread);
8031
8032 finish:
8033 IORecursiveLockUnlock(sKextInnerLock);
8034 return;
8035 }
8036
8037 #else // !CONFIG_KXLD
8038
8039 /* static */
8040 void
8041 OSKext::considerDestroyingLinkContext(void)
8042 {
8043 return;
8044 }
8045
8046 #endif // CONFIG_KXLD
8047
8048 #if PRAGMA_MARK
8049 #pragma mark Autounload
8050 #endif
8051 /*********************************************************************
8052 * This is a static method because the kext will be deallocated if it
8053 * does unload!
8054 *********************************************************************/
8055 /* static */
8056 OSReturn
8057 OSKext::autounloadKext(OSKext * aKext)
8058 {
8059 OSReturn result = kOSKextReturnInUse;
8060
8061 #if NO_KEXTD
8062 /*
8063 * Do not unload prelinked kexts on platforms that do not have an
8064 * IOKit daemon as there is no way to reload the kext or restart
8065 * matching.
8066 */
8067 if (aKext->isPrelinked()) {
8068 goto finish;
8069 }
8070 #endif /* defined(__x86_64__) */
8071
8072 /* Check for external references to this kext (usu. dependents),
8073 * instances of defined classes (or classes derived from them),
8074 * outstanding requests.
8075 */
8076 if ((aKext->getRetainCount() > kOSKextMinLoadedRetainCount) ||
8077 !aKext->flags.autounloadEnabled ||
8078 aKext->isKernelComponent()) {
8079 goto finish;
8080 }
8081
8082 /* Skip a delay-autounload kext, once.
8083 */
8084 if (aKext->flags.delayAutounload) {
8085 OSKextLog(aKext,
8086 kOSKextLogProgressLevel |
8087 kOSKextLogLoadFlag | kOSKextLogKextBookkeepingFlag,
8088 "Kext %s has delayed autounload set; skipping and clearing flag.",
8089 aKext->getIdentifierCString());
8090 aKext->flags.delayAutounload = 0;
8091 goto finish;
8092 }
8093
8094 if (aKext->hasOSMetaClassInstances() ||
8095 aKext->countRequestCallbacks()) {
8096 goto finish;
8097 }
8098
8099 result = OSKext::removeKext(aKext);
8100
8101 finish:
8102 return result;
8103 }
8104
8105 /*********************************************************************
8106 *********************************************************************/
8107 void
8108 _OSKextConsiderUnloads(
8109 __unused thread_call_param_t p0,
8110 __unused thread_call_param_t p1)
8111 {
8112 bool didUnload = false;
8113 unsigned int count, i;
8114
8115 /* Take multiple locks in the correct order
8116 * (note also sKextSummaries lock further down).
8117 */
8118 IORecursiveLockLock(sKextLock);
8119 IORecursiveLockLock(sKextInnerLock);
8120
8121 OSKext::flushNonloadedKexts(/* flushPrelinkedKexts */ true);
8122
8123 /* If the system is powering down, don't try to unload anything.
8124 */
8125 if (sSystemSleep) {
8126 goto finish;
8127 }
8128
8129 OSKextLog(/* kext */ NULL,
8130 kOSKextLogProgressLevel | kOSKextLogLoadFlag,
8131 "Checking for unused kexts to autounload.");
8132
8133 /*****
8134 * Remove any request callbacks marked as stale,
8135 * and mark as stale any currently in flight.
8136 */
8137 count = sRequestCallbackRecords->getCount();
8138 if (count) {
8139 i = count - 1;
8140 do {
8141 OSDictionary * callbackRecord = OSDynamicCast(OSDictionary,
8142 sRequestCallbackRecords->getObject(i));
8143 OSBoolean * stale = OSDynamicCast(OSBoolean,
8144 callbackRecord->getObject(kKextRequestStaleKey));
8145
8146 if (stale == kOSBooleanTrue) {
8147 OSKext::invokeRequestCallback(callbackRecord,
8148 kOSKextReturnTimeout);
8149 } else {
8150 callbackRecord->setObject(kKextRequestStaleKey,
8151 kOSBooleanTrue);
8152 }
8153 } while (i--);
8154 }
8155
8156 /*****
8157 * Make multiple passes through the array of loaded kexts until
8158 * we don't unload any. This handles unwinding of dependency
8159 * chains. We have to go *backwards* through the array because
8160 * kexts are removed from it when unloaded, and we cannot make
8161 * a copy or we'll mess up the retain counts we rely on to
8162 * check whether a kext will unload. If only we could have
8163 * nonretaining collections like CF has....
8164 */
8165 do {
8166 didUnload = false;
8167
8168 count = sLoadedKexts->getCount();
8169 if (count) {
8170 i = count - 1;
8171 do {
8172 OSKext * thisKext = OSDynamicCast(OSKext,
8173 sLoadedKexts->getObject(i));
8174 didUnload |= (kOSReturnSuccess == OSKext::autounloadKext(thisKext));
8175 } while (i--);
8176 }
8177 } while (didUnload);
8178
8179 finish:
8180 sConsiderUnloadsPending = false;
8181 sConsiderUnloadsExecuted = true;
8182
8183 (void) OSKext::considerRebuildOfPrelinkedKernel();
8184
8185 IORecursiveLockUnlock(sKextInnerLock);
8186 IORecursiveLockUnlock(sKextLock);
8187
8188 return;
8189 }
8190
8191 /*********************************************************************
8192 * Do not call any function that takes sKextLock here!
8193 *********************************************************************/
8194 void
8195 OSKext::considerUnloads(Boolean rescheduleOnlyFlag)
8196 {
8197 AbsoluteTime when;
8198
8199 IORecursiveLockLock(sKextInnerLock);
8200
8201 if (!sUnloadCallout) {
8202 sUnloadCallout = thread_call_allocate(&_OSKextConsiderUnloads, NULL);
8203 }
8204
8205 /* we only reset delay value for unloading if we already have something
8206 * pending. rescheduleOnlyFlag should not start the count down.
8207 */
8208 if (rescheduleOnlyFlag && !sConsiderUnloadsPending) {
8209 goto finish;
8210 }
8211
8212 thread_call_cancel(sUnloadCallout);
8213 if (OSKext::getAutounloadEnabled() && !sSystemSleep
8214 #if !NO_KEXTD
8215 && sIOKitDaemonActive
8216 #endif
8217 ) {
8218 clock_interval_to_deadline(sConsiderUnloadDelay,
8219 1000 * 1000 * 1000, &when);
8220
8221 OSKextLog(/* kext */ NULL,
8222 kOSKextLogProgressLevel |
8223 kOSKextLogLoadFlag,
8224 "%scheduling %sscan for unused kexts in %lu seconds.",
8225 sConsiderUnloadsPending ? "Res" : "S",
8226 sConsiderUnloadsCalled ? "" : "initial ",
8227 (unsigned long)sConsiderUnloadDelay);
8228
8229 sConsiderUnloadsPending = true;
8230 thread_call_enter_delayed(sUnloadCallout, when);
8231 }
8232
8233 finish:
8234 /* The kxld context should be reused throughout boot. We mark the end of
8235 * period as the first time considerUnloads() is called, and we destroy
8236 * the first kxld context in that function. Afterwards, it will be
8237 * destroyed in flushNonloadedKexts.
8238 */
8239 if (!sConsiderUnloadsCalled) {
8240 sConsiderUnloadsCalled = true;
8241 OSKext::considerDestroyingLinkContext();
8242 }
8243
8244 IORecursiveLockUnlock(sKextInnerLock);
8245 return;
8246 }
8247
8248 /*********************************************************************
8249 * Do not call any function that takes sKextLock here!
8250 *********************************************************************/
8251 extern "C" {
8252 IOReturn OSKextSystemSleepOrWake(UInt32 messageType);
8253 IOReturn
8254 OSKextSystemSleepOrWake(UInt32 messageType)
8255 {
8256 IORecursiveLockLock(sKextInnerLock);
8257
8258 /* If the system is going to sleep, cancel the reaper thread timer,
8259 * and note that we're in a sleep state in case it just fired but hasn't
8260 * taken the lock yet. If we are coming back from sleep, just
8261 * clear the sleep flag; IOService's normal operation will cause
8262 * unloads to be considered soon enough.
8263 */
8264 if (messageType == kIOMessageSystemWillSleep) {
8265 if (sUnloadCallout) {
8266 thread_call_cancel(sUnloadCallout);
8267 }
8268 sSystemSleep = true;
8269 AbsoluteTime_to_scalar(&sLastWakeTime) = 0;
8270 } else if (messageType == kIOMessageSystemHasPoweredOn) {
8271 sSystemSleep = false;
8272 clock_get_uptime(&sLastWakeTime);
8273 }
8274 IORecursiveLockUnlock(sKextInnerLock);
8275
8276 return kIOReturnSuccess;
8277 }
8278 };
8279
8280
8281 #if PRAGMA_MARK
8282 #pragma mark Prelinked Kernel
8283 #endif
8284
8285 #ifdef CONFIG_KXLD
8286 /*********************************************************************
8287 * Do not access sConsiderUnloads... variables other than
8288 * sConsiderUnloadsExecuted in this function. They are guarded by a
8289 * different lock.
8290 *********************************************************************/
8291 /* static */
8292 void
8293 OSKext::considerRebuildOfPrelinkedKernel(void)
8294 {
8295 static bool requestedPrelink = false;
8296 OSReturn checkResult = kOSReturnError;
8297 OSSharedPtr<OSDictionary> prelinkRequest;
8298 OSSharedPtr<OSCollectionIterator> kextIterator;
8299 const OSSymbol * thisID = NULL; // do not release
8300 bool doRebuild = false;
8301 AbsoluteTime my_abstime;
8302 UInt64 my_ns;
8303 SInt32 delta_secs;
8304
8305 /* Only one auto rebuild per boot and only on boot from prelinked kernel */
8306 if (requestedPrelink || !sPrelinkBoot) {
8307 return;
8308 }
8309
8310 /* no direct return from this point */
8311 IORecursiveLockLock(sKextLock);
8312
8313 /* We need to wait for the IOKit daemon to get up and running with unloads already done
8314 * and any new startup kexts loaded.
8315 */
8316 if (!sConsiderUnloadsExecuted ||
8317 !sDeferredLoadSucceeded) {
8318 goto finish;
8319 }
8320
8321 /* we really only care about boot / system start up related kexts so bail
8322 * if we're here after REBUILD_MAX_TIME.
8323 */
8324 if (!_OSKextInPrelinkRebuildWindow()) {
8325 OSKextLog(/* kext */ NULL,
8326 kOSKextLogArchiveFlag,
8327 "%s prebuild rebuild has expired",
8328 __FUNCTION__);
8329 requestedPrelink = true;
8330 goto finish;
8331 }
8332
8333 /* we do not want to trigger a rebuild if we get here too close to waking
8334 * up. (see radar 10233768)
8335 */
8336 IORecursiveLockLock(sKextInnerLock);
8337
8338 clock_get_uptime(&my_abstime);
8339 delta_secs = MINIMUM_WAKEUP_SECONDS + 1;
8340 if (AbsoluteTime_to_scalar(&sLastWakeTime) != 0) {
8341 SUB_ABSOLUTETIME(&my_abstime, &sLastWakeTime);
8342 absolutetime_to_nanoseconds(my_abstime, &my_ns);
8343 delta_secs = (SInt32)(my_ns / NSEC_PER_SEC);
8344 }
8345 IORecursiveLockUnlock(sKextInnerLock);
8346
8347 if (delta_secs < MINIMUM_WAKEUP_SECONDS) {
8348 /* too close to time of last wake from sleep */
8349 goto finish;
8350 }
8351 requestedPrelink = true;
8352
8353 /* Now it's time to see if we have a reason to rebuild. We may have done
8354 * some loads and unloads but the kernel cache didn't actually change.
8355 * We will rebuild if any kext is not marked prelinked AND is not in our
8356 * list of prelinked kexts that got unloaded. (see radar 9055303)
8357 */
8358 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
8359 if (!kextIterator) {
8360 goto finish;
8361 }
8362
8363 while ((thisID = OSDynamicCast(OSSymbol, kextIterator->getNextObject()))) {
8364 OSKext * thisKext; // do not release
8365
8366 thisKext = OSDynamicCast(OSKext, sKextsByID->getObject(thisID));
8367 if (!thisKext || thisKext->isPrelinked() || thisKext->isKernel()) {
8368 continue;
8369 }
8370
8371 if (_OSKextInUnloadedPrelinkedKexts(thisKext->bundleID.get())) {
8372 continue;
8373 }
8374 /* kext is loaded and was not in current kernel cache so let's rebuild
8375 */
8376 doRebuild = true;
8377 OSKextLog(/* kext */ NULL,
8378 kOSKextLogArchiveFlag,
8379 "considerRebuildOfPrelinkedKernel %s triggered rebuild",
8380 thisKext->bundleID->getCStringNoCopy());
8381 break;
8382 }
8383 sUnloadedPrelinkedKexts->flushCollection();
8384
8385 if (!doRebuild) {
8386 goto finish;
8387 }
8388
8389 checkResult = _OSKextCreateRequest(kKextRequestPredicateRequestPrelink,
8390 prelinkRequest);
8391 if (checkResult != kOSReturnSuccess) {
8392 goto finish;
8393 }
8394
8395 if (!sKernelRequests->setObject(prelinkRequest.get())) {
8396 goto finish;
8397 }
8398
8399 OSKext::pingIOKitDaemon();
8400
8401 finish:
8402 IORecursiveLockUnlock(sKextLock);
8403
8404 return;
8405 }
8406
8407 #else /* !CONFIG_KXLD */
8408
8409 void
8410 OSKext::considerRebuildOfPrelinkedKernel(void)
8411 {
8412 /* in a non-dynamic kext loading world, there is never a reason to rebuild */
8413 return;
8414 }
8415
8416 #endif /* CONFIG_KXLD */
8417
8418 #if PRAGMA_MARK
8419 #pragma mark Dependencies
8420 #endif
8421 /*********************************************************************
8422 *********************************************************************/
8423 bool
8424 OSKext::resolveDependencies(
8425 OSArray * loopStack)
8426 {
8427 bool result = false;
8428 OSSharedPtr<OSArray> localLoopStack;
8429 bool addedToLoopStack = false;
8430 OSDictionary * libraries = NULL; // do not release
8431 OSSharedPtr<OSCollectionIterator> libraryIterator;
8432 OSString * libraryID = NULL; // do not release
8433 OSKext * libraryKext = NULL; // do not release
8434 bool hasRawKernelDependency = false;
8435 bool hasKernelDependency = false;
8436 bool hasKPIDependency = false;
8437 bool hasPrivateKPIDependency = false;
8438 unsigned int count;
8439
8440 #if CONFIG_KXLD
8441 OSString * infoString = NULL; // do not release
8442 OSString * readableString = NULL; // do not release
8443 #endif // CONFIG_KXLD
8444
8445 /* A kernel component will automatically have this flag set,
8446 * and a loaded kext should also have it set (as should all its
8447 * loaded dependencies).
8448 */
8449 if (flags.hasAllDependencies) {
8450 result = true;
8451 goto finish;
8452 }
8453
8454 /* Check for loops in the dependency graph.
8455 */
8456 if (loopStack) {
8457 if (loopStack->getNextIndexOfObject(this, 0) != (unsigned int)-1) {
8458 OSKextLog(this,
8459 kOSKextLogErrorLevel |
8460 kOSKextLogDependenciesFlag,
8461 "Kext %s has a dependency loop; can't resolve dependencies.",
8462 getIdentifierCString());
8463 goto finish;
8464 }
8465 } else {
8466 OSKextLog(this,
8467 kOSKextLogStepLevel |
8468 kOSKextLogDependenciesFlag,
8469 "Kext %s resolving dependencies.",
8470 getIdentifierCString());
8471
8472 localLoopStack = OSArray::withCapacity(6); // any small capacity will do
8473 if (!localLoopStack) {
8474 OSKextLog(this,
8475 kOSKextLogErrorLevel |
8476 kOSKextLogDependenciesFlag,
8477 "Kext %s can't create bookkeeping stack to resolve dependencies.",
8478 getIdentifierCString());
8479 goto finish;
8480 }
8481 loopStack = localLoopStack.get();
8482 }
8483 if (!loopStack->setObject(this)) {
8484 OSKextLog(this,
8485 kOSKextLogErrorLevel |
8486 kOSKextLogDependenciesFlag,
8487 "Kext %s - internal error resolving dependencies.",
8488 getIdentifierCString());
8489 goto finish;
8490 }
8491 addedToLoopStack = true;
8492
8493 /* Purge any existing kexts in the dependency list and start over.
8494 */
8495 flushDependencies();
8496 if (dependencies) {
8497 OSKextLog(this,
8498 kOSKextLogErrorLevel |
8499 kOSKextLogDependenciesFlag,
8500 "Kext %s - internal error resolving dependencies.",
8501 getIdentifierCString());
8502 }
8503
8504 libraries = OSDynamicCast(OSDictionary,
8505 getPropertyForHostArch(kOSBundleLibrariesKey));
8506 if (libraries == NULL || libraries->getCount() == 0) {
8507 OSKextLog(this,
8508 kOSKextLogErrorLevel |
8509 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8510 "Kext %s - can't resolve dependencies; %s missing/invalid type.",
8511 getIdentifierCString(), kOSBundleLibrariesKey);
8512 goto finish;
8513 }
8514
8515 /* Make a new array to hold the dependencies (flush freed the old one).
8516 */
8517 dependencies = OSArray::withCapacity(libraries->getCount());
8518 if (!dependencies) {
8519 OSKextLog(this,
8520 kOSKextLogErrorLevel |
8521 kOSKextLogDependenciesFlag,
8522 "Kext %s - can't allocate dependencies array.",
8523 getIdentifierCString());
8524 goto finish;
8525 }
8526
8527 // xxx - compat: We used to add an implicit dependency on kernel 6.0
8528 // xxx - compat: if none were declared.
8529
8530 libraryIterator = OSCollectionIterator::withCollection(libraries);
8531 if (!libraryIterator) {
8532 OSKextLog(this,
8533 kOSKextLogErrorLevel |
8534 kOSKextLogDependenciesFlag,
8535 "Kext %s - can't allocate dependencies iterator.",
8536 getIdentifierCString());
8537 goto finish;
8538 }
8539
8540 while ((libraryID = OSDynamicCast(OSString,
8541 libraryIterator->getNextObject()))) {
8542 const char * library_id = libraryID->getCStringNoCopy();
8543
8544 OSString * libraryVersion = OSDynamicCast(OSString,
8545 libraries->getObject(libraryID));
8546 if (libraryVersion == NULL) {
8547 OSKextLog(this,
8548 kOSKextLogErrorLevel |
8549 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8550 "Kext %s - illegal type in OSBundleLibraries.",
8551 getIdentifierCString());
8552 goto finish;
8553 }
8554
8555 OSKextVersion libraryVers =
8556 OSKextParseVersionString(libraryVersion->getCStringNoCopy());
8557 if (libraryVers == -1) {
8558 OSKextLog(this,
8559 kOSKextLogErrorLevel |
8560 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8561 "Kext %s - invalid library version %s.",
8562 getIdentifierCString(),
8563 libraryVersion->getCStringNoCopy());
8564 goto finish;
8565 }
8566
8567 libraryKext = OSDynamicCast(OSKext, sKextsByID->getObject(libraryID));
8568 if (libraryKext == NULL) {
8569 OSKextLog(this,
8570 kOSKextLogErrorLevel |
8571 kOSKextLogDependenciesFlag,
8572 "Kext %s - library kext %s not found.",
8573 getIdentifierCString(), library_id);
8574 goto finish;
8575 }
8576
8577 if (!libraryKext->isCompatibleWithVersion(libraryVers)) {
8578 OSKextLog(this,
8579 kOSKextLogErrorLevel |
8580 kOSKextLogDependenciesFlag,
8581 "Kext %s - library kext %s not compatible "
8582 "with requested version %s.",
8583 getIdentifierCString(), library_id,
8584 libraryVersion->getCStringNoCopy());
8585 goto finish;
8586 }
8587
8588 /* If a nonprelinked library somehow got into the mix for a
8589 * prelinked kext, at any point in the chain, we must fail
8590 * because the prelinked relocs for the library will be all wrong.
8591 */
8592 if (this->isPrelinked() &&
8593 libraryKext->declaresExecutable() &&
8594 !libraryKext->isPrelinked()) {
8595 OSKextLog(this,
8596 kOSKextLogErrorLevel |
8597 kOSKextLogDependenciesFlag,
8598 "Kext %s (prelinked) - library kext %s (v%s) not prelinked.",
8599 getIdentifierCString(), library_id,
8600 libraryVersion->getCStringNoCopy());
8601 goto finish;
8602 }
8603
8604 if (!libraryKext->resolveDependencies(loopStack)) {
8605 goto finish;
8606 }
8607
8608 /* Add the library directly only if it has an executable to link.
8609 * Otherwise it's just used to collect other dependencies, so put
8610 * *its* dependencies on the list for this kext.
8611 */
8612 // xxx - We are losing info here; would like to make fake entries or
8613 // xxx - keep these in the dependency graph for loaded kexts.
8614 // xxx - I really want to make kernel components not a special case!
8615 if (libraryKext->declaresExecutable() ||
8616 libraryKext->isInterface()) {
8617 if (dependencies->getNextIndexOfObject(libraryKext, 0) == (unsigned)-1) {
8618 dependencies->setObject(libraryKext);
8619
8620 OSKextLog(this,
8621 kOSKextLogDetailLevel |
8622 kOSKextLogDependenciesFlag,
8623 "Kext %s added dependency %s.",
8624 getIdentifierCString(),
8625 libraryKext->getIdentifierCString());
8626 }
8627 } else {
8628 int numLibDependencies = libraryKext->getNumDependencies();
8629 OSArray * libraryDependencies = libraryKext->getDependencies();
8630 int index;
8631
8632 if (numLibDependencies) {
8633 // xxx - this msg level should be 1 lower than the per-kext one
8634 OSKextLog(this,
8635 kOSKextLogDetailLevel |
8636 kOSKextLogDependenciesFlag,
8637 "Kext %s pulling %d dependencies from codeless library %s.",
8638 getIdentifierCString(),
8639 numLibDependencies,
8640 libraryKext->getIdentifierCString());
8641 }
8642 for (index = 0; index < numLibDependencies; index++) {
8643 OSKext * thisLibDependency = OSDynamicCast(OSKext,
8644 libraryDependencies->getObject(index));
8645 if (dependencies->getNextIndexOfObject(thisLibDependency, 0) == (unsigned)-1) {
8646 dependencies->setObject(thisLibDependency);
8647 OSKextLog(this,
8648 kOSKextLogDetailLevel |
8649 kOSKextLogDependenciesFlag,
8650 "Kext %s added dependency %s from codeless library %s.",
8651 getIdentifierCString(),
8652 thisLibDependency->getIdentifierCString(),
8653 libraryKext->getIdentifierCString());
8654 }
8655 }
8656 }
8657
8658 if ((strlen(library_id) == strlen(KERNEL_LIB)) &&
8659 0 == strncmp(library_id, KERNEL_LIB, sizeof(KERNEL_LIB) - 1)) {
8660 hasRawKernelDependency = true;
8661 } else if (STRING_HAS_PREFIX(library_id, KERNEL_LIB_PREFIX)) {
8662 hasKernelDependency = true;
8663 } else if (STRING_HAS_PREFIX(library_id, KPI_LIB_PREFIX)) {
8664 hasKPIDependency = true;
8665 if (!strncmp(library_id, PRIVATE_KPI, sizeof(PRIVATE_KPI) - 1)) {
8666 hasPrivateKPIDependency = true;
8667 }
8668 }
8669 }
8670
8671 if (hasRawKernelDependency) {
8672 OSKextLog(this,
8673 kOSKextLogErrorLevel |
8674 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8675 "Error - kext %s declares a dependency on %s, which is not permitted.",
8676 getIdentifierCString(), KERNEL_LIB);
8677 goto finish;
8678 }
8679 #if __LP64__
8680 if (hasKernelDependency) {
8681 OSKextLog(this,
8682 kOSKextLogErrorLevel |
8683 kOSKextLogValidationFlag | kOSKextLogDependenciesFlag,
8684 "Error - kext %s declares %s dependencies. "
8685 "Only %s* dependencies are supported for 64-bit kexts.",
8686 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8687 goto finish;
8688 }
8689 if (!hasKPIDependency) {
8690 OSKextLog(this,
8691 kOSKextLogWarningLevel |
8692 kOSKextLogDependenciesFlag,
8693 "Warning - kext %s declares no %s* dependencies. "
8694 "If it uses any KPIs, the link may fail with undefined symbols.",
8695 getIdentifierCString(), KPI_LIB_PREFIX);
8696 }
8697 #else /* __LP64__ */
8698 // xxx - will change to flatly disallow "kernel" dependencies at some point
8699 // xxx - is it invalid to do both "com.apple.kernel" and any
8700 // xxx - "com.apple.kernel.*"?
8701
8702 if (hasKernelDependency && hasKPIDependency) {
8703 OSKextLog(this,
8704 kOSKextLogWarningLevel |
8705 kOSKextLogDependenciesFlag,
8706 "Warning - kext %s has immediate dependencies on both "
8707 "%s* and %s* components; use only one style.",
8708 getIdentifierCString(), KERNEL_LIB, KPI_LIB_PREFIX);
8709 }
8710
8711 if (!hasKernelDependency && !hasKPIDependency) {
8712 // xxx - do we want to use validation flag for these too?
8713 OSKextLog(this,
8714 kOSKextLogWarningLevel |
8715 kOSKextLogDependenciesFlag,
8716 "Warning - %s declares no kernel dependencies; using %s.",
8717 getIdentifierCString(), KERNEL6_LIB);
8718 OSKext * kernelKext = OSDynamicCast(OSKext,
8719 sKextsByID->getObject(KERNEL6_LIB));
8720 if (kernelKext) {
8721 dependencies->setObject(kernelKext);
8722 } else {
8723 OSKextLog(this,
8724 kOSKextLogErrorLevel |
8725 kOSKextLogDependenciesFlag,
8726 "Error - Library %s not found for %s.",
8727 KERNEL6_LIB, getIdentifierCString());
8728 }
8729 }
8730
8731 /* If the kext doesn't have a raw kernel or KPI dependency, then add all of
8732 * its indirect dependencies to simulate old-style linking. XXX - Should
8733 * check for duplicates.
8734 */
8735 if (!hasKPIDependency) {
8736 unsigned int i;
8737
8738 flags.hasBleedthrough = true;
8739
8740 count = getNumDependencies();
8741
8742 /* We add to the dependencies array in this loop, but do not iterate
8743 * past its original count.
8744 */
8745 for (i = 0; i < count; i++) {
8746 OSKext * dependencyKext = OSDynamicCast(OSKext,
8747 dependencies->getObject(i));
8748 dependencyKext->addBleedthroughDependencies(dependencies.get());
8749 }
8750 }
8751 #endif /* __LP64__ */
8752
8753 #if CONFIG_KXLD
8754 /*
8755 * If we're not dynamically linking kexts, then we don't need to check
8756 * copyright strings. The linker in user space has already done this.
8757 */
8758 if (hasPrivateKPIDependency) {
8759 bool hasApplePrefix = false;
8760 bool infoCopyrightIsValid = false;
8761 bool readableCopyrightIsValid = false;
8762
8763 hasApplePrefix = STRING_HAS_PREFIX(getIdentifierCString(),
8764 APPLE_KEXT_PREFIX);
8765
8766 infoString = OSDynamicCast(OSString,
8767 getPropertyForHostArch("CFBundleGetInfoString"));
8768 if (infoString) {
8769 infoCopyrightIsValid =
8770 kxld_validate_copyright_string(infoString->getCStringNoCopy());
8771 }
8772
8773 readableString = OSDynamicCast(OSString,
8774 getPropertyForHostArch("NSHumanReadableCopyright"));
8775 if (readableString) {
8776 readableCopyrightIsValid =
8777 kxld_validate_copyright_string(readableString->getCStringNoCopy());
8778 }
8779
8780 if (!hasApplePrefix || (!infoCopyrightIsValid && !readableCopyrightIsValid)) {
8781 OSKextLog(this,
8782 kOSKextLogErrorLevel |
8783 kOSKextLogDependenciesFlag,
8784 "Error - kext %s declares a dependency on %s. "
8785 "Only Apple kexts may declare a dependency on %s.",
8786 getIdentifierCString(), PRIVATE_KPI, PRIVATE_KPI);
8787 goto finish;
8788 }
8789 }
8790 #endif // CONFIG_KXLD
8791
8792 result = true;
8793 flags.hasAllDependencies = 1;
8794
8795 finish:
8796
8797 if (addedToLoopStack) {
8798 count = loopStack->getCount();
8799 if (count > 0 && (this == loopStack->getObject(count - 1))) {
8800 loopStack->removeObject(count - 1);
8801 } else {
8802 OSKextLog(this,
8803 kOSKextLogErrorLevel |
8804 kOSKextLogDependenciesFlag,
8805 "Kext %s - internal error resolving dependencies.",
8806 getIdentifierCString());
8807 }
8808 }
8809
8810 if (result && localLoopStack) {
8811 OSKextLog(this,
8812 kOSKextLogStepLevel |
8813 kOSKextLogDependenciesFlag,
8814 "Kext %s successfully resolved dependencies.",
8815 getIdentifierCString());
8816 }
8817
8818 return result;
8819 }
8820
8821 /*********************************************************************
8822 *********************************************************************/
8823 bool
8824 OSKext::addBleedthroughDependencies(OSArray * anArray)
8825 {
8826 bool result = false;
8827 unsigned int dependencyIndex, dependencyCount;
8828
8829 dependencyCount = getNumDependencies();
8830
8831 for (dependencyIndex = 0;
8832 dependencyIndex < dependencyCount;
8833 dependencyIndex++) {
8834 OSKext * dependency = OSDynamicCast(OSKext,
8835 dependencies->getObject(dependencyIndex));
8836 if (!dependency) {
8837 OSKextLog(this,
8838 kOSKextLogErrorLevel |
8839 kOSKextLogDependenciesFlag,
8840 "Kext %s - internal error propagating compatibility dependencies.",
8841 getIdentifierCString());
8842 goto finish;
8843 }
8844 if (anArray->getNextIndexOfObject(dependency, 0) == (unsigned int)-1) {
8845 anArray->setObject(dependency);
8846 }
8847 dependency->addBleedthroughDependencies(anArray);
8848 }
8849
8850 result = true;
8851
8852 finish:
8853 return result;
8854 }
8855
8856 /*********************************************************************
8857 *********************************************************************/
8858 bool
8859 OSKext::flushDependencies(bool forceFlag)
8860 {
8861 bool result = false;
8862
8863 /* Only clear the dependencies if the kext isn't loaded;
8864 * we need the info for loaded kexts to track references.
8865 */
8866 if (!isLoaded() || forceFlag) {
8867 if (dependencies) {
8868 // xxx - check level
8869 OSKextLog(this,
8870 kOSKextLogProgressLevel |
8871 kOSKextLogDependenciesFlag,
8872 "Kext %s flushing dependencies.",
8873 getIdentifierCString());
8874 dependencies.reset();
8875 }
8876 if (!isKernelComponent()) {
8877 flags.hasAllDependencies = 0;
8878 }
8879 result = true;
8880 }
8881
8882 return result;
8883 }
8884
8885 /*********************************************************************
8886 *********************************************************************/
8887 uint32_t
8888 OSKext::getNumDependencies(void)
8889 {
8890 if (!dependencies) {
8891 return 0;
8892 }
8893 return dependencies->getCount();
8894 }
8895
8896 /*********************************************************************
8897 *********************************************************************/
8898 OSArray *
8899 OSKext::getDependencies(void)
8900 {
8901 return dependencies.get();
8902 }
8903
8904 bool
8905 OSKext::hasDependency(const OSSymbol * depID)
8906 {
8907 bool result __block;
8908
8909 if (depID == getIdentifier()) {
8910 return true;
8911 }
8912 if (!dependencies) {
8913 return false;
8914 }
8915 result = false;
8916 dependencies->iterateObjects(^bool (OSObject * obj) {
8917 OSKext * kext;
8918 kext = OSDynamicCast(OSKext, obj);
8919 if (!kext) {
8920 return false;
8921 }
8922 result = (depID == kext->getIdentifier());
8923 return result;
8924 });
8925 return result;
8926 }
8927
8928 #if PRAGMA_MARK
8929 #pragma mark OSMetaClass Support
8930 #endif
8931 /*********************************************************************
8932 *********************************************************************/
8933 OSReturn
8934 OSKext::addClass(
8935 OSMetaClass * aClass,
8936 uint32_t numClasses)
8937 {
8938 OSReturn result = kOSMetaClassNoInsKModSet;
8939
8940 if (!metaClasses) {
8941 metaClasses = OSSet::withCapacity(numClasses);
8942 if (!metaClasses) {
8943 goto finish;
8944 }
8945 }
8946
8947 if (metaClasses->containsObject(aClass)) {
8948 OSKextLog(this,
8949 kOSKextLogWarningLevel |
8950 kOSKextLogLoadFlag,
8951 "Notice - kext %s has already registered class %s.",
8952 getIdentifierCString(),
8953 aClass->getClassName());
8954 result = kOSReturnSuccess;
8955 goto finish;
8956 }
8957
8958 if (!metaClasses->setObject(aClass)) {
8959 goto finish;
8960 } else {
8961 OSKextLog(this,
8962 kOSKextLogDetailLevel |
8963 kOSKextLogLoadFlag,
8964 "Kext %s registered class %s.",
8965 getIdentifierCString(),
8966 aClass->getClassName());
8967 }
8968
8969 if (!flags.autounloadEnabled) {
8970 const OSMetaClass * metaScan = NULL; // do not release
8971
8972 for (metaScan = aClass; metaScan; metaScan = metaScan->getSuperClass()) {
8973 if (metaScan == OSTypeID(IOService)) {
8974 OSKextLog(this,
8975 kOSKextLogProgressLevel |
8976 kOSKextLogLoadFlag,
8977 "Kext %s has IOService subclass %s; enabling autounload.",
8978 getIdentifierCString(),
8979 aClass->getClassName());
8980
8981 flags.autounloadEnabled = 1;
8982 break;
8983 }
8984 }
8985 }
8986
8987 notifyAddClassObservers(this, aClass, flags);
8988
8989 result = kOSReturnSuccess;
8990
8991 finish:
8992 if (result != kOSReturnSuccess) {
8993 OSKextLog(this,
8994 kOSKextLogErrorLevel |
8995 kOSKextLogLoadFlag,
8996 "Kext %s failed to register class %s.",
8997 getIdentifierCString(),
8998 aClass->getClassName());
8999 }
9000
9001 return result;
9002 }
9003
9004 /*********************************************************************
9005 *********************************************************************/
9006 OSReturn
9007 OSKext::removeClass(
9008 OSMetaClass * aClass)
9009 {
9010 OSReturn result = kOSMetaClassNoKModSet;
9011
9012 if (!metaClasses) {
9013 goto finish;
9014 }
9015
9016 if (!metaClasses->containsObject(aClass)) {
9017 OSKextLog(this,
9018 kOSKextLogWarningLevel |
9019 kOSKextLogLoadFlag,
9020 "Notice - kext %s asked to unregister unknown class %s.",
9021 getIdentifierCString(),
9022 aClass->getClassName());
9023 result = kOSReturnSuccess;
9024 goto finish;
9025 }
9026
9027 OSKextLog(this,
9028 kOSKextLogDetailLevel |
9029 kOSKextLogLoadFlag,
9030 "Kext %s unregistering class %s.",
9031 getIdentifierCString(),
9032 aClass->getClassName());
9033
9034 metaClasses->removeObject(aClass);
9035
9036 notifyRemoveClassObservers(this, aClass, flags);
9037
9038 result = kOSReturnSuccess;
9039
9040 finish:
9041 if (result != kOSReturnSuccess) {
9042 OSKextLog(this,
9043 kOSKextLogErrorLevel |
9044 kOSKextLogLoadFlag,
9045 "Failed to unregister kext %s class %s.",
9046 getIdentifierCString(),
9047 aClass->getClassName());
9048 }
9049 return result;
9050 }
9051
9052 /*********************************************************************
9053 *********************************************************************/
9054 OSSet *
9055 OSKext::getMetaClasses(void)
9056 {
9057 return metaClasses.get();
9058 }
9059
9060 /*********************************************************************
9061 *********************************************************************/
9062 bool
9063 OSKext::hasOSMetaClassInstances(void)
9064 {
9065 bool result = false;
9066 OSSharedPtr<OSCollectionIterator> classIterator;
9067 OSMetaClass * checkClass = NULL; // do not release
9068
9069 if (!metaClasses) {
9070 goto finish;
9071 }
9072
9073 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9074 if (!classIterator) {
9075 // xxx - log alloc failure?
9076 goto finish;
9077 }
9078 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9079 if (checkClass->getInstanceCount()) {
9080 result = true;
9081 goto finish;
9082 }
9083 }
9084
9085 finish:
9086 return result;
9087 }
9088
9089 /*********************************************************************
9090 *********************************************************************/
9091 /* static */
9092 void
9093 OSKext::reportOSMetaClassInstances(
9094 const char * kextIdentifier,
9095 OSKextLogSpec msgLogSpec)
9096 {
9097 OSSharedPtr<OSKext> theKext;
9098
9099 theKext = OSKext::lookupKextWithIdentifier(kextIdentifier);
9100 if (!theKext) {
9101 goto finish;
9102 }
9103
9104 theKext->reportOSMetaClassInstances(msgLogSpec);
9105 finish:
9106 return;
9107 }
9108
9109 /*********************************************************************
9110 *********************************************************************/
9111 void
9112 OSKext::reportOSMetaClassInstances(OSKextLogSpec msgLogSpec)
9113 {
9114 OSSharedPtr<OSCollectionIterator> classIterator;
9115 OSMetaClass * checkClass = NULL; // do not release
9116
9117 if (!metaClasses) {
9118 goto finish;
9119 }
9120
9121 classIterator = OSCollectionIterator::withCollection(metaClasses.get());
9122 if (!classIterator) {
9123 goto finish;
9124 }
9125 while ((checkClass = (OSMetaClass *)classIterator->getNextObject())) {
9126 if (checkClass->getInstanceCount()) {
9127 OSKextLog(this,
9128 msgLogSpec,
9129 " Kext %s class %s has %d instance%s.",
9130 getIdentifierCString(),
9131 checkClass->getClassName(),
9132 checkClass->getInstanceCount(),
9133 checkClass->getInstanceCount() == 1 ? "" : "s");
9134 }
9135 }
9136
9137 finish:
9138 return;
9139 }
9140
9141 #if PRAGMA_MARK
9142 #pragma mark User-Space Requests
9143 #endif
9144
9145 static kern_return_t
9146 patchDextLaunchRequests(task_t calling_task, OSArray *requests)
9147 {
9148 OSReturn result = kOSReturnSuccess;
9149 for (uint32_t requestIndex = 0; requestIndex < requests->getCount(); requestIndex++) {
9150 OSDictionary * request = NULL; //do not release
9151 IOUserServerCheckInToken * token = NULL; //do not release
9152 OSString * requestPredicate = NULL; //do not release
9153 OSSharedPtr<OSNumber> portNameNumber;
9154 mach_port_name_t portName = 0;
9155 request = OSDynamicCast(OSDictionary, requests->getObject(requestIndex));
9156 if (!request) {
9157 OSKextLog(/* kext */ NULL,
9158 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9159 "Elements of request should be of type OSDictionary");
9160 result = kOSKextReturnInternalError;
9161 goto finish;
9162 }
9163 requestPredicate = _OSKextGetRequestPredicate(request);
9164 if (!requestPredicate) {
9165 OSKextLog(/* kext */ NULL,
9166 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9167 "Failed to get request predicate");
9168 result = kOSKextReturnInternalError;
9169 goto finish;
9170 }
9171 // is this a dext launch?
9172 if (requestPredicate->isEqualTo(kKextRequestPredicateRequestDaemonLaunch)) {
9173 token = OSDynamicCast(IOUserServerCheckInToken, _OSKextGetRequestArgument(request, kKextRequestArgumentCheckInToken));
9174 if (!token) {
9175 OSKextLog(/* kext */ NULL,
9176 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9177 "Could not find a IOUserServerCheckInToken in daemon launch request.");
9178 result = kOSKextReturnInternalError;
9179 goto finish;
9180 }
9181 portName = iokit_make_send_right(calling_task, token, IKOT_IOKIT_IDENT);
9182 if (portName == 0 || portName == MACH_PORT_DEAD) {
9183 OSKextLog(/* kext */ NULL,
9184 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9185 "Could not create send right for object.");
9186 result = kOSKextReturnInternalError;
9187 goto finish;
9188 }
9189 // Store the mach port name as a OSNumber
9190 portNameNumber = OSNumber::withNumber(portName, CHAR_BIT * sizeof(portName));
9191 if (!portNameNumber) {
9192 OSKextLog(/* kext */ NULL,
9193 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9194 "Could not create OSNumber object.");
9195 result = kOSKextReturnNoMemory;
9196 goto finish;
9197 }
9198 if (!_OSKextSetRequestArgument(request, kKextRequestArgumentCheckInToken, portNameNumber.get())) {
9199 OSKextLog(/* kext */ NULL,
9200 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9201 "Could not set OSNumber object as request " kKextRequestArgumentCheckInToken);
9202 result = kOSKextReturnNoMemory;
9203 goto finish;
9204 }
9205 }
9206 finish:
9207 if (result != kOSReturnSuccess) {
9208 break;
9209 }
9210 }
9211 return result;
9212 }
9213
9214 /*********************************************************************
9215 * XXX - this function is a big ugly mess
9216 *********************************************************************/
9217 /* static */
9218 OSReturn
9219 OSKext::handleRequest(
9220 host_priv_t hostPriv,
9221 OSKextLogSpec clientLogFilter,
9222 char * requestBuffer,
9223 uint32_t requestLength,
9224 char ** responseOut,
9225 uint32_t * responseLengthOut,
9226 char ** logInfoOut,
9227 uint32_t * logInfoLengthOut)
9228 {
9229 OSReturn result = kOSReturnError;
9230 kern_return_t kmem_result = KERN_FAILURE;
9231
9232 char * response = NULL; // returned by reference
9233 uint32_t responseLength = 0;
9234
9235 bool taskCanManageAllKCs = false;
9236 bool taskOnlyManagesBootKC = false;
9237
9238 OSSharedPtr<OSObject> parsedXML;
9239 OSDictionary * requestDict = NULL; // do not release
9240 OSSharedPtr<OSString> errorString;
9241
9242 OSSharedPtr<OSObject> responseObject;
9243
9244 OSSharedPtr<OSSerialize> serializer;
9245
9246 OSSharedPtr<OSArray> logInfoArray;
9247
9248 OSString * predicate = NULL; // do not release
9249 OSString * kextIdentifier = NULL; // do not release
9250 OSArray * kextIdentifiers = NULL; // do not release
9251 OSKext * theKext = NULL; // do not release
9252 OSBoolean * boolArg = NULL; // do not release
9253
9254 IORecursiveLockLock(sKextLock);
9255
9256 if (responseOut) {
9257 *responseOut = NULL;
9258 *responseLengthOut = 0;
9259 }
9260 if (logInfoOut) {
9261 *logInfoOut = NULL;
9262 *logInfoLengthOut = 0;
9263 }
9264
9265 OSKext::setUserSpaceLogFilter(clientLogFilter, logInfoOut ? true : false);
9266
9267 /* XML must be nul-terminated.
9268 */
9269 if (requestBuffer[requestLength - 1] != '\0') {
9270 OSKextLog(/* kext */ NULL,
9271 kOSKextLogErrorLevel |
9272 kOSKextLogIPCFlag,
9273 "Invalid request from user space (not nul-terminated).");
9274 result = kOSKextReturnBadData;
9275 goto finish;
9276 }
9277 parsedXML = OSUnserializeXML((const char *)requestBuffer, errorString);
9278 if (parsedXML) {
9279 requestDict = OSDynamicCast(OSDictionary, parsedXML.get());
9280 }
9281 if (!requestDict) {
9282 const char * errorCString = "(unknown error)";
9283
9284 if (errorString && errorString->getCStringNoCopy()) {
9285 errorCString = errorString->getCStringNoCopy();
9286 } else if (parsedXML) {
9287 errorCString = "not a dictionary";
9288 }
9289 OSKextLog(/* kext */ NULL,
9290 kOSKextLogErrorLevel |
9291 kOSKextLogIPCFlag,
9292 "Error unserializing request from user space: %s.",
9293 errorCString);
9294 result = kOSKextReturnSerialization;
9295 goto finish;
9296 }
9297
9298 predicate = _OSKextGetRequestPredicate(requestDict);
9299 if (!predicate) {
9300 OSKextLog(/* kext */ NULL,
9301 kOSKextLogErrorLevel |
9302 kOSKextLogIPCFlag,
9303 "Recieved kext request from user space with no predicate.");
9304 result = kOSKextReturnInvalidArgument;
9305 goto finish;
9306 }
9307
9308 OSKextLog(/* kext */ NULL,
9309 kOSKextLogDebugLevel |
9310 kOSKextLogIPCFlag,
9311 "Received '%s' request from user space.",
9312 predicate->getCStringNoCopy());
9313
9314 /*
9315 * All management of file sets requires an entitlement
9316 */
9317 result = kOSKextReturnNotPrivileged;
9318 if (predicate->isEqualTo(kKextRequestPredicateUnload) ||
9319 predicate->isEqualTo(kKextRequestPredicateStart) ||
9320 predicate->isEqualTo(kKextRequestPredicateStop) ||
9321 predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9322 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9323 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9324 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9325 predicate->isEqualTo(kKextRequestPredicateLoadFromKC) ||
9326 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9327 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9328 predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9329 if (hostPriv == HOST_PRIV_NULL) {
9330 OSKextLog(/* kext */ NULL,
9331 kOSKextLogErrorLevel |
9332 kOSKextLogIPCFlag,
9333 "Access Failure - must be root user.");
9334 goto finish;
9335 }
9336 taskCanManageAllKCs = IOTaskHasEntitlement(current_task(), kOSKextCollectionManagementEntitlement) == TRUE;
9337 taskOnlyManagesBootKC = IOTaskHasEntitlement(current_task(), kOSKextOnlyBootKCManagementEntitlement) == TRUE;
9338
9339 if (!taskCanManageAllKCs && !taskOnlyManagesBootKC) {
9340 OSKextLog(/* kext */ NULL,
9341 kOSKextLogErrorLevel |
9342 kOSKextLogIPCFlag,
9343 "Access Failure - client not entitled to manage file sets.");
9344 goto finish;
9345 }
9346
9347 /*
9348 * The OnlyBootKC entitlement restricts the
9349 * collection-management entitlement to only managing kexts in
9350 * the BootKC. All other predicates that alter global state or
9351 * add new KCs are disallowed.
9352 */
9353 if (taskOnlyManagesBootKC &&
9354 (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests) ||
9355 predicate->isEqualTo(kKextRequestPredicateSendResource) ||
9356 predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC) ||
9357 predicate->isEqualTo(kKextRequestPredicateLoadCodeless) ||
9358 predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles) ||
9359 predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable) ||
9360 predicate->isEqualTo(kKextRequestPredicateDaemonReady))) {
9361 OSKextLog(/* kext */ NULL,
9362 kOSKextLogErrorLevel |
9363 kOSKextLogIPCFlag,
9364 "Access Failure - client not entitled to manage non-primary KCs");
9365 goto finish;
9366 }
9367
9368 /*
9369 * If we get here, then the process either has the full KC
9370 * management entitlement, or it has the BootKC-only
9371 * entitlement and the request is about the BootKC.
9372 */
9373 }
9374
9375 /* Get common args in anticipation of use.
9376 */
9377 kextIdentifier = OSDynamicCast(OSString, _OSKextGetRequestArgument(
9378 requestDict, kKextRequestArgumentBundleIdentifierKey));
9379 kextIdentifiers = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
9380 requestDict, kKextRequestArgumentBundleIdentifierKey));
9381 if (kextIdentifier) {
9382 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextIdentifier));
9383 }
9384 boolArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
9385 requestDict, kKextRequestArgumentValueKey));
9386
9387 if (taskOnlyManagesBootKC &&
9388 theKext &&
9389 theKext->isInFileset() &&
9390 theKext->kc_type != KCKindPrimary) {
9391 OSKextLog(/* kext */ NULL,
9392 kOSKextLogErrorLevel |
9393 kOSKextLogIPCFlag,
9394 "Access Failure - client not entitled to manage kext in non-primary KC");
9395 result = kOSKextReturnNotPrivileged;
9396 goto finish;
9397 }
9398
9399 result = kOSKextReturnInvalidArgument;
9400
9401 if (predicate->isEqualTo(kKextRequestPredicateStart)) {
9402 if (!kextIdentifier) {
9403 OSKextLog(/* kext */ NULL,
9404 kOSKextLogErrorLevel |
9405 kOSKextLogIPCFlag,
9406 "Invalid arguments to kext start request.");
9407 } else if (!theKext) {
9408 OSKextLog(/* kext */ NULL,
9409 kOSKextLogErrorLevel |
9410 kOSKextLogIPCFlag,
9411 "Kext %s not found for start request.",
9412 kextIdentifier->getCStringNoCopy());
9413 result = kOSKextReturnNotFound;
9414 } else {
9415 result = theKext->start();
9416 }
9417 } else if (predicate->isEqualTo(kKextRequestPredicateStop)) {
9418 if (!kextIdentifier) {
9419 OSKextLog(/* kext */ NULL,
9420 kOSKextLogErrorLevel |
9421 kOSKextLogIPCFlag,
9422 "Invalid arguments to kext stop request.");
9423 } else if (!theKext) {
9424 OSKextLog(/* kext */ NULL,
9425 kOSKextLogErrorLevel |
9426 kOSKextLogIPCFlag,
9427 "Kext %s not found for stop request.",
9428 kextIdentifier->getCStringNoCopy());
9429 result = kOSKextReturnNotFound;
9430 } else {
9431 result = theKext->stop();
9432 }
9433 } else if (predicate->isEqualTo(kKextRequestPredicateMissingAuxKCBundles)) {
9434 result = OSKext::setMissingAuxKCBundles(requestDict);
9435 } else if (predicate->isEqualTo(kKextRequestPredicateAuxKCBundleAvailable)) {
9436 if (!kextIdentifier) {
9437 OSKextLog(/* kext */ NULL,
9438 kOSKextLogErrorLevel |
9439 kOSKextLogIPCFlag,
9440 "Invalid arguments to AuxKC Bundle Available request.");
9441 } else {
9442 result = OSKext::setAuxKCBundleAvailable(kextIdentifier, requestDict);
9443 }
9444 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFromKC)) {
9445 if (!kextIdentifier) {
9446 OSKextLog(/* kext */ NULL,
9447 kOSKextLogErrorLevel |
9448 kOSKextLogIPCFlag,
9449 "Invalid arguments to kext load from KC request.");
9450 } else if (!theKext) {
9451 OSKextLog(/* kext */ NULL,
9452 kOSKextLogErrorLevel |
9453 kOSKextLogIPCFlag,
9454 "Kext %s not found for load from KC request.",
9455 kextIdentifier->getCStringNoCopy());
9456 result = kOSKextReturnNotFound;
9457 } else if (!theKext->isInFileset()) {
9458 OSKextLog(/* kext */ NULL,
9459 kOSKextLogErrorLevel |
9460 kOSKextLogIPCFlag,
9461 "Kext %s does not exist in a KC: refusing to load.",
9462 kextIdentifier->getCStringNoCopy());
9463 result = kOSKextReturnNotLoadable;
9464 } else {
9465 result = OSKext::loadKextFromKC(theKext, requestDict);
9466 }
9467 } else if (predicate->isEqualTo(kKextRequestPredicateLoadCodeless)) {
9468 if (!kextIdentifier) {
9469 OSKextLog(/* kext */ NULL,
9470 kOSKextLogErrorLevel |
9471 kOSKextLogIPCFlag,
9472 "Invalid arguments to codeless kext load interface (missing identifier).");
9473 } else {
9474 result = OSKext::loadCodelessKext(kextIdentifier, requestDict);
9475 }
9476 } else if (predicate->isEqualTo(kKextRequestPredicateUnload)) {
9477 if (!kextIdentifier) {
9478 OSKextLog(/* kext */ NULL,
9479 kOSKextLogErrorLevel |
9480 kOSKextLogIPCFlag,
9481 "Invalid arguments to kext unload request.");
9482 } else if (!theKext) {
9483 OSKextLog(/* kext */ NULL,
9484 kOSKextLogErrorLevel |
9485 kOSKextLogIPCFlag,
9486 "Kext %s not found for unload request.",
9487 kextIdentifier->getCStringNoCopy());
9488 result = kOSKextReturnNotFound;
9489 } else {
9490 OSBoolean * terminateFlag = OSDynamicCast(OSBoolean,
9491 _OSKextGetRequestArgument(requestDict,
9492 kKextRequestArgumentTerminateIOServicesKey));
9493 result = OSKext::removeKext(theKext, terminateFlag == kOSBooleanTrue);
9494 }
9495 } else if (predicate->isEqualTo(kKextRequestPredicateSendResource)) {
9496 result = OSKext::dispatchResource(requestDict);
9497 } else if (predicate->isEqualTo(kKextRequestPredicateGetUUIDByAddress)) {
9498 OSNumber *lookupNum = NULL;
9499 lookupNum = OSDynamicCast(OSNumber,
9500 _OSKextGetRequestArgument(requestDict,
9501 kKextRequestArgumentLookupAddressKey));
9502
9503 responseObject = OSKext::copyKextUUIDForAddress(lookupNum);
9504 if (responseObject) {
9505 result = kOSReturnSuccess;
9506 } else {
9507 goto finish;
9508 }
9509 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoaded) ||
9510 predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID) ||
9511 predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9512 OSBoolean * delayAutounloadBool = NULL;
9513 OSObject * infoKeysRaw = NULL;
9514 OSArray * infoKeys = NULL;
9515 uint32_t infoKeysCount = 0;
9516
9517 delayAutounloadBool = OSDynamicCast(OSBoolean,
9518 _OSKextGetRequestArgument(requestDict,
9519 kKextRequestArgumentDelayAutounloadKey));
9520
9521 /* If asked to delay autounload, reset the timer if it's currently set.
9522 * (That is, don't schedule an unload if one isn't already pending.
9523 */
9524 if (delayAutounloadBool == kOSBooleanTrue) {
9525 OSKext::considerUnloads(/* rescheduleOnly? */ true);
9526 }
9527
9528 infoKeysRaw = _OSKextGetRequestArgument(requestDict,
9529 kKextRequestArgumentInfoKeysKey);
9530 infoKeys = OSDynamicCast(OSArray, infoKeysRaw);
9531 if (infoKeysRaw && !infoKeys) {
9532 OSKextLog(/* kext */ NULL,
9533 kOSKextLogErrorLevel |
9534 kOSKextLogIPCFlag,
9535 "Invalid arguments to kext info request.");
9536 goto finish;
9537 }
9538
9539 if (infoKeys) {
9540 infoKeysCount = infoKeys->getCount();
9541 for (uint32_t i = 0; i < infoKeysCount; i++) {
9542 if (!OSDynamicCast(OSString, infoKeys->getObject(i))) {
9543 OSKextLog(/* kext */ NULL,
9544 kOSKextLogErrorLevel |
9545 kOSKextLogIPCFlag,
9546 "Invalid arguments to kext info request.");
9547 goto finish;
9548 }
9549 }
9550 }
9551
9552 if (predicate->isEqualTo(kKextRequestPredicateGetLoaded)) {
9553 responseObject = OSKext::copyLoadedKextInfo(kextIdentifiers, infoKeys);
9554 } else if (predicate->isEqualTo(kKextRequestPredicateGetLoadedByUUID)) {
9555 responseObject = OSKext::copyLoadedKextInfoByUUID(kextIdentifiers, infoKeys);
9556 } else if (predicate->isEqualTo(kKextRequestPredicateGetKextsInCollection)) {
9557 responseObject = OSKext::copyKextCollectionInfo(requestDict, infoKeys);
9558 }
9559
9560 if (!responseObject) {
9561 result = kOSKextReturnInternalError;
9562 } else {
9563 OSKextLog(/* kext */ NULL,
9564 kOSKextLogDebugLevel |
9565 kOSKextLogIPCFlag,
9566 "Returning loaded kext info.");
9567 result = kOSReturnSuccess;
9568 }
9569 } else if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9570 /* Hand the current sKernelRequests array to the caller
9571 * (who must release it), and make a new one.
9572 */
9573 responseObject = os::move(sKernelRequests);
9574 sKernelRequests = OSArray::withCapacity(0);
9575 sPostedKextLoadIdentifiers->flushCollection();
9576 OSKextLog(/* kext */ NULL,
9577 kOSKextLogDebugLevel |
9578 kOSKextLogIPCFlag,
9579 "Returning kernel requests.");
9580 result = kOSReturnSuccess;
9581 } else if (predicate->isEqualTo(kKextRequestPredicateGetAllLoadRequests)) {
9582 /* Return the set of all requested bundle identifiers */
9583 responseObject = sAllKextLoadIdentifiers;
9584 OSKextLog(/* kext */ NULL,
9585 kOSKextLogDebugLevel |
9586 kOSKextLogIPCFlag,
9587 "Returning load requests.");
9588 result = kOSReturnSuccess;
9589 } else if (predicate->isEqualTo(kKextRequestPredicateLoadFileSetKC)) {
9590 printf("KextLog: Loading FileSet KC(s)\n");
9591 result = OSKext::loadFileSetKexts(requestDict);
9592 } else if (predicate->isEqualTo(kKextRequestPredicateDaemonReady)) {
9593 printf("KextLog: " kIOKitDaemonName " is %s\n", sIOKitDaemonActive ? "active" : "not active");
9594 result = (sIOKitDaemonActive && !sOSKextWasResetAfterUserspaceReboot) ? kOSReturnSuccess : kIOReturnNotReady;
9595 } else {
9596 OSKextLog(/* kext */ NULL,
9597 kOSKextLogDebugLevel |
9598 kOSKextLogIPCFlag,
9599 "Received '%s' invalid request from user space.",
9600 predicate->getCStringNoCopy());
9601 goto finish;
9602 }
9603
9604 /**********
9605 * Now we have handle the request, or not. Gather up the response & logging
9606 * info to ship to user space.
9607 *********/
9608
9609 /* Note: Nothing in OSKext is supposed to retain requestDict,
9610 * but you never know....
9611 */
9612 if (requestDict->getRetainCount() > 1) {
9613 OSKextLog(/* kext */ NULL,
9614 kOSKextLogWarningLevel |
9615 kOSKextLogIPCFlag,
9616 "Request from user space still retained by a kext; "
9617 "probable memory leak.");
9618 }
9619
9620 if (responseOut && responseObject) {
9621 serializer = OSSerialize::withCapacity(0);
9622 if (!serializer) {
9623 result = kOSKextReturnNoMemory;
9624 goto finish;
9625 }
9626 /*
9627 * Before serializing the kernel requests, patch the dext launch requests so
9628 * that the value for kKextRequestArgumentCheckInToken is a mach port name for the
9629 * IOUserServerCheckInToken kernel object.
9630 */
9631 if (predicate->isEqualTo(kKextRequestPredicateGetKernelRequests)) {
9632 OSArray * requests = OSDynamicCast(OSArray, responseObject.get());
9633 task_t calling_task = current_task();
9634 if (!requests) {
9635 OSKextLog(/* kext */ NULL,
9636 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9637 "responseObject should be an OSArray if predicate is " kKextRequestPredicateGetKernelRequests);
9638 result = kOSKextReturnInternalError;
9639 goto finish;
9640 }
9641 result = patchDextLaunchRequests(calling_task, requests);
9642 if (result != kOSReturnSuccess) {
9643 OSKextLog(/* kext */ NULL,
9644 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9645 "Failed to patch dext launch requests.");
9646 goto finish;
9647 }
9648 }
9649
9650 if (!responseObject->serialize(serializer.get())) {
9651 OSKextLog(/* kext */ NULL,
9652 kOSKextLogGeneralFlag | kOSKextLogErrorLevel,
9653 "Failed to serialize response to request from user space.");
9654 result = kOSKextReturnSerialization;
9655 goto finish;
9656 }
9657
9658 response = (char *)serializer->text();
9659 responseLength = serializer->getLength();
9660 }
9661
9662 if (responseOut && response) {
9663 char * buffer;
9664
9665 /* This kmem_alloc sets the return value of the function.
9666 */
9667 kmem_result = kmem_alloc(kernel_map, (vm_offset_t *)&buffer,
9668 round_page(responseLength), VM_KERN_MEMORY_OSKEXT);
9669 if (kmem_result != KERN_SUCCESS) {
9670 OSKextLog(/* kext */ NULL,
9671 kOSKextLogErrorLevel |
9672 kOSKextLogIPCFlag,
9673 "Failed to copy response to request from user space.");
9674 result = kmem_result;
9675 goto finish;
9676 } else {
9677 /* 11981737 - clear uninitialized data in last page */
9678 bzero((void *)(buffer + responseLength),
9679 (round_page(responseLength) - responseLength));
9680 memcpy(buffer, response, responseLength);
9681 *responseOut = buffer;
9682 *responseLengthOut = responseLength;
9683 }
9684 }
9685
9686 finish:
9687
9688 /* Gather up the collected log messages for user space. Any messages
9689 * messages past this call will not make it up as log messages but
9690 * will be in the system log. Note that we ignore the return of the
9691 * serialize; it has no bearing on the operation at hand even if we
9692 * fail to get the log messages.
9693 */
9694 logInfoArray = OSKext::clearUserSpaceLogFilter();
9695
9696 if (logInfoArray && logInfoOut && logInfoLengthOut) {
9697 (void)OSKext::serializeLogInfo(logInfoArray.get(),
9698 logInfoOut, logInfoLengthOut);
9699 }
9700
9701 IORecursiveLockUnlock(sKextLock);
9702
9703 return result;
9704 }
9705
9706 #if PRAGMA_MARK
9707 #pragma mark Linked Kext Collection Support
9708 #endif
9709
9710 static int
9711 __whereIsAddr(vm_offset_t theAddr, unsigned long *segSizes, vm_offset_t *segAddrs, int segCount)
9712 {
9713 for (int i = 0; i < segCount; i++) {
9714 vm_offset_t segStart = segAddrs[i];
9715 vm_offset_t segEnd = segStart + (vm_offset_t)segSizes[i];
9716
9717 if (theAddr >= segStart && theAddr < segEnd) {
9718 return i;
9719 }
9720 }
9721 return -1;
9722 }
9723
9724 static void
9725 __slideOldKaslrOffsets(kernel_mach_header_t *mh,
9726 kernel_segment_command_t *kextTextSeg,
9727 OSData *kaslrOffsets)
9728 {
9729 static const char *plk_segNames[] = {
9730 "__TEXT",
9731 "__TEXT_EXEC",
9732 "__DATA",
9733 "__DATA_CONST",
9734 "__LINKEDIT",
9735 "__PRELINK_TEXT",
9736 "__PLK_TEXT_EXEC",
9737 "__PRELINK_DATA",
9738 "__PLK_DATA_CONST",
9739 "__PLK_LLVM_COV",
9740 "__PLK_LINKEDIT",
9741 "__PRELINK_INFO"
9742 };
9743 static const size_t num_plk_seg = (size_t)(sizeof(plk_segNames) / sizeof(plk_segNames[0]));
9744
9745 unsigned long plk_segSizes[num_plk_seg];
9746 vm_offset_t plk_segAddrs[num_plk_seg];
9747
9748 for (size_t i = 0; i < num_plk_seg; i++) {
9749 plk_segSizes[i] = 0;
9750 plk_segAddrs[i] = (vm_offset_t)getsegdatafromheader(mh, plk_segNames[i], &plk_segSizes[i]);
9751 }
9752
9753 uint64_t kextTextStart = (uint64_t)kextTextSeg->vmaddr;
9754
9755 int slidKextAddrCount = 0;
9756 int badSlideAddr = 0;
9757 int badSlideTarget = 0;
9758
9759 struct kaslrPackedOffsets {
9760 uint32_t count; /* number of offsets */
9761 uint32_t offsetsArray[]; /* offsets to slide */
9762 };
9763 const struct kaslrPackedOffsets *myOffsets = NULL;
9764 myOffsets = (const struct kaslrPackedOffsets *)kaslrOffsets->getBytesNoCopy();
9765
9766 for (uint32_t j = 0; j < myOffsets->count; j++) {
9767 uint64_t slideOffset = (uint64_t)myOffsets->offsetsArray[j];
9768 vm_offset_t *slideAddr = (vm_offset_t *)((uint64_t)kextTextStart + slideOffset);
9769 int slideAddrSegIndex = -1;
9770 int addrToSlideSegIndex = -1;
9771
9772 slideAddrSegIndex = __whereIsAddr((vm_offset_t)slideAddr, &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9773 if (slideAddrSegIndex >= 0) {
9774 addrToSlideSegIndex = __whereIsAddr(ml_static_slide(*slideAddr), &plk_segSizes[0], &plk_segAddrs[0], num_plk_seg);
9775 if (addrToSlideSegIndex < 0) {
9776 badSlideTarget++;
9777 continue;
9778 }
9779 } else {
9780 badSlideAddr++;
9781 continue;
9782 }
9783
9784 slidKextAddrCount++;
9785 *slideAddr = ml_static_slide(*slideAddr);
9786 } // for ...
9787 }
9788
9789
9790
9791 /********************************************************************
9792 * addKextsFromKextCollection
9793 *
9794 * Input: MachO header of kext collection. The MachO is assumed to
9795 * have a section named 'info_seg_name,info_sect_name' that
9796 * contains a serialized XML info dictionary. This dictionary
9797 * contains a UUID, possibly a set of relocations (for older
9798 * kxld-built binaries), and an array of kext personalities.
9799 *
9800 ********************************************************************/
9801 bool
9802 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9803 OSDictionary *infoDict, const char *text_seg_name,
9804 OSData **kcUUID, kc_kind_t type)
9805 {
9806 bool result = false;
9807
9808 OSArray *kextArray = NULL; // do not release
9809 OSData *infoDictKCUUID = NULL; // do not release
9810 OSData *kaslrOffsets = NULL; // do not release
9811
9812 IORegistryEntry *registryRoot = NULL; // do not release
9813 OSSharedPtr<OSNumber> kcKextCount;
9814
9815 /* extract the KC UUID from the dictionary */
9816 infoDictKCUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9817 if (infoDictKCUUID) {
9818 if (infoDictKCUUID->getLength() != sizeof(uuid_t)) {
9819 panic("kcUUID length is %d, expected %lu",
9820 infoDictKCUUID->getLength(), sizeof(uuid_t));
9821 }
9822 }
9823
9824 /* locate the array of kext dictionaries */
9825 kextArray = OSDynamicCast(OSArray, infoDict->getObject(kPrelinkInfoDictionaryKey));
9826 if (!kextArray) {
9827 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9828 "The given KC has no kext info dictionaries");
9829 goto finish;
9830 }
9831
9832 /*
9833 * old-style KASLR offsets may be present in the info dictionary. If
9834 * we find them, use them and eventually slide them.
9835 */
9836 kaslrOffsets = OSDynamicCast(OSData, infoDict->getObject(kPrelinkLinkKASLROffsetsKey));
9837
9838 /*
9839 * Before processing any kexts, locate the special kext bundle which
9840 * contains a list of kexts that we are to prevent from loading.
9841 */
9842 createExcludeListFromPrelinkInfo(kextArray);
9843
9844 /*
9845 * Create OSKext objects for each kext we find in the array of kext
9846 * info plist dictionaries.
9847 */
9848 for (int i = 0; i < (int)kextArray->getCount(); ++i) {
9849 OSDictionary *kextDict = NULL;
9850 kextDict = OSDynamicCast(OSDictionary, kextArray->getObject(i));
9851 if (!kextDict) {
9852 OSKextLog(/* kext */ NULL,
9853 kOSKextLogErrorLevel |
9854 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9855 "Kext info dictionary for kext #%d isn't a dictionary?", i);
9856 continue;
9857 }
9858
9859 /*
9860 * Create the kext for the entry, then release it, because the
9861 * kext system keeps a reference around until the kext is
9862 * explicitly removed. Any creation/registration failures are
9863 * already logged for us.
9864 */
9865 withPrelinkedInfoDict(kextDict, (kaslrOffsets ? TRUE : FALSE), type);
9866 }
9867
9868 /*
9869 * slide old-style kxld relocations
9870 * NOTE: this is still used on embedded KCs built with kcgen
9871 * TODO: Remove this once we use the new kext linker everywhere!
9872 */
9873 if (kaslrOffsets && vm_kernel_slide > 0) {
9874 kernel_segment_command_t *text_segment = NULL;
9875 text_segment = getsegbynamefromheader(mh, text_seg_name);
9876 if (!text_segment) {
9877 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9878 "Can't find a TEXT segment named '%s' in macho header", text_seg_name);
9879 goto finish;
9880 }
9881
9882 __slideOldKaslrOffsets(mh, text_segment, kaslrOffsets);
9883 /* All kexts covered by the old-style kaslr relocation list are now slid, set VM protections for them */
9884 setAllVMAttributes();
9885 }
9886
9887 /* Store the number of prelinked kexts in the registry so we can tell
9888 * when the system has been started from a prelinked kernel.
9889 */
9890 registryRoot = IORegistryEntry::getRegistryRoot();
9891 assert(registryRoot);
9892
9893 kcKextCount = OSNumber::withNumber((unsigned long long)infoDict->getCount(), 8 * sizeof(uint32_t));
9894 assert(kcKextCount);
9895 if (kcKextCount) {
9896 OSSharedPtr<OSObject> prop = registryRoot->copyProperty(kOSPrelinkKextCountKey);
9897 OSNumber *num;
9898 num = OSDynamicCast(OSNumber, prop.get());
9899 if (num) {
9900 kcKextCount->addValue(num->unsigned64BitValue());
9901 }
9902 registryRoot->setProperty(kOSPrelinkKextCountKey, kcKextCount.get());
9903 }
9904
9905 OSKextLog(/* kext */ NULL,
9906 kOSKextLogProgressLevel |
9907 kOSKextLogGeneralFlag | kOSKextLogKextBookkeepingFlag |
9908 kOSKextLogDirectoryScanFlag | kOSKextLogArchiveFlag,
9909 "%u prelinked kexts", infoDict->getCount());
9910
9911
9912 if (kcUUID && infoDictKCUUID) {
9913 *kcUUID = OSData::withData(infoDictKCUUID).detach();
9914 }
9915
9916 result = true;
9917
9918 finish:
9919 return result;
9920 }
9921
9922 bool
9923 OSKext::addKextsFromKextCollection(kernel_mach_header_t *mh,
9924 OSDictionary *infoDict, const char *text_seg_name,
9925 OSSharedPtr<OSData> &kcUUID, kc_kind_t type)
9926 {
9927 OSData *result = NULL;
9928 bool success = addKextsFromKextCollection(mh,
9929 infoDict,
9930 text_seg_name,
9931 &result,
9932 type);
9933 if (success) {
9934 kcUUID.reset(result, OSNoRetain);
9935 }
9936 return success;
9937 }
9938
9939 static OSSharedPtr<OSObject> deferredAuxKCXML;
9940 bool
9941 OSKext::registerDeferredKextCollection(kernel_mach_header_t *mh,
9942 OSSharedPtr<OSObject> &parsedXML, kc_kind_t type)
9943 {
9944 if (type != KCKindAuxiliary) {
9945 return false;
9946 }
9947
9948 kernel_mach_header_t *_mh;
9949 _mh = (kernel_mach_header_t*)PE_get_kc_header(type);
9950 if (!_mh || _mh != mh) {
9951 return false;
9952 }
9953
9954 if (deferredAuxKCXML) {
9955 /* only allow this to be called once */
9956 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9957 "An Aux KC has already been registered for deferred processing.");
9958 return false;
9959 }
9960
9961 OSDictionary *infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
9962 if (!infoDict) {
9963 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9964 "The Aux KC has info dictionary");
9965 return false;
9966 }
9967
9968 OSData *kcUUID = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
9969 if (!kcUUID || kcUUID->getLength() != sizeof(uuid_t)) {
9970 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
9971 "The Aux KC has no UUID in %s", kPrelinkInfoKCIDKey);
9972 return false;
9973 }
9974
9975 /*
9976 * Copy the AuxKC UUID to make sure that the kern.auxiliaryfilesetuuid
9977 * sysctl can return the UUID to user space which will check this
9978 * value for errors.
9979 */
9980 memcpy((void *)&auxkc_uuid, (const void *)kcUUID->getBytesNoCopy(),
9981 kcUUID->getLength());
9982 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
9983 auxkc_uuid_valid = TRUE;
9984
9985 deferredAuxKCXML = parsedXML;
9986
9987 return true;
9988 }
9989
9990 OSSharedPtr<OSObject>
9991 OSKext::consumeDeferredKextCollection(kc_kind_t type)
9992 {
9993 if (type != KCKindAuxiliary || !deferredAuxKCXML) {
9994 return NULL;
9995 }
9996
9997 return os::move(deferredAuxKCXML);
9998 }
9999
10000 #if PRAGMA_MARK
10001 #pragma mark Profile-Guided-Optimization Support
10002 #endif
10003
10004 // #include <InstrProfiling.h>
10005 extern "C" {
10006 uint64_t __llvm_profile_get_size_for_buffer_internal(const char *DataBegin,
10007 const char *DataEnd,
10008 const char *CountersBegin,
10009 const char *CountersEnd,
10010 const char *NamesBegin,
10011 const char *NamesEnd);
10012 int __llvm_profile_write_buffer_internal(char *Buffer,
10013 const char *DataBegin,
10014 const char *DataEnd,
10015 const char *CountersBegin,
10016 const char *CountersEnd,
10017 const char *NamesBegin,
10018 const char *NamesEnd);
10019 }
10020
10021
10022 static
10023 void
10024 OSKextPgoMetadataPut(char *pBuffer,
10025 size_t *position,
10026 size_t bufferSize,
10027 uint32_t *num_pairs,
10028 const char *key,
10029 const char *value)
10030 {
10031 size_t strlen_key = strlen(key);
10032 size_t strlen_value = strlen(value);
10033 size_t len = strlen(key) + 1 + strlen(value) + 1;
10034 char *pos = pBuffer + *position;
10035 *position += len;
10036 if (pBuffer && bufferSize && *position <= bufferSize) {
10037 memcpy(pos, key, strlen_key); pos += strlen_key;
10038 *(pos++) = '=';
10039 memcpy(pos, value, strlen_value); pos += strlen_value;
10040 *(pos++) = 0;
10041 if (num_pairs) {
10042 (*num_pairs)++;
10043 }
10044 }
10045 }
10046
10047
10048 static
10049 void
10050 OSKextPgoMetadataPutMax(size_t *position, const char *key, size_t value_max)
10051 {
10052 *position += strlen(key) + 1 + value_max + 1;
10053 }
10054
10055
10056 static
10057 void
10058 OSKextPgoMetadataPutAll(OSKext *kext,
10059 uuid_t instance_uuid,
10060 char *pBuffer,
10061 size_t *position,
10062 size_t bufferSize,
10063 uint32_t *num_pairs)
10064 {
10065 _static_assert_1_arg(sizeof(clock_sec_t) % 2 == 0);
10066 //log_10 2^16 ≈ 4.82
10067 const size_t max_secs_string_size = 5 * sizeof(clock_sec_t) / 2;
10068 const size_t max_timestamp_string_size = max_secs_string_size + 1 + 6;
10069
10070 if (!pBuffer) {
10071 OSKextPgoMetadataPutMax(position, "INSTANCE", 36);
10072 OSKextPgoMetadataPutMax(position, "UUID", 36);
10073 OSKextPgoMetadataPutMax(position, "TIMESTAMP", max_timestamp_string_size);
10074 } else {
10075 uuid_string_t instance_uuid_string;
10076 uuid_unparse(instance_uuid, instance_uuid_string);
10077 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10078 "INSTANCE", instance_uuid_string);
10079
10080 OSSharedPtr<OSData> uuid_data;
10081 uuid_t uuid;
10082 uuid_string_t uuid_string;
10083 uuid_data = kext->copyUUID();
10084 if (uuid_data) {
10085 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid));
10086 uuid_unparse(uuid, uuid_string);
10087 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10088 "UUID", uuid_string);
10089 }
10090
10091 clock_sec_t secs;
10092 clock_usec_t usecs;
10093 clock_get_calendar_microtime(&secs, &usecs);
10094 assert(usecs < 1000000);
10095 char timestamp[max_timestamp_string_size + 1];
10096 _static_assert_1_arg(sizeof(long) >= sizeof(clock_sec_t));
10097 snprintf(timestamp, sizeof(timestamp), "%lu.%06d", (unsigned long)secs, (int)usecs);
10098 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10099 "TIMESTAMP", timestamp);
10100 }
10101
10102 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10103 "NAME", kext->getIdentifierCString());
10104
10105 char versionCString[kOSKextVersionMaxLength];
10106 OSKextVersionGetString(kext->getVersion(), versionCString, kOSKextVersionMaxLength);
10107 OSKextPgoMetadataPut(pBuffer, position, bufferSize, num_pairs,
10108 "VERSION", versionCString);
10109 }
10110
10111 static
10112 size_t
10113 OSKextPgoMetadataSize(OSKext *kext)
10114 {
10115 size_t position = 0;
10116 uuid_t fakeuuid = {};
10117 OSKextPgoMetadataPutAll(kext, fakeuuid, NULL, &position, 0, NULL);
10118 return position;
10119 }
10120
10121 int
10122 OSKextGrabPgoDataLocked(OSKext *kext,
10123 bool metadata,
10124 uuid_t instance_uuid,
10125 uint64_t *pSize,
10126 char *pBuffer,
10127 uint64_t bufferSize)
10128 {
10129 int err = 0;
10130
10131 kernel_section_t *sect_prf_data = NULL;
10132 kernel_section_t *sect_prf_name = NULL;
10133 kernel_section_t *sect_prf_cnts = NULL;
10134 uint64_t size;
10135 size_t metadata_size = 0;
10136 size_t offset_to_pairs = 0;
10137
10138 sect_prf_data = kext->lookupSection("__DATA", "__llvm_prf_data");
10139 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_names");
10140 if (!sect_prf_name) {
10141 // kextcache sometimes truncates the section name to 15 chars
10142 // <rdar://problem/52080551> 16 character section name is truncated to 15 characters by kextcache
10143 sect_prf_name = kext->lookupSection("__DATA", "__llvm_prf_name");
10144 }
10145 sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10146
10147 if (!sect_prf_data || !sect_prf_name || !sect_prf_cnts) {
10148 err = ENOTSUP;
10149 goto out;
10150 }
10151
10152 size = __llvm_profile_get_size_for_buffer_internal(
10153 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10154 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10155 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10156
10157 if (metadata) {
10158 metadata_size = OSKextPgoMetadataSize(kext);
10159 size += metadata_size;
10160 size += sizeof(pgo_metadata_footer);
10161 }
10162
10163
10164 if (pSize) {
10165 *pSize = size;
10166 }
10167
10168 if (pBuffer && bufferSize) {
10169 if (bufferSize < size) {
10170 err = ERANGE;
10171 goto out;
10172 }
10173
10174 err = __llvm_profile_write_buffer_internal(
10175 pBuffer,
10176 (const char*) sect_prf_data->addr, (const char*) sect_prf_data->addr + sect_prf_data->size,
10177 (const char*) sect_prf_cnts->addr, (const char*) sect_prf_cnts->addr + sect_prf_cnts->size,
10178 (const char*) sect_prf_name->addr, (const char*) sect_prf_name->addr + sect_prf_name->size);
10179
10180 if (err) {
10181 err = EIO;
10182 goto out;
10183 }
10184
10185 if (metadata) {
10186 offset_to_pairs = sizeof(struct pgo_metadata_footer) + metadata_size;
10187 if (offset_to_pairs > UINT32_MAX) {
10188 err = E2BIG;
10189 goto out;
10190 }
10191
10192 char *end_of_buffer = pBuffer + size;
10193 struct pgo_metadata_footer *footerp = (struct pgo_metadata_footer *) (end_of_buffer - sizeof(struct pgo_metadata_footer));
10194 char *metadata_buffer = end_of_buffer - (sizeof(struct pgo_metadata_footer) + metadata_size);
10195
10196 size_t metadata_position = 0;
10197 uint32_t num_pairs = 0;
10198 OSKextPgoMetadataPutAll(kext, instance_uuid, metadata_buffer, &metadata_position, metadata_size, &num_pairs);
10199 while (metadata_position < metadata_size) {
10200 metadata_buffer[metadata_position++] = 0;
10201 }
10202
10203 struct pgo_metadata_footer footer;
10204 footer.magic = htonl(0x6d657461);
10205 footer.number_of_pairs = htonl( num_pairs );
10206 footer.offset_to_pairs = htonl((uint32_t)offset_to_pairs );
10207 memcpy(footerp, &footer, sizeof(footer));
10208 }
10209 }
10210
10211 out:
10212 return err;
10213 }
10214
10215
10216 int
10217 OSKextGrabPgoData(uuid_t uuid,
10218 uint64_t *pSize,
10219 char *pBuffer,
10220 uint64_t bufferSize,
10221 int wait_for_unload,
10222 int metadata)
10223 {
10224 int err = 0;
10225 OSSharedPtr<OSKext> kext;
10226
10227
10228 IORecursiveLockLock(sKextLock);
10229
10230 kext = OSKext::lookupKextWithUUID(uuid);
10231 if (!kext) {
10232 err = ENOENT;
10233 goto out;
10234 }
10235
10236 if (wait_for_unload) {
10237 OSKextGrabPgoStruct s;
10238
10239 s.metadata = metadata;
10240 s.pSize = pSize;
10241 s.pBuffer = pBuffer;
10242 s.bufferSize = bufferSize;
10243 s.err = EINTR;
10244
10245 struct list_head *prev = &kext->pendingPgoHead;
10246 struct list_head *next = kext->pendingPgoHead.next;
10247
10248 s.list_head.prev = prev;
10249 s.list_head.next = next;
10250
10251 prev->next = &s.list_head;
10252 next->prev = &s.list_head;
10253
10254 kext.reset();
10255
10256 IORecursiveLockSleep(sKextLock, &s, THREAD_ABORTSAFE);
10257
10258 prev = s.list_head.prev;
10259 next = s.list_head.next;
10260
10261 prev->next = next;
10262 next->prev = prev;
10263
10264 err = s.err;
10265 } else {
10266 err = OSKextGrabPgoDataLocked(kext.get(), metadata, kext->instance_uuid, pSize, pBuffer, bufferSize);
10267 }
10268
10269 out:
10270
10271 IORecursiveLockUnlock(sKextLock);
10272
10273 return err;
10274 }
10275
10276 void
10277 OSKextResetPgoCountersLock()
10278 {
10279 IORecursiveLockLock(sKextLock);
10280 }
10281
10282 void
10283 OSKextResetPgoCountersUnlock()
10284 {
10285 IORecursiveLockUnlock(sKextLock);
10286 }
10287
10288
10289 extern unsigned int not_in_kdp;
10290
10291 void
10292 OSKextResetPgoCounters()
10293 {
10294 assert(!not_in_kdp);
10295 uint32_t count = sLoadedKexts->getCount();
10296 for (uint32_t i = 0; i < count; i++) {
10297 OSKext *kext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
10298 kernel_section_t *sect_prf_cnts = kext->lookupSection("__DATA", "__llvm_prf_cnts");
10299 if (!sect_prf_cnts) {
10300 continue;
10301 }
10302 memset((void*)sect_prf_cnts->addr, 0, sect_prf_cnts->size);
10303 }
10304 }
10305
10306 OSSharedPtr<OSDictionary>
10307 OSKext::copyLoadedKextInfoByUUID(
10308 OSArray * kextIdentifiers,
10309 OSArray * infoKeys)
10310 {
10311 OSSharedPtr<OSDictionary> result;
10312 OSSharedPtr<OSDictionary> kextInfo;
10313 uint32_t max_count, i, j;
10314 uint32_t idCount = 0;
10315 uint32_t idIndex = 0;
10316 IORecursiveLockLock(sKextLock);
10317 OSArray *list[2] = {sLoadedKexts.get(), sLoadedDriverKitKexts.get()};
10318 uint32_t count[2] = {sLoadedKexts->getCount(), sLoadedDriverKitKexts->getCount()};
10319
10320 #if CONFIG_MACF
10321 /* Is the calling process allowed to query kext info? */
10322 if (current_task() != kernel_task) {
10323 int macCheckResult = 0;
10324 kauth_cred_t cred = NULL;
10325
10326 cred = kauth_cred_get_with_ref();
10327 macCheckResult = mac_kext_check_query(cred);
10328 kauth_cred_unref(&cred);
10329
10330 if (macCheckResult != 0) {
10331 OSKextLog(/* kext */ NULL,
10332 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10333 "Failed to query kext info (MAC policy error 0x%x).",
10334 macCheckResult);
10335 goto finish;
10336 }
10337 }
10338 #endif
10339
10340 /* Empty list of UUIDs is equivalent to no list (get all).
10341 */
10342 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10343 kextIdentifiers = NULL;
10344 } else if (kextIdentifiers) {
10345 idCount = kextIdentifiers->getCount();
10346 }
10347
10348 /* Same for keys.
10349 */
10350 if (infoKeys && !infoKeys->getCount()) {
10351 infoKeys = NULL;
10352 }
10353
10354 max_count = count[0] + count[1];
10355 result = OSDictionary::withCapacity(max_count);
10356 if (!result) {
10357 goto finish;
10358 }
10359
10360 for (j = 0; j < (sizeof(list) / sizeof(list[0])); j++) {
10361 for (i = 0; i < count[j]; i++) {
10362 OSKext *thisKext = NULL; // do not release
10363 Boolean includeThis = true;
10364 uuid_t thisKextUUID;
10365 uuid_t thisKextTextUUID;
10366 OSSharedPtr<OSData> uuid_data;
10367 uuid_string_t uuid_key;
10368
10369 thisKext = OSDynamicCast(OSKext, list[j]->getObject(i));
10370 if (!thisKext) {
10371 continue;
10372 }
10373
10374 uuid_data = thisKext->copyUUID();
10375 if (!uuid_data) {
10376 continue;
10377 }
10378
10379 memcpy(&thisKextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextUUID));
10380
10381 uuid_unparse(thisKextUUID, uuid_key);
10382
10383 uuid_data = thisKext->copyTextUUID();
10384 if (!uuid_data) {
10385 continue;
10386 }
10387 memcpy(&thisKextTextUUID, uuid_data->getBytesNoCopy(), sizeof(thisKextTextUUID));
10388
10389 /* Skip current kext if we have a list of UUIDs and
10390 * it isn't in the list.
10391 */
10392 if (kextIdentifiers) {
10393 includeThis = false;
10394
10395 for (idIndex = 0; idIndex < idCount; idIndex++) {
10396 const OSString* wantedUUID = OSDynamicCast(OSString,
10397 kextIdentifiers->getObject(idIndex));
10398
10399 uuid_t uuid;
10400 uuid_parse(wantedUUID->getCStringNoCopy(), uuid);
10401
10402 if ((0 == uuid_compare(uuid, thisKextUUID))
10403 || (0 == uuid_compare(uuid, thisKextTextUUID))) {
10404 includeThis = true;
10405 /* Only need to find the first kext if multiple match,
10406 * ie. asking for the kernel uuid does not need to find
10407 * interface kexts or builtin static kexts.
10408 */
10409 kextIdentifiers->removeObject(idIndex);
10410 uuid_unparse(uuid, uuid_key);
10411 break;
10412 }
10413 }
10414 }
10415
10416 if (!includeThis) {
10417 continue;
10418 }
10419
10420 kextInfo = thisKext->copyInfo(infoKeys);
10421 if (kextInfo) {
10422 result->setObject(uuid_key, kextInfo.get());
10423 }
10424
10425 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10426 goto finish;
10427 }
10428 }
10429 }
10430
10431 finish:
10432 IORecursiveLockUnlock(sKextLock);
10433
10434 return result;
10435 }
10436
10437 /*********************************************************************
10438 *********************************************************************/
10439 /* static */
10440 OSSharedPtr<OSDictionary>
10441 OSKext::copyKextCollectionInfo(
10442 OSDictionary *requestDict,
10443 OSArray *infoKeys)
10444 {
10445 OSSharedPtr<OSDictionary> result;
10446 OSString *collectionType = NULL;
10447 OSObject *rawLoadedState = NULL;
10448 OSString *loadedState = NULL;
10449
10450 kc_kind_t kc_request_kind = KCKindUnknown;
10451 bool onlyLoaded = false;
10452 bool onlyUnloaded = false;
10453
10454 #if CONFIG_MACF
10455 /* Is the calling process allowed to query kext info? */
10456 if (current_task() != kernel_task) {
10457 int macCheckResult = 0;
10458 kauth_cred_t cred = NULL;
10459
10460 cred = kauth_cred_get_with_ref();
10461 macCheckResult = mac_kext_check_query(cred);
10462 kauth_cred_unref(&cred);
10463
10464 if (macCheckResult != 0) {
10465 OSKextLog(/* kext */ NULL,
10466 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10467 "Failed to query kext info (MAC policy error 0x%x).",
10468 macCheckResult);
10469 goto finish;
10470 }
10471 }
10472 #endif
10473
10474 if (infoKeys && !infoKeys->getCount()) {
10475 infoKeys = NULL;
10476 }
10477
10478 collectionType = OSDynamicCast(OSString,
10479 _OSKextGetRequestArgument(requestDict,
10480 kKextRequestArgumentCollectionTypeKey));
10481 if (!collectionType) {
10482 OSKextLog(/* kext */ NULL,
10483 kOSKextLogErrorLevel |
10484 kOSKextLogIPCFlag,
10485 "Invalid '%s' argument to kext collection info request.",
10486 kKextRequestArgumentCollectionTypeKey);
10487 goto finish;
10488 }
10489 if (collectionType->isEqualTo(kKCTypePrimary)) {
10490 kc_request_kind = KCKindPrimary;
10491 } else if (collectionType->isEqualTo(kKCTypeSystem)) {
10492 kc_request_kind = KCKindPageable;
10493 } else if (collectionType->isEqualTo(kKCTypeAuxiliary)) {
10494 kc_request_kind = KCKindAuxiliary;
10495 } else if (collectionType->isEqualTo(kKCTypeCodeless)) {
10496 kc_request_kind = KCKindNone;
10497 } else if (!collectionType->isEqualTo(kKCTypeAny)) {
10498 OSKextLog(/* kext */ NULL,
10499 kOSKextLogErrorLevel |
10500 kOSKextLogIPCFlag,
10501 "Invalid '%s' argument value '%s' to kext collection info request.",
10502 kKextRequestArgumentCollectionTypeKey,
10503 collectionType->getCStringNoCopy());
10504 goto finish;
10505 }
10506
10507 rawLoadedState = _OSKextGetRequestArgument(requestDict,
10508 kKextRequestArgumentLoadedStateKey);
10509 if (rawLoadedState) {
10510 loadedState = OSDynamicCast(OSString, rawLoadedState);
10511 if (!loadedState) {
10512 OSKextLog(/* kext */ NULL,
10513 kOSKextLogErrorLevel |
10514 kOSKextLogIPCFlag,
10515 "Invalid '%s' argument to kext collection info request.",
10516 kKextRequestArgumentLoadedStateKey);
10517 goto finish;
10518 }
10519 }
10520 if (loadedState) {
10521 if (loadedState->isEqualTo("Loaded")) {
10522 onlyLoaded = true;
10523 } else if (loadedState->isEqualTo("Unloaded")) {
10524 onlyUnloaded = true;
10525 } else if (!loadedState->isEqualTo("Any")) {
10526 OSKextLog(/* kext */ NULL,
10527 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10528 "Invalid '%s' argument value '%s' for '%s' collection info",
10529 kKextRequestArgumentLoadedStateKey,
10530 loadedState->getCStringNoCopy(),
10531 collectionType->getCStringNoCopy());
10532 goto finish;
10533 }
10534 }
10535
10536 result = OSDictionary::withCapacity(sKextsByID->getCount());
10537 if (!result) {
10538 goto finish;
10539 }
10540
10541 IORecursiveLockLock(sKextLock);
10542 { // start block scope
10543 sKextsByID->iterateObjects(^bool (const OSSymbol *thisKextID, OSObject *obj)
10544 {
10545 OSKext *thisKext = NULL; // do not release
10546 OSSharedPtr<OSDictionary> kextInfo;
10547
10548 (void)thisKextID;
10549
10550 thisKext = OSDynamicCast(OSKext, obj);
10551 if (!thisKext) {
10552 return false;;
10553 }
10554
10555 /*
10556 * skip the kext if it came from the wrong collection type
10557 * (and the caller requested a specific type)
10558 */
10559 if ((kc_request_kind != KCKindUnknown) && (thisKext->kc_type != kc_request_kind)) {
10560 return false;
10561 }
10562
10563 /*
10564 * respect the caller's desire to find only loaded or
10565 * unloaded kexts
10566 */
10567 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10568 return false;
10569 }
10570 if (onlyUnloaded && (-1U != sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10571 return false;
10572 }
10573
10574 kextInfo = thisKext->copyInfo(infoKeys);
10575 if (kextInfo) {
10576 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10577 }
10578 return false;
10579 });
10580 } // end block scope
10581 IORecursiveLockUnlock(sKextLock);
10582
10583 finish:
10584 return result;
10585 }
10586
10587 /*********************************************************************
10588 *********************************************************************/
10589 /* static */
10590 OSSharedPtr<OSDictionary>
10591 OSKext::copyLoadedKextInfo(
10592 OSArray * kextIdentifiers,
10593 OSArray * infoKeys)
10594 {
10595 OSSharedPtr<OSDictionary> result;
10596 uint32_t idCount = 0;
10597 bool onlyLoaded;
10598
10599 IORecursiveLockLock(sKextLock);
10600
10601 #if CONFIG_MACF
10602 /* Is the calling process allowed to query kext info? */
10603 if (current_task() != kernel_task) {
10604 int macCheckResult = 0;
10605 kauth_cred_t cred = NULL;
10606
10607 cred = kauth_cred_get_with_ref();
10608 macCheckResult = mac_kext_check_query(cred);
10609 kauth_cred_unref(&cred);
10610
10611 if (macCheckResult != 0) {
10612 OSKextLog(/* kext */ NULL,
10613 kOSKextLogErrorLevel | kOSKextLogLoadFlag,
10614 "Failed to query kext info (MAC policy error 0x%x).",
10615 macCheckResult);
10616 goto finish;
10617 }
10618 }
10619 #endif
10620
10621 /* Empty list of bundle ids is equivalent to no list (get all).
10622 */
10623 if (kextIdentifiers && !kextIdentifiers->getCount()) {
10624 kextIdentifiers = NULL;
10625 } else if (kextIdentifiers) {
10626 idCount = kextIdentifiers->getCount();
10627 }
10628
10629 /* Same for keys.
10630 */
10631 if (infoKeys && !infoKeys->getCount()) {
10632 infoKeys = NULL;
10633 }
10634
10635 onlyLoaded = (!infoKeys || !_OSArrayContainsCString(infoKeys, kOSBundleAllPrelinkedKey));
10636
10637 result = OSDictionary::withCapacity(128);
10638 if (!result) {
10639 goto finish;
10640 }
10641
10642 #if 0
10643 OSKextLog(/* kext */ NULL,
10644 kOSKextLogErrorLevel |
10645 kOSKextLogGeneralFlag,
10646 "kaslr: vm_kernel_slide 0x%lx \n",
10647 vm_kernel_slide);
10648 OSKextLog(/* kext */ NULL,
10649 kOSKextLogErrorLevel |
10650 kOSKextLogGeneralFlag,
10651 "kaslr: vm_kernel_stext 0x%lx vm_kernel_etext 0x%lx \n",
10652 vm_kernel_stext, vm_kernel_etext);
10653 OSKextLog(/* kext */ NULL,
10654 kOSKextLogErrorLevel |
10655 kOSKextLogGeneralFlag,
10656 "kaslr: vm_kernel_base 0x%lx vm_kernel_top 0x%lx \n",
10657 vm_kernel_base, vm_kernel_top);
10658 OSKextLog(/* kext */ NULL,
10659 kOSKextLogErrorLevel |
10660 kOSKextLogGeneralFlag,
10661 "kaslr: vm_kext_base 0x%lx vm_kext_top 0x%lx \n",
10662 vm_kext_base, vm_kext_top);
10663 OSKextLog(/* kext */ NULL,
10664 kOSKextLogErrorLevel |
10665 kOSKextLogGeneralFlag,
10666 "kaslr: vm_prelink_stext 0x%lx vm_prelink_etext 0x%lx \n",
10667 vm_prelink_stext, vm_prelink_etext);
10668 OSKextLog(/* kext */ NULL,
10669 kOSKextLogErrorLevel |
10670 kOSKextLogGeneralFlag,
10671 "kaslr: vm_prelink_sinfo 0x%lx vm_prelink_einfo 0x%lx \n",
10672 vm_prelink_sinfo, vm_prelink_einfo);
10673 OSKextLog(/* kext */ NULL,
10674 kOSKextLogErrorLevel |
10675 kOSKextLogGeneralFlag,
10676 "kaslr: vm_slinkedit 0x%lx vm_elinkedit 0x%lx \n",
10677 vm_slinkedit, vm_elinkedit);
10678 #endif
10679 { // start block scope
10680 sKextsByID->iterateObjects(^bool (const OSSymbol * thisKextID, OSObject * obj)
10681 {
10682 OSKext * thisKext = NULL; // do not release
10683 Boolean includeThis = true;
10684 OSSharedPtr<OSDictionary> kextInfo;
10685
10686 thisKext = OSDynamicCast(OSKext, obj);
10687 if (!thisKext) {
10688 return false;;
10689 }
10690
10691 /* Skip current kext if not yet started and caller didn't request all.
10692 */
10693 if (onlyLoaded && (-1U == sLoadedKexts->getNextIndexOfObject(thisKext, 0))) {
10694 return false;;
10695 }
10696
10697 /* Skip current kext if we have a list of bundle IDs and
10698 * it isn't in the list.
10699 */
10700 if (kextIdentifiers) {
10701 includeThis = false;
10702
10703 for (uint32_t idIndex = 0; idIndex < idCount; idIndex++) {
10704 const OSString * thisRequestID = OSDynamicCast(OSString,
10705 kextIdentifiers->getObject(idIndex));
10706 if (thisKextID->isEqualTo(thisRequestID)) {
10707 includeThis = true;
10708 break;
10709 }
10710 }
10711 }
10712
10713 if (!includeThis) {
10714 return false;
10715 }
10716
10717 kextInfo = thisKext->copyInfo(infoKeys);
10718 if (kextInfo) {
10719 result->setObject(thisKext->getIdentifier(), kextInfo.get());
10720 }
10721 return false;
10722 });
10723 } // end block scope
10724
10725 finish:
10726 IORecursiveLockUnlock(sKextLock);
10727
10728 return result;
10729 }
10730
10731 /*********************************************************************
10732 * Any info that needs to do allocations must goto finish on alloc
10733 * failure. Info that is just a lookup should just not set the object
10734 * if the info does not exist.
10735 *********************************************************************/
10736 #define _OSKextLoadInfoDictCapacity (12)
10737
10738 OSSharedPtr<OSDictionary>
10739 OSKext::copyInfo(OSArray * infoKeys)
10740 {
10741 OSSharedPtr<OSDictionary> result;
10742 bool success = false;
10743 OSSharedPtr<OSData> headerData;
10744 OSSharedPtr<OSData> logData;
10745 OSSharedPtr<OSNumber> cpuTypeNumber;
10746 OSSharedPtr<OSNumber> cpuSubtypeNumber;
10747 OSString * versionString = NULL; // do not release
10748 OSString * bundleType = NULL; // do not release
10749 uint32_t executablePathCStringSize = 0;
10750 char * executablePathCString = NULL; // must kfree
10751 OSSharedPtr<OSString> executablePathString;
10752 OSSharedPtr<OSData> uuid;
10753 OSSharedPtr<OSArray> dependencyLoadTags;
10754 OSSharedPtr<OSCollectionIterator> metaClassIterator;
10755 OSSharedPtr<OSArray> metaClassInfo;
10756 OSSharedPtr<OSDictionary> metaClassDict;
10757 OSMetaClass * thisMetaClass = NULL; // do not release
10758 OSSharedPtr<OSString> metaClassName;
10759 OSSharedPtr<OSString> superclassName;
10760 kc_format_t kcformat;
10761 uint32_t count, i;
10762
10763 result = OSDictionary::withCapacity(_OSKextLoadInfoDictCapacity);
10764 if (!result) {
10765 goto finish;
10766 }
10767
10768
10769 /* Empty keys means no keys, but NULL is quicker to check.
10770 */
10771 if (infoKeys && !infoKeys->getCount()) {
10772 infoKeys = NULL;
10773 }
10774
10775 if (!PE_get_primary_kc_format(&kcformat)) {
10776 goto finish;
10777 }
10778
10779 /* Headers, CPU type, and CPU subtype.
10780 */
10781 if (!infoKeys ||
10782 _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey) ||
10783 _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey) ||
10784 _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey) ||
10785 _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10786 if (linkedExecutable && !isInterface()) {
10787 kernel_mach_header_t *kext_mach_hdr = (kernel_mach_header_t *)
10788 linkedExecutable->getBytesNoCopy();
10789
10790 #if !SECURE_KERNEL || XNU_TARGET_OS_OSX
10791 // do not return macho header info on shipping embedded - 19095897
10792 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleMachOHeadersKey)) {
10793 kernel_mach_header_t * temp_kext_mach_hdr;
10794 struct load_command * lcp;
10795
10796 headerData = OSData::withBytes(kext_mach_hdr,
10797 (u_int) (sizeof(*kext_mach_hdr) + kext_mach_hdr->sizeofcmds));
10798 if (!headerData) {
10799 goto finish;
10800 }
10801
10802 // unslide any vmaddrs we return to userspace - 10726716
10803 temp_kext_mach_hdr = (kernel_mach_header_t *)
10804 headerData->getBytesNoCopy();
10805 if (temp_kext_mach_hdr == NULL) {
10806 goto finish;
10807 }
10808
10809 lcp = (struct load_command *) (temp_kext_mach_hdr + 1);
10810 for (i = 0; i < temp_kext_mach_hdr->ncmds; i++) {
10811 if (lcp->cmd == LC_SEGMENT_KERNEL) {
10812 kernel_segment_command_t * segp;
10813 kernel_section_t * secp;
10814
10815 segp = (kernel_segment_command_t *) lcp;
10816 // 10543468 - if we jettisoned __LINKEDIT clear size info
10817 if (flags.jettisonLinkeditSeg) {
10818 if (strncmp(segp->segname, SEG_LINKEDIT, sizeof(segp->segname)) == 0) {
10819 segp->vmsize = 0;
10820 segp->fileoff = 0;
10821 segp->filesize = 0;
10822 }
10823 }
10824
10825 #if __arm__ || __arm64__
10826 // iBoot disregards zero-size segments, just set their addresses to gVirtBase
10827 // and unslide them to avoid vm assertion failures / kernel logging breakage.
10828 if (segp->vmsize == 0 && segp->vmaddr < gVirtBase) {
10829 segp->vmaddr = gVirtBase;
10830 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10831 secp->size = 0; // paranoia :)
10832 secp->addr = gVirtBase;
10833 }
10834 }
10835 #endif
10836
10837 #if 0
10838 OSKextLog(/* kext */ NULL,
10839 kOSKextLogErrorLevel |
10840 kOSKextLogGeneralFlag,
10841 "%s: LC_SEGMENT_KERNEL segname '%s' vmaddr 0x%llX 0x%lX vmsize %llu nsects %u",
10842 __FUNCTION__, segp->segname, segp->vmaddr,
10843 VM_KERNEL_UNSLIDE(segp->vmaddr),
10844 segp->vmsize, segp->nsects);
10845 if ((VM_KERNEL_IS_SLID(segp->vmaddr) == false) &&
10846 (VM_KERNEL_IS_KEXT(segp->vmaddr) == false) &&
10847 (VM_KERNEL_IS_PRELINKTEXT(segp->vmaddr) == false) &&
10848 (VM_KERNEL_IS_PRELINKINFO(segp->vmaddr) == false) &&
10849 (VM_KERNEL_IS_KEXT_LINKEDIT(segp->vmaddr) == false)) {
10850 OSKextLog(/* kext */ NULL,
10851 kOSKextLogErrorLevel |
10852 kOSKextLogGeneralFlag,
10853 "%s: not in kext range - vmaddr 0x%llX vm_kext_base 0x%lX vm_kext_top 0x%lX",
10854 __FUNCTION__, segp->vmaddr, vm_kext_base, vm_kext_top);
10855 }
10856 #endif
10857 segp->vmaddr = ml_static_unslide(segp->vmaddr);
10858
10859 for (secp = firstsect(segp); secp != NULL; secp = nextsect(segp, secp)) {
10860 secp->addr = ml_static_unslide(secp->addr);
10861 }
10862 }
10863 lcp = (struct load_command *)((caddr_t)lcp + lcp->cmdsize);
10864 }
10865 result->setObject(kOSBundleMachOHeadersKey, headerData.get());
10866 }
10867 #endif // !SECURE_KERNEL || XNU_TARGET_OS_OSX
10868
10869 if (_OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10870 osLogDataHeaderRef *header;
10871 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10872
10873 void *os_log_data = NULL;
10874 void *cstring_data = NULL;
10875 unsigned long os_log_size = 0;
10876 unsigned long cstring_size = 0;
10877 uint32_t os_log_offset = 0;
10878 uint32_t cstring_offset = 0;
10879 bool res;
10880
10881 os_log_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__os_log", &os_log_size);
10882 os_log_offset = (uintptr_t)os_log_data - (uintptr_t)kext_mach_hdr;
10883 cstring_data = getsectdatafromheader(kext_mach_hdr, "__TEXT", "__cstring", &cstring_size);
10884 cstring_offset = (uintptr_t)cstring_data - (uintptr_t)kext_mach_hdr;
10885
10886 header = (osLogDataHeaderRef *) headerBytes;
10887 header->version = OS_LOG_HDR_VERSION;
10888 header->sect_count = NUM_OS_LOG_SECTIONS;
10889 header->sections[OS_LOG_SECT_IDX].sect_offset = os_log_offset;
10890 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) os_log_size;
10891 header->sections[CSTRING_SECT_IDX].sect_offset = cstring_offset;
10892 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) cstring_size;
10893
10894
10895 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10896 if (!logData) {
10897 goto finish;
10898 }
10899 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10900 if (!res) {
10901 goto finish;
10902 }
10903 if (os_log_data) {
10904 res = logData->appendBytes(os_log_data, (u_int)header->sections[OS_LOG_SECT_IDX].sect_size);
10905 if (!res) {
10906 goto finish;
10907 }
10908 }
10909 if (cstring_data) {
10910 res = logData->appendBytes(cstring_data, (u_int)header->sections[CSTRING_SECT_IDX].sect_size);
10911 if (!res) {
10912 goto finish;
10913 }
10914 }
10915 result->setObject(kOSBundleLogStringsKey, logData.get());
10916 }
10917
10918 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUTypeKey)) {
10919 cpuTypeNumber = OSNumber::withNumber(
10920 (uint64_t) kext_mach_hdr->cputype,
10921 8 * sizeof(kext_mach_hdr->cputype));
10922 if (!cpuTypeNumber) {
10923 goto finish;
10924 }
10925 result->setObject(kOSBundleCPUTypeKey, cpuTypeNumber.get());
10926 }
10927
10928 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCPUSubtypeKey)) {
10929 cpuSubtypeNumber = OSNumber::withNumber(
10930 (uint64_t) kext_mach_hdr->cpusubtype,
10931 8 * sizeof(kext_mach_hdr->cpusubtype));
10932 if (!cpuSubtypeNumber) {
10933 goto finish;
10934 }
10935 result->setObject(kOSBundleCPUSubtypeKey, cpuSubtypeNumber.get());
10936 }
10937 } else {
10938 if (isDriverKit() && _OSArrayContainsCString(infoKeys, kOSBundleLogStringsKey)) {
10939 osLogDataHeaderRef *header;
10940 char headerBytes[offsetof(osLogDataHeaderRef, sections) + NUM_OS_LOG_SECTIONS * sizeof(header->sections[0])];
10941 bool res;
10942
10943 header = (osLogDataHeaderRef *) headerBytes;
10944 header->version = OS_LOG_HDR_VERSION;
10945 header->sect_count = NUM_OS_LOG_SECTIONS;
10946 header->sections[OS_LOG_SECT_IDX].sect_offset = 0;
10947 header->sections[OS_LOG_SECT_IDX].sect_size = (uint32_t) 0;
10948 header->sections[CSTRING_SECT_IDX].sect_offset = 0;
10949 header->sections[CSTRING_SECT_IDX].sect_size = (uint32_t) 0;
10950
10951 logData = OSData::withBytes(header, (u_int) (sizeof(osLogDataHeaderRef)));
10952 if (!logData) {
10953 goto finish;
10954 }
10955 res = logData->appendBytes(&(header->sections[0]), (u_int)(header->sect_count * sizeof(header->sections[0])));
10956 if (!res) {
10957 goto finish;
10958 }
10959 result->setObject(kOSBundleLogStringsKey, logData.get());
10960 }
10961 }
10962 }
10963
10964 /* CFBundleIdentifier. We set this regardless because it's just stupid not to.
10965 */
10966 result->setObject(kCFBundleIdentifierKey, bundleID.get());
10967
10968 /* CFBundlePackageType
10969 */
10970 bundleType = infoDict ? OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey)): NULL;
10971 if (bundleType) {
10972 result->setObject(kCFBundlePackageTypeKey, bundleType);
10973 }
10974
10975 /* CFBundleVersion.
10976 */
10977 if (!infoKeys || _OSArrayContainsCString(infoKeys, kCFBundleVersionKey)) {
10978 versionString = OSDynamicCast(OSString,
10979 getPropertyForHostArch(kCFBundleVersionKey));
10980 if (versionString) {
10981 result->setObject(kCFBundleVersionKey, versionString);
10982 }
10983 }
10984
10985 /* OSBundleCompatibleVersion.
10986 */
10987 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCompatibleVersionKey)) {
10988 versionString = OSDynamicCast(OSString,
10989 getPropertyForHostArch(kOSBundleCompatibleVersionKey));
10990 if (versionString) {
10991 result->setObject(kOSBundleCompatibleVersionKey, versionString);
10992 }
10993 }
10994
10995 /* Path.
10996 */
10997 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePathKey)) {
10998 if (path) {
10999 result->setObject(kOSBundlePathKey, path.get());
11000 }
11001 }
11002
11003
11004 /* OSBundleExecutablePath.
11005 */
11006 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecutablePathKey)) {
11007 if (path && executableRelPath) {
11008 uint32_t pathLength = path->getLength(); // gets incremented below
11009
11010 // +1 for slash, +1 for \0
11011 executablePathCStringSize = pathLength + executableRelPath->getLength() + 2;
11012
11013 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11014 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT); // +1 for \0
11015 if (!executablePathCString) {
11016 goto finish;
11017 }
11018 strlcpy(executablePathCString, path->getCStringNoCopy(),
11019 executablePathCStringSize);
11020 executablePathCString[pathLength++] = '/';
11021 executablePathCString[pathLength++] = '\0';
11022 strlcat(executablePathCString, executableRelPath->getCStringNoCopy(),
11023 executablePathCStringSize);
11024
11025 executablePathString = OSString::withCString(executablePathCString);
11026
11027 if (!executablePathString) {
11028 goto finish;
11029 }
11030
11031 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11032 } else if (flags.builtin) {
11033 result->setObject(kOSBundleExecutablePathKey, bundleID.get());
11034 } else if (isDriverKit()) {
11035 if (path) {
11036 // +1 for slash, +1 for \0
11037 uint32_t pathLength = path->getLength();
11038 executablePathCStringSize = pathLength + 2;
11039
11040 executablePathCString = (char *)kheap_alloc_tag(KHEAP_TEMP,
11041 executablePathCStringSize, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
11042 if (!executablePathCString) {
11043 goto finish;
11044 }
11045 strlcpy(executablePathCString, path->getCStringNoCopy(), executablePathCStringSize);
11046 executablePathCString[pathLength++] = '/';
11047 executablePathCString[pathLength++] = '\0';
11048
11049 executablePathString = OSString::withCString(executablePathCString);
11050
11051 if (!executablePathString) {
11052 goto finish;
11053 }
11054
11055 result->setObject(kOSBundleExecutablePathKey, executablePathString.get());
11056 }
11057 }
11058 }
11059
11060 /* UUID, if the kext has one.
11061 */
11062 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleUUIDKey)) {
11063 uuid = copyUUID();
11064 if (uuid) {
11065 result->setObject(kOSBundleUUIDKey, uuid.get());
11066 }
11067 }
11068 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleTextUUIDKey)) {
11069 uuid = copyTextUUID();
11070 if (uuid) {
11071 result->setObject(kOSBundleTextUUIDKey, uuid.get());
11072 }
11073 }
11074
11075 /*
11076 * Info.plist digest
11077 */
11078 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextInfoPlistDigestKey)) {
11079 OSData *digest;
11080 digest = infoDict ? OSDynamicCast(OSData, infoDict->getObject(kOSKextInfoPlistDigestKey)) : NULL;
11081 if (digest) {
11082 result->setObject(kOSKextInfoPlistDigestKey, digest);
11083 }
11084 }
11085
11086 /*
11087 * Collection type
11088 */
11089 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextBundleCollectionTypeKey)) {
11090 result->setObject(kOSKextBundleCollectionTypeKey, OSString::withCString(getKCTypeString()));
11091 }
11092
11093 /*
11094 * Collection availability
11095 */
11096 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKextAuxKCAvailabilityKey)) {
11097 result->setObject(kOSKextAuxKCAvailabilityKey,
11098 isLoadable() ? kOSBooleanTrue : kOSBooleanFalse);
11099 }
11100
11101 /*
11102 * Allows user load
11103 */
11104 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleAllowUserLoadKey)) {
11105 OSBoolean *allowUserLoad = OSDynamicCast(OSBoolean, getPropertyForHostArch(kOSBundleAllowUserLoadKey));
11106 if (allowUserLoad) {
11107 result->setObject(kOSBundleAllowUserLoadKey, allowUserLoad);
11108 }
11109 }
11110
11111 /*
11112 * Bundle Dependencies (OSBundleLibraries)
11113 */
11114 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLibrariesKey)) {
11115 OSDictionary *libraries = OSDynamicCast(OSDictionary, getPropertyForHostArch(kOSBundleLibrariesKey));
11116 if (libraries) {
11117 result->setObject(kOSBundleLibrariesKey, libraries);
11118 }
11119 }
11120
11121 /*****
11122 * OSKernelResource, OSBundleIsInterface, OSBundlePrelinked, OSBundleStarted.
11123 */
11124 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSKernelResourceKey)) {
11125 result->setObject(kOSKernelResourceKey,
11126 isKernelComponent() ? kOSBooleanTrue : kOSBooleanFalse);
11127 }
11128
11129 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleIsInterfaceKey)) {
11130 result->setObject(kOSBundleIsInterfaceKey,
11131 isInterface() ? kOSBooleanTrue : kOSBooleanFalse);
11132 }
11133
11134 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundlePrelinkedKey)) {
11135 result->setObject(kOSBundlePrelinkedKey,
11136 isPrelinked() ? kOSBooleanTrue : kOSBooleanFalse);
11137 }
11138
11139 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleStartedKey)) {
11140 result->setObject(kOSBundleStartedKey,
11141 isStarted() ? kOSBooleanTrue : kOSBooleanFalse);
11142 }
11143
11144 /* LoadTag (Index).
11145 */
11146 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadTagKey)) {
11147 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber((unsigned long long)loadTag,
11148 /* numBits */ 8 * sizeof(loadTag));
11149 if (!scratchNumber) {
11150 goto finish;
11151 }
11152 result->setObject(kOSBundleLoadTagKey, scratchNumber.get());
11153 }
11154
11155 /* LoadAddress, LoadSize.
11156 */
11157 if (!infoKeys ||
11158 _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey) ||
11159 _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey) ||
11160 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey) ||
11161 _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey) ||
11162 _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11163 bool is_dext = isDriverKit();
11164 if (isInterface() || flags.builtin || linkedExecutable || is_dext) {
11165 /* These go to userspace via serialization, so we don't want any doubts
11166 * about their size.
11167 */
11168 uint64_t loadAddress = 0;
11169 uint32_t loadSize = 0;
11170 uint32_t wiredSize = 0;
11171 uint64_t execLoadAddress = 0;
11172 uint32_t execLoadSize = 0;
11173
11174 /* Interfaces always report 0 load address & size.
11175 * Just the way they roll.
11176 *
11177 * xxx - leaving in # when we have a linkedExecutable...a kernelcomp
11178 * xxx - shouldn't have one!
11179 */
11180
11181 if (flags.builtin || linkedExecutable) {
11182 kernel_mach_header_t *mh = NULL;
11183 kernel_segment_command_t *seg = NULL;
11184
11185 if (flags.builtin) {
11186 loadAddress = kmod_info->address;
11187 loadSize = (uint32_t)kmod_info->size;
11188 } else {
11189 loadAddress = (uint64_t)linkedExecutable->getBytesNoCopy();
11190 loadSize = linkedExecutable->getLength();
11191 }
11192 mh = (kernel_mach_header_t *)loadAddress;
11193 loadAddress = ml_static_unslide(loadAddress);
11194
11195 /* Walk through the kext, looking for the first executable
11196 * segment in case we were asked for its size/address.
11197 */
11198 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
11199 if (seg->initprot & VM_PROT_EXECUTE) {
11200 execLoadAddress = ml_static_unslide(seg->vmaddr);
11201 execLoadSize = (uint32_t)seg->vmsize;
11202 break;
11203 }
11204 }
11205
11206 /* If we have a kmod_info struct, calculated the wired size
11207 * from that. Otherwise it's the full load size.
11208 */
11209 if (kmod_info) {
11210 wiredSize = loadSize - (uint32_t)kmod_info->hdr_size;
11211 } else {
11212 wiredSize = loadSize;
11213 }
11214 } else if (is_dext) {
11215 /*
11216 * DriverKit userspace executables do not have a kernel linkedExecutable,
11217 * so we "fake" their address range with the LoadTag.
11218 */
11219 if (loadTag) {
11220 loadAddress = execLoadAddress = loadTag;
11221 loadSize = execLoadSize = 1;
11222 }
11223 }
11224
11225 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadAddressKey)) {
11226 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11227 (unsigned long long)(loadAddress),
11228 /* numBits */ 8 * sizeof(loadAddress));
11229 if (!scratchNumber) {
11230 goto finish;
11231 }
11232 result->setObject(kOSBundleLoadAddressKey, scratchNumber.get());
11233 }
11234 if (kcformat == KCFormatStatic || kcformat == KCFormatKCGEN) {
11235 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleCacheLoadAddressKey))
11236 && loadAddress && loadSize) {
11237 void *baseAddress = PE_get_kc_baseaddress(KCKindPrimary);
11238 if (!baseAddress) {
11239 goto finish;
11240 }
11241
11242 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11243 (unsigned long long)ml_static_unslide((vm_offset_t)baseAddress),
11244 /* numBits */ 8 * sizeof(loadAddress));
11245 if (!scratchNumber) {
11246 goto finish;
11247 }
11248 result->setObject(kOSBundleCacheLoadAddressKey, scratchNumber.get());
11249 }
11250 if ((!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleKextsInKernelTextKey))
11251 && (this == sKernelKext) && gBuiltinKmodsCount) {
11252 result->setObject(kOSBundleKextsInKernelTextKey, kOSBooleanTrue);
11253 }
11254 }
11255
11256 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadAddressKey)) {
11257 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11258 (unsigned long long)(execLoadAddress),
11259 /* numBits */ 8 * sizeof(execLoadAddress));
11260 if (!scratchNumber) {
11261 goto finish;
11262 }
11263 result->setObject(kOSBundleExecLoadAddressKey, scratchNumber.get());
11264 }
11265 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleLoadSizeKey)) {
11266 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11267 (unsigned long long)(loadSize),
11268 /* numBits */ 8 * sizeof(loadSize));
11269 if (!scratchNumber) {
11270 goto finish;
11271 }
11272 result->setObject(kOSBundleLoadSizeKey, scratchNumber.get());
11273 }
11274 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleExecLoadSizeKey)) {
11275 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11276 (unsigned long long)(execLoadSize),
11277 /* numBits */ 8 * sizeof(execLoadSize));
11278 if (!scratchNumber) {
11279 goto finish;
11280 }
11281 result->setObject(kOSBundleExecLoadSizeKey, scratchNumber.get());
11282 }
11283 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleWiredSizeKey)) {
11284 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11285 (unsigned long long)(wiredSize),
11286 /* numBits */ 8 * sizeof(wiredSize));
11287 if (!scratchNumber) {
11288 goto finish;
11289 }
11290 result->setObject(kOSBundleWiredSizeKey, scratchNumber.get());
11291 }
11292 }
11293 }
11294
11295 /* OSBundleDependencies. In descending order for
11296 * easy compatibility with kextstat(8).
11297 */
11298 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleDependenciesKey)) {
11299 if ((count = getNumDependencies())) {
11300 dependencyLoadTags = OSArray::withCapacity(count);
11301 result->setObject(kOSBundleDependenciesKey, dependencyLoadTags.get());
11302
11303 i = count - 1;
11304 do {
11305 OSKext * dependency = OSDynamicCast(OSKext,
11306 dependencies->getObject(i));
11307
11308 if (!dependency) {
11309 continue;
11310 }
11311 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11312 (unsigned long long)dependency->getLoadTag(),
11313 /* numBits*/ 8 * sizeof(loadTag));
11314 if (!scratchNumber) {
11315 goto finish;
11316 }
11317 dependencyLoadTags->setObject(scratchNumber.get());
11318 } while (i--);
11319 }
11320 }
11321
11322 /* OSBundleMetaClasses.
11323 */
11324 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleClassesKey)) {
11325 if (metaClasses && metaClasses->getCount()) {
11326 metaClassIterator = OSCollectionIterator::withCollection(metaClasses.get());
11327 metaClassInfo = OSArray::withCapacity(metaClasses->getCount());
11328 if (!metaClassIterator || !metaClassInfo) {
11329 goto finish;
11330 }
11331 result->setObject(kOSBundleClassesKey, metaClassInfo.get());
11332
11333 while ((thisMetaClass = OSDynamicCast(OSMetaClass,
11334 metaClassIterator->getNextObject()))) {
11335 metaClassDict = OSDictionary::withCapacity(3);
11336 if (!metaClassDict) {
11337 goto finish;
11338 }
11339
11340 metaClassName = OSString::withCString(thisMetaClass->getClassName());
11341 if (thisMetaClass->getSuperClass()) {
11342 superclassName = OSString::withCString(
11343 thisMetaClass->getSuperClass()->getClassName());
11344 }
11345 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(thisMetaClass->getInstanceCount(),
11346 8 * sizeof(unsigned int));
11347
11348 /* Bail if any of the essentials is missing. The root class lacks a superclass,
11349 * of course.
11350 */
11351 if (!metaClassDict || !metaClassName || !scratchNumber) {
11352 goto finish;
11353 }
11354
11355 metaClassInfo->setObject(metaClassDict.get());
11356 metaClassDict->setObject(kOSMetaClassNameKey, metaClassName.get());
11357 if (superclassName) {
11358 metaClassDict->setObject(kOSMetaClassSuperclassNameKey, superclassName.get());
11359 }
11360 metaClassDict->setObject(kOSMetaClassTrackingCountKey, scratchNumber.get());
11361 }
11362 }
11363 }
11364
11365 /* OSBundleRetainCount.
11366 */
11367 if (!infoKeys || _OSArrayContainsCString(infoKeys, kOSBundleRetainCountKey)) {
11368 {
11369 int kextRetainCount = getRetainCount() - 1;
11370 if (isLoaded()) {
11371 kextRetainCount--;
11372 }
11373 OSSharedPtr<OSNumber> scratchNumber = OSNumber::withNumber(
11374 (int)kextRetainCount,
11375 /* numBits*/ 8 * sizeof(int));
11376 if (scratchNumber) {
11377 result->setObject(kOSBundleRetainCountKey, scratchNumber.get());
11378 }
11379 }
11380 }
11381
11382 success = true;
11383
11384 finish:
11385 if (executablePathCString) {
11386 kheap_free(KHEAP_TEMP, executablePathCString, executablePathCStringSize);
11387 }
11388 if (!success) {
11389 result.reset();
11390 }
11391 return result;
11392 }
11393
11394 /*********************************************************************
11395 *********************************************************************/
11396 /* static */
11397 bool
11398 OSKext::copyUserExecutablePath(const OSSymbol * bundleID, char * pathResult, size_t pathSize)
11399 {
11400 bool ok;
11401 OSSharedPtr<OSKext> kext;
11402
11403 IORecursiveLockLock(sKextLock);
11404 kext.reset(OSDynamicCast(OSKext, sKextsByID->getObject(bundleID)), OSRetain);
11405 IORecursiveLockUnlock(sKextLock);
11406
11407 if (!kext || !kext->path || !kext->userExecutableRelPath) {
11408 return false;
11409 }
11410 snprintf(pathResult, pathSize, "%s/Contents/MacOS/%s",
11411 kext->path->getCStringNoCopy(),
11412 kext->userExecutableRelPath->getCStringNoCopy());
11413 ok = true;
11414
11415 return ok;
11416 }
11417
11418 /*********************************************************************
11419 *********************************************************************/
11420 /* static */
11421 OSReturn
11422 OSKext::requestResource(
11423 const char * kextIdentifierCString,
11424 const char * resourceNameCString,
11425 OSKextRequestResourceCallback callback,
11426 void * context,
11427 OSKextRequestTag * requestTagOut)
11428 {
11429 OSReturn result = kOSReturnError;
11430 OSSharedPtr<OSKext> callbackKext; // looked up
11431
11432 OSKextRequestTag requestTag = -1;
11433 OSSharedPtr<OSNumber> requestTagNum;
11434 OSSharedPtr<OSDictionary> requestDict;
11435 OSSharedPtr<OSString> kextIdentifier;
11436 OSSharedPtr<OSString> resourceName;
11437
11438 OSSharedPtr<OSDictionary> callbackRecord;
11439 OSSharedPtr<OSData> callbackWrapper;
11440
11441 OSSharedPtr<OSData> contextWrapper;
11442
11443 IORecursiveLockLock(sKextLock);
11444
11445 if (requestTagOut) {
11446 *requestTagOut = kOSKextRequestTagInvalid;
11447 }
11448
11449 /* If requests to user space are disabled, don't go any further */
11450 if (!sKernelRequestsEnabled) {
11451 OSKextLog(/* kext */ NULL,
11452 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11453 "Can't request resource %s for %s - requests to user space are disabled.",
11454 resourceNameCString,
11455 kextIdentifierCString);
11456 result = kOSKextReturnDisabled;
11457 goto finish;
11458 }
11459
11460 if (!kextIdentifierCString || !resourceNameCString || !callback) {
11461 result = kOSKextReturnInvalidArgument;
11462 goto finish;
11463 }
11464
11465 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
11466 if (!callbackKext) {
11467 OSKextLog(/* kext */ NULL,
11468 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11469 "Resource request has bad callback address.");
11470 result = kOSKextReturnInvalidArgument;
11471 goto finish;
11472 }
11473 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
11474 OSKextLog(/* kext */ NULL,
11475 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11476 "Resource request callback is in a kext that is not started.");
11477 result = kOSKextReturnInvalidArgument;
11478 goto finish;
11479 }
11480
11481 /* Do not allow any new requests to be made on a kext that is unloading.
11482 */
11483 if (callbackKext->flags.stopping) {
11484 result = kOSKextReturnStopping;
11485 goto finish;
11486 }
11487
11488 /* If we're wrapped the next available request tag around to the negative
11489 * numbers, we can't service any more requests.
11490 */
11491 if (sNextRequestTag == kOSKextRequestTagInvalid) {
11492 OSKextLog(/* kext */ NULL,
11493 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11494 "No more request tags available; restart required.");
11495 result = kOSKextReturnNoResources;
11496 goto finish;
11497 }
11498 requestTag = sNextRequestTag++;
11499
11500 result = _OSKextCreateRequest(kKextRequestPredicateRequestResource,
11501 requestDict);
11502 if (result != kOSReturnSuccess) {
11503 goto finish;
11504 }
11505
11506 kextIdentifier = OSString::withCString(kextIdentifierCString);
11507 resourceName = OSString::withCString(resourceNameCString);
11508 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11509 8 * sizeof(requestTag));
11510 if (!kextIdentifier ||
11511 !resourceName ||
11512 !requestTagNum ||
11513 !_OSKextSetRequestArgument(requestDict.get(),
11514 kKextRequestArgumentBundleIdentifierKey, kextIdentifier.get()) ||
11515 !_OSKextSetRequestArgument(requestDict.get(),
11516 kKextRequestArgumentNameKey, resourceName.get()) ||
11517 !_OSKextSetRequestArgument(requestDict.get(),
11518 kKextRequestArgumentRequestTagKey, requestTagNum.get())) {
11519 result = kOSKextReturnNoMemory;
11520 goto finish;
11521 }
11522
11523 callbackRecord = OSDynamicPtrCast<OSDictionary>(requestDict->copyCollection());
11524 if (!callbackRecord) {
11525 result = kOSKextReturnNoMemory;
11526 goto finish;
11527 }
11528 // we validate callback address at call time
11529 callbackWrapper = OSData::withBytes((void *)&callback, sizeof(void *));
11530 if (context) {
11531 contextWrapper = OSData::withBytes((void *)&context, sizeof(void *));
11532 }
11533 if (!callbackWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11534 kKextRequestArgumentCallbackKey, callbackWrapper.get())) {
11535 result = kOSKextReturnNoMemory;
11536 goto finish;
11537 }
11538
11539 if (context) {
11540 if (!contextWrapper || !_OSKextSetRequestArgument(callbackRecord.get(),
11541 kKextRequestArgumentContextKey, contextWrapper.get())) {
11542 result = kOSKextReturnNoMemory;
11543 goto finish;
11544 }
11545 }
11546
11547 /* Only post the requests after all the other potential failure points
11548 * have been passed.
11549 */
11550 if (!sKernelRequests->setObject(requestDict.get()) ||
11551 !sRequestCallbackRecords->setObject(callbackRecord.get())) {
11552 result = kOSKextReturnNoMemory;
11553 goto finish;
11554 }
11555
11556 OSKext::pingIOKitDaemon();
11557
11558 result = kOSReturnSuccess;
11559 if (requestTagOut) {
11560 *requestTagOut = requestTag;
11561 }
11562
11563 finish:
11564
11565 /* If we didn't succeed, yank the request & callback
11566 * from their holding arrays.
11567 */
11568 if (result != kOSReturnSuccess) {
11569 unsigned int index;
11570
11571 index = sKernelRequests->getNextIndexOfObject(requestDict.get(), 0);
11572 if (index != (unsigned int)-1) {
11573 sKernelRequests->removeObject(index);
11574 }
11575 index = sRequestCallbackRecords->getNextIndexOfObject(callbackRecord.get(), 0);
11576 if (index != (unsigned int)-1) {
11577 sRequestCallbackRecords->removeObject(index);
11578 }
11579 }
11580
11581 OSKext::considerUnloads(/* rescheduleOnly? */ true);
11582
11583 IORecursiveLockUnlock(sKextLock);
11584
11585 return result;
11586 }
11587
11588 OSReturn
11589 OSKext::requestDaemonLaunch(
11590 OSString *kextIdentifier,
11591 OSString *serverName,
11592 OSNumber *serverTag,
11593 OSSharedPtr<IOUserServerCheckInToken> &checkInToken)
11594 {
11595 OSReturn result;
11596 IOUserServerCheckInToken * checkInTokenRaw = NULL;
11597
11598 result = requestDaemonLaunch(kextIdentifier, serverName,
11599 serverTag, &checkInTokenRaw);
11600
11601 if (kOSReturnSuccess == result) {
11602 checkInToken.reset(checkInTokenRaw, OSNoRetain);
11603 }
11604
11605 return result;
11606 }
11607
11608 OSReturn
11609 OSKext::requestDaemonLaunch(
11610 OSString *kextIdentifier,
11611 OSString *serverName,
11612 OSNumber *serverTag,
11613 IOUserServerCheckInToken ** checkInToken)
11614 {
11615 OSReturn result = kOSReturnError;
11616 OSSharedPtr<OSDictionary> requestDict;
11617 OSSharedPtr<IOUserServerCheckInToken> token;
11618
11619 if (!kextIdentifier || !serverName || !serverTag) {
11620 result = kOSKextReturnInvalidArgument;
11621 goto finish;
11622 }
11623
11624 IORecursiveLockLock(sKextLock);
11625
11626 OSKextLog(/* kext */ NULL,
11627 kOSKextLogDebugLevel |
11628 kOSKextLogGeneralFlag,
11629 "Requesting daemon launch for %s with serverName %s and tag %llu",
11630 kextIdentifier->getCStringNoCopy(),
11631 serverName->getCStringNoCopy(),
11632 serverTag->unsigned64BitValue()
11633 );
11634
11635 result = _OSKextCreateRequest(kKextRequestPredicateRequestDaemonLaunch, requestDict);
11636 if (result != kOSReturnSuccess) {
11637 goto finish;
11638 }
11639
11640 token.reset(IOUserServerCheckInToken::create(), OSNoRetain);
11641 if (!token) {
11642 result = kOSKextReturnNoMemory;
11643 goto finish;
11644 }
11645
11646 if (!_OSKextSetRequestArgument(requestDict.get(),
11647 kKextRequestArgumentBundleIdentifierKey, kextIdentifier) ||
11648 !_OSKextSetRequestArgument(requestDict.get(),
11649 kKextRequestArgumentDriverExtensionServerName, serverName) ||
11650 !_OSKextSetRequestArgument(requestDict.get(),
11651 kKextRequestArgumentDriverExtensionServerTag, serverTag) ||
11652 !_OSKextSetRequestArgument(requestDict.get(),
11653 kKextRequestArgumentCheckInToken, token.get())) {
11654 result = kOSKextReturnNoMemory;
11655 goto finish;
11656 }
11657
11658 /* Only post the requests after all the other potential failure points
11659 * have been passed.
11660 */
11661 if (!sKernelRequests->setObject(requestDict.get())) {
11662 result = kOSKextReturnNoMemory;
11663 goto finish;
11664 }
11665 *checkInToken = token.detach();
11666 OSKext::pingIOKitDaemon();
11667
11668 result = kOSReturnSuccess;
11669 finish:
11670 IORecursiveLockUnlock(sKextLock);
11671 return result;
11672 }
11673
11674 /*********************************************************************
11675 * Assumes sKextLock is held.
11676 *********************************************************************/
11677 /* static */
11678 OSReturn
11679 OSKext::dequeueCallbackForRequestTag(
11680 OSKextRequestTag requestTag,
11681 OSSharedPtr<OSDictionary> &callbackRecordOut)
11682 {
11683 OSDictionary * callbackRecordOutRaw = NULL;
11684 OSReturn result;
11685
11686 result = dequeueCallbackForRequestTag(requestTag,
11687 &callbackRecordOutRaw);
11688
11689 if (kOSReturnSuccess == result) {
11690 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11691 }
11692
11693 return result;
11694 }
11695 OSReturn
11696 OSKext::dequeueCallbackForRequestTag(
11697 OSKextRequestTag requestTag,
11698 OSDictionary ** callbackRecordOut)
11699 {
11700 OSReturn result = kOSReturnError;
11701 OSSharedPtr<OSNumber> requestTagNum;
11702
11703 requestTagNum = OSNumber::withNumber((long long unsigned int)requestTag,
11704 8 * sizeof(requestTag));
11705 if (!requestTagNum) {
11706 goto finish;
11707 }
11708
11709 result = OSKext::dequeueCallbackForRequestTag(requestTagNum.get(),
11710 callbackRecordOut);
11711
11712 finish:
11713 return result;
11714 }
11715
11716 /*********************************************************************
11717 * Assumes sKextLock is held.
11718 *********************************************************************/
11719 /* static */
11720 OSReturn
11721 OSKext::dequeueCallbackForRequestTag(
11722 OSNumber * requestTagNum,
11723 OSSharedPtr<OSDictionary> &callbackRecordOut)
11724 {
11725 OSDictionary * callbackRecordOutRaw = NULL;
11726 OSReturn result;
11727
11728 result = dequeueCallbackForRequestTag(requestTagNum,
11729 &callbackRecordOutRaw);
11730
11731 if (kOSReturnSuccess == result) {
11732 callbackRecordOut.reset(callbackRecordOutRaw, OSNoRetain);
11733 }
11734
11735 return result;
11736 }
11737 OSReturn
11738 OSKext::dequeueCallbackForRequestTag(
11739 OSNumber * requestTagNum,
11740 OSDictionary ** callbackRecordOut)
11741 {
11742 OSReturn result = kOSKextReturnInvalidArgument;
11743 OSDictionary * callbackRecord = NULL; // retain if matched!
11744 OSNumber * callbackTagNum = NULL; // do not release
11745 unsigned int count, i;
11746
11747 result = kOSReturnError;
11748 count = sRequestCallbackRecords->getCount();
11749 for (i = 0; i < count; i++) {
11750 callbackRecord = OSDynamicCast(OSDictionary,
11751 sRequestCallbackRecords->getObject(i));
11752 if (!callbackRecord) {
11753 goto finish;
11754 }
11755
11756 /* If we don't find a tag, we basically have a leak here. Maybe
11757 * we should just remove it.
11758 */
11759 callbackTagNum = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(
11760 callbackRecord, kKextRequestArgumentRequestTagKey));
11761 if (!callbackTagNum) {
11762 goto finish;
11763 }
11764
11765 /* We could be even more paranoid and check that all the incoming
11766 * args match what's in the callback record.
11767 */
11768 if (callbackTagNum->isEqualTo(requestTagNum)) {
11769 if (callbackRecordOut) {
11770 *callbackRecordOut = callbackRecord;
11771 callbackRecord->retain();
11772 }
11773 sRequestCallbackRecords->removeObject(i);
11774 result = kOSReturnSuccess;
11775 goto finish;
11776 }
11777 }
11778 result = kOSKextReturnNotFound;
11779
11780 finish:
11781 return result;
11782 }
11783
11784
11785 /*********************************************************************
11786 * Busy timeout triage
11787 *********************************************************************/
11788 /* static */
11789 bool
11790 OSKext::pendingIOKitDaemonRequests(void)
11791 {
11792 return sRequestCallbackRecords && sRequestCallbackRecords->getCount();
11793 }
11794
11795 /*********************************************************************
11796 * Acquires and releases sKextLock
11797 *
11798 * This function is designed to be called exactly once on boot by
11799 * the IOKit management daemon, kernelmanagerd. It gathers all codeless
11800 * kext and dext personalities, and then attempts to map a System
11801 * (pageable) KC and an Auxiliary (aux) KC.
11802 *
11803 * Even if the pageable or aux KC fail to load - this function will
11804 * not allow a second call. This avoids security issues where
11805 * kernelmanagerd has been compromised or the pageable kc has been
11806 * tampered with and the attacker attempts to re-load a malicious
11807 * variant.
11808 *
11809 * Return: if a KC fails to load the return value will contain:
11810 * kOSKextReturnKCLoadFailure. If the pageable KC fails,
11811 * the return value will contain kOSKextReturnKCLoadFailureSystemKC.
11812 * Similarly, if the aux kc load fails, the return value will
11813 * contain kOSKextReturnKCLoadFailureAuxKC. The two values
11814 * compose with each other and with kOSKextReturnKCLoadFailure.
11815 *********************************************************************/
11816 /* static */
11817 OSReturn
11818 OSKext::loadFileSetKexts(OSDictionary * requestDict __unused)
11819 {
11820 static bool daemon_ready = false;
11821
11822 OSReturn ret = kOSKextReturnInvalidArgument;
11823 OSReturn kcerr = 0;
11824 bool start_matching = false;
11825
11826 bool allow_fileset_load = !daemon_ready;
11827 #if !(defined(__x86_64__) || defined(__i386__))
11828 /* never allow KCs full of kexts on non-x86 machines */
11829 allow_fileset_load = false;
11830 #endif
11831
11832 /*
11833 * Get the args from the request. Right now we need the file
11834 * name for the pageable and the aux kext collection file sets.
11835 */
11836 OSDictionary * requestArgs = NULL; // do not release
11837 OSString * pageable_filepath = NULL; // do not release
11838 OSString * aux_filepath = NULL; // do not release
11839 OSArray * codeless_kexts = NULL; // do not release
11840
11841 kernel_mach_header_t *akc_mh = NULL;
11842
11843 requestArgs = OSDynamicCast(OSDictionary,
11844 requestDict->getObject(kKextRequestArgumentsKey));
11845
11846 if (requestArgs == NULL) {
11847 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11848 "KextLog: No arguments in plist for loading fileset kext\n");
11849 printf("KextLog: No arguments in plist for loading fileset kext\n");
11850 return ret;
11851 }
11852
11853 ret = kOSKextReturnDisabled;
11854
11855 IORecursiveLockLock(sKextLock);
11856
11857 if (!sLoadEnabled) {
11858 OSKextLog(NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11859 "KextLog: Kext loading is disabled (attempt to load KCs).");
11860 IORecursiveLockUnlock(sKextLock);
11861 return ret;
11862 }
11863
11864 pageable_filepath = OSDynamicCast(OSString,
11865 requestArgs->getObject(kKextRequestArgumentPageableKCFilename));
11866
11867 if (allow_fileset_load && pageable_filepath != NULL) {
11868 printf("KextLog: Loading Pageable KC from file %s\n", pageable_filepath->getCStringNoCopy());
11869
11870 ret = OSKext::loadKCFileSet(pageable_filepath->getCStringNoCopy(), KCKindPageable);
11871 if (ret) {
11872 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11873 "KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11874
11875 printf("KextLog: loadKCFileSet for Pageable KC returned %d\n", ret);
11876 ret = kOSKextReturnKCLoadFailure;
11877 kcerr |= kOSKextReturnKCLoadFailureSystemKC;
11878 goto try_auxkc;
11879 }
11880 /*
11881 * Even if the AuxKC fails to load, we still want to send
11882 * the System KC personalities to the catalog for matching
11883 */
11884 start_matching = true;
11885 } else if (pageable_filepath != NULL) {
11886 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11887 "KextLog: ignoring Pageable KC load from %s\n", pageable_filepath->getCStringNoCopy());
11888 ret = kOSKextReturnUnsupported;
11889 }
11890
11891 try_auxkc:
11892 akc_mh = (kernel_mach_header_t*)PE_get_kc_header(KCKindAuxiliary);
11893 if (akc_mh) {
11894 /*
11895 * If we try to load a deferred AuxKC, then don't ever attempt
11896 * a filesystem map of a file
11897 */
11898 allow_fileset_load = false;
11899
11900 /*
11901 * This function is only called once per boot, so we haven't
11902 * yet loaded an AuxKC. If we have registered the AuxKC mach
11903 * header, that means that the kext collection has been placed
11904 * in memory for us by the booter, and is waiting for us to
11905 * process it. Grab the deferred XML plist of info
11906 * dictionaries and add all the kexts.
11907 */
11908 OSSharedPtr<OSObject> parsedXML;
11909 OSSharedPtr<OSData> loaded_kcUUID;
11910 OSDictionary *infoDict;
11911 parsedXML = consumeDeferredKextCollection(KCKindAuxiliary);
11912 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
11913 if (infoDict) {
11914 bool added;
11915 printf("KextLog: Adding kexts from in-memory AuxKC\n");
11916 added = OSKext::addKextsFromKextCollection(akc_mh, infoDict,
11917 kPrelinkTextSegment, loaded_kcUUID, KCKindAuxiliary);
11918 if (!loaded_kcUUID) {
11919 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11920 "KextLog: WARNING: did not find UUID in deferred Aux KC!");
11921 } else if (!added) {
11922 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
11923 "KextLog: WARNING: Failed to load AuxKC from memory.");
11924 }
11925 /* only return success if the pageable load (above) was successful */
11926 if (ret != kOSKextReturnKCLoadFailure) {
11927 ret = kOSReturnSuccess;
11928 }
11929 /* the registration of the AuxKC parsed out the KC's UUID already */
11930 } else {
11931 if (daemon_ready) {
11932 /*
11933 * Complain, but don't return an error if this isn't the first time the
11934 * IOKit daemon is checking in. If the daemon ever restarts, we will
11935 * hit this case because we've already consumed the deferred personalities.
11936 * We return success here so that a call to this function from a restarted
11937 * daemon with no codeless kexts will succeed.
11938 */
11939 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11940 "KextLog: can't re-parse deferred AuxKC personalities on IOKit daemon restart");
11941 if (ret != kOSKextReturnKCLoadFailure) {
11942 ret = kOSReturnSuccess;
11943 }
11944 } else {
11945 /* this is a real error case */
11946 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogIPCFlag,
11947 "KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary");
11948 printf("KextLog: ERROR loading deferred AuxKC: PRELINK_INFO wasn't an OSDictionary\n");
11949 ret = kOSKextReturnKCLoadFailure;
11950 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
11951 }
11952 }
11953 }
11954
11955 aux_filepath = OSDynamicCast(OSString,
11956 requestArgs->getObject(kKextRequestArgumentAuxKCFilename));
11957 if (allow_fileset_load && aux_filepath != NULL) {
11958 printf("KextLog: Loading Aux KC from file %s\n", aux_filepath->getCStringNoCopy());
11959
11960 ret = OSKext::loadKCFileSet(aux_filepath->getCStringNoCopy(), KCKindAuxiliary);
11961 if (ret) {
11962 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11963 "KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
11964
11965 printf("KextLog: loadKCFileSet for Aux KC returned %d\n", ret);
11966 ret = kOSKextReturnKCLoadFailure;
11967 kcerr |= kOSKextReturnKCLoadFailureAuxKC;
11968 goto try_codeless;
11969 }
11970 start_matching = true;
11971 } else if (aux_filepath != NULL) {
11972 OSKextLog(/* kext */ NULL, kOSKextLogBasicLevel | kOSKextLogIPCFlag,
11973 "KextLog: Ignoring AuxKC load from %s\n", aux_filepath->getCStringNoCopy());
11974 if (ret != kOSKextReturnKCLoadFailure) {
11975 ret = kOSKextReturnUnsupported;
11976 }
11977 }
11978
11979 try_codeless:
11980 /*
11981 * Load codeless kexts last so that there is no possibilty of a
11982 * codeless kext bundle ID preventing a kext in the system KC from
11983 * loading
11984 */
11985 codeless_kexts = OSDynamicCast(OSArray,
11986 requestArgs->getObject(kKextRequestArgumentCodelessPersonalities));
11987 if (codeless_kexts != NULL) {
11988 uint32_t count = codeless_kexts->getCount();
11989 OSKextLog(NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
11990 "KextLog: loading %d codeless kexts/dexts", count);
11991 for (uint32_t i = 0; i < count; i++) {
11992 OSDictionary *infoDict;
11993 infoDict = OSDynamicCast(OSDictionary,
11994 codeless_kexts->getObject(i));
11995 if (!infoDict) {
11996 continue;
11997 }
11998 // instantiate a new kext, and don't hold a reference
11999 // (the kext subsystem will hold one implicitly)
12000 OSKext::withCodelessInfo(infoDict);
12001 }
12002 /* ignore errors that are not KC load failures */
12003 if (ret != kOSKextReturnKCLoadFailure) {
12004 ret = kOSReturnSuccess;
12005 }
12006 start_matching = true;
12007 }
12008
12009 /* send personalities to the IOCatalog once */
12010 if (ret == kOSReturnSuccess || start_matching || sOSKextWasResetAfterUserspaceReboot) {
12011 OSKext::sendAllKextPersonalitiesToCatalog(true);
12012 /*
12013 * This request necessarily came from the IOKit daemon (kernelmanagerd), so mark
12014 * things as active and start all the delayed matching: the
12015 * dext and codeless kext personalities should have all been
12016 * delivered via this one call.
12017 */
12018 if (!daemon_ready) {
12019 OSKext::setIOKitDaemonActive();
12020 OSKext::setDeferredLoadSucceeded(TRUE);
12021 IOService::iokitDaemonLaunched();
12022 }
12023 if (sOSKextWasResetAfterUserspaceReboot) {
12024 sOSKextWasResetAfterUserspaceReboot = false;
12025 OSKext::setIOKitDaemonActive();
12026 IOService::startDeferredMatches();
12027 }
12028 }
12029
12030 if (ret == kOSKextReturnKCLoadFailure) {
12031 ret |= kcerr;
12032 }
12033
12034 /*
12035 * Only allow this function to attempt to load the pageable and
12036 * aux KCs once per boot.
12037 */
12038 daemon_ready = true;
12039
12040 IORecursiveLockUnlock(sKextLock);
12041
12042 return ret;
12043 }
12044
12045 OSReturn
12046 OSKext::resetMutableSegments(void)
12047 {
12048 kernel_segment_command_t *seg = NULL;
12049 kernel_mach_header_t *k_mh = (kernel_mach_header_t *)kmod_info->address;
12050 u_int index = 0;
12051 OSKextSavedMutableSegment *savedSegment = NULL;
12052 uintptr_t kext_slide = PE_get_kc_slide(kc_type);
12053 OSReturn err;
12054
12055 if (!savedMutableSegments) {
12056 OSKextLog(this, kOSKextLogErrorLevel | kOSKextLogLoadFlag,
12057 "Kext %s cannot be reset, mutable segments were not saved.", getIdentifierCString());
12058 err = kOSKextReturnInternalError;
12059 goto finish;
12060 }
12061
12062 for (seg = firstsegfromheader(k_mh), index = 0; seg; seg = nextsegfromheader(k_mh, seg)) {
12063 if (!segmentIsMutable(seg)) {
12064 continue;
12065 }
12066 uint64_t unslid_vmaddr = seg->vmaddr - kext_slide;
12067 uint64_t vmsize = seg->vmsize;
12068 err = kOSKextReturnInternalError;
12069 for (index = 0; index < savedMutableSegments->getCount(); index++) {
12070 savedSegment = OSDynamicCast(OSKextSavedMutableSegment, savedMutableSegments->getObject(index));
12071 assert(savedSegment);
12072 if (savedSegment->getVMAddr() == seg->vmaddr && savedSegment->getVMSize() == seg->vmsize) {
12073 OSKextLog(this, kOSKextLogDebugLevel | kOSKextLogLoadFlag,
12074 "Resetting kext %s, mutable segment %.*s %llx->%llx.", getIdentifierCString(), (int)strnlen(seg->segname, sizeof(seg->segname)), seg->segname, unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12075 err = savedSegment->restoreContents(seg);
12076 if (err != kOSReturnSuccess) {
12077 panic("Kext %s cannot be reset, mutable segment %llx->%llx could not be restored.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12078 }
12079 }
12080 }
12081 if (err != kOSReturnSuccess) {
12082 panic("Kext %s cannot be reset, could not find saved mutable segment for %llx->%llx.", getIdentifierCString(), unslid_vmaddr, unslid_vmaddr + vmsize - 1);
12083 }
12084 }
12085 err = kOSReturnSuccess;
12086 finish:
12087 return err;
12088 }
12089
12090
12091 /*********************************************************************
12092 * Assumes sKextLock is held.
12093 *********************************************************************/
12094 /* static */
12095 OSReturn
12096 OSKext::loadKCFileSet(
12097 const char *filepath,
12098 kc_kind_t type)
12099 {
12100 #if VM_MAPPED_KEXTS
12101 /* we only need to load filesets on systems that support VM_MAPPED kexts */
12102 OSReturn err;
12103 struct vnode *vp = NULL;
12104 void *fileset_control;
12105 off_t fsize;
12106 bool pageable = (type == KCKindPageable);
12107
12108 if ((pageable && pageableKCloaded) ||
12109 (!pageable && auxKCloaded)) {
12110 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12111 "KC FileSet of type %s is already loaded", (pageable ? "Pageable" : "Aux"));
12112
12113 return kOSKextReturnInvalidArgument;
12114 }
12115
12116 /* Do not allow AuxKC to load if Pageable KC is not loaded */
12117 if (!pageable && !pageableKCloaded) {
12118 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12119 "Trying to load the Aux KC without loading the Pageable KC");
12120 return kOSKextReturnInvalidArgument;
12121 }
12122
12123 fileset_control = ubc_getobject_from_filename(filepath, &vp, &fsize);
12124
12125 if (fileset_control == NULL) {
12126 printf("Could not get memory control object for file %s", filepath);
12127
12128 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12129 "Could not get memory control object for file %s", filepath);
12130 return kOSKextReturnInvalidArgument;
12131 }
12132 if (vp == NULL) {
12133 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12134 "Could not find vnode for file %s", filepath);
12135 return kOSKextReturnInvalidArgument;
12136 }
12137
12138 kernel_mach_header_t *mh = NULL;
12139 uintptr_t slide = 0;
12140
12141 #if CONFIG_CSR
12142 /*
12143 * When SIP is enabled, the KC we map must be SIP-protected
12144 */
12145 if (csr_check(CSR_ALLOW_UNRESTRICTED_FS) != 0) {
12146 struct vnode_attr va;
12147 int error;
12148 VATTR_INIT(&va);
12149 VATTR_WANTED(&va, va_flags);
12150 error = vnode_getattr(vp, &va, vfs_context_current());
12151 if (error) {
12152 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12153 "vnode_getattr(%s) failed (error=%d)", filepath, error);
12154 err = kOSKextReturnInternalError;
12155 goto finish;
12156 }
12157 if (!(va.va_flags & SF_RESTRICTED)) {
12158 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12159 "Path to KC '%s' is not SIP-protected", filepath);
12160 err = kOSKextReturnInvalidArgument;
12161 goto finish;
12162 }
12163 }
12164 #endif
12165
12166 err = OSKext::mapKCFileSet(fileset_control, (vm_size_t)fsize, &mh, 0, &slide, pageable, NULL);
12167 if (err) {
12168 printf("KextLog: mapKCFileSet returned %d\n", err);
12169
12170 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12171 "mapKCFileSet returned %d\n", err);
12172
12173 err = kOSKextReturnInvalidArgument;
12174 }
12175
12176 #if CONFIG_CSR
12177 finish:
12178 #endif
12179 /* Drop the vnode ref returned by ubc_getobject_from_filename if mapKCFileSet failed */
12180 assert(vp != NULL);
12181 if (err == kOSReturnSuccess) {
12182 PE_set_kc_vp(type, vp);
12183 if (pageable) {
12184 pageableKCloaded = true;
12185 } else {
12186 auxKCloaded = true;
12187 }
12188 } else {
12189 vnode_put(vp);
12190 }
12191
12192 return err;
12193 #else
12194 (void)filepath;
12195 (void)type;
12196 return kOSKextReturnUnsupported;
12197 #endif // VM_MAPPED_KEXTS
12198 }
12199
12200 #if defined(__x86_64__) || defined(__i386__)
12201 /*********************************************************************
12202 * Assumes sKextLock is held.
12203 *********************************************************************/
12204 /* static */
12205 OSReturn
12206 OSKext::mapKCFileSet(
12207 void *control,
12208 vm_size_t fsize,
12209 kernel_mach_header_t **mhp,
12210 off_t file_offset,
12211 uintptr_t *slidep,
12212 bool pageable,
12213 void *map_entry_list)
12214 {
12215 bool fileset_load = false;
12216 kern_return_t ret;
12217 OSReturn err;
12218 kernel_section_t *infoPlistSection = NULL;
12219 OSDictionary *infoDict = NULL;
12220
12221 OSSharedPtr<OSObject> parsedXML;
12222 OSSharedPtr<OSString> errorString;
12223 OSSharedPtr<OSData> loaded_kcUUID;
12224
12225 /* Check if initial load for file set */
12226 if (*mhp == NULL) {
12227 fileset_load = true;
12228
12229 /* Get a page aligned address from kext map to map the file */
12230 vm_map_offset_t pagealigned_addr = get_address_from_kext_map(fsize);
12231 if (pagealigned_addr == 0) {
12232 return kOSKextReturnNoMemory;
12233 }
12234
12235 *mhp = (kernel_mach_header_t *)pagealigned_addr;
12236
12237 /* Allocate memory for bailout mechanism */
12238 map_entry_list = allocate_kcfileset_map_entry_list();
12239 if (map_entry_list == NULL) {
12240 return kOSKextReturnNoMemory;
12241 }
12242 }
12243
12244 uintptr_t *slideptr = fileset_load ? slidep : NULL;
12245 err = mapKCTextSegment(control, mhp, file_offset, slideptr, map_entry_list);
12246 /* mhp and slideptr are updated by mapKCTextSegment */
12247 if (err) {
12248 if (fileset_load) {
12249 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12250 }
12251 return err;
12252 }
12253
12254 /* Initialize the kc header globals */
12255 if (fileset_load) {
12256 if (pageable) {
12257 PE_set_kc_header(KCKindPageable, *mhp, *slidep);
12258 } else {
12259 PE_set_kc_header(KCKindAuxiliary, *mhp, *slidep);
12260 }
12261 }
12262
12263 /* Iterate through all the segments and map necessary segments */
12264 struct load_command *lcp = (struct load_command *) (*mhp + 1);
12265 for (unsigned int i = 0; i < (*mhp)->ncmds; i++, lcp = (struct load_command *)((uintptr_t)lcp + lcp->cmdsize)) {
12266 vm_map_offset_t start;
12267 kernel_mach_header_t *k_mh = NULL;
12268 kernel_segment_command_t * seg = NULL;
12269 struct fileset_entry_command *fse = NULL;
12270
12271 if (lcp->cmd == LC_SEGMENT_KERNEL) {
12272 seg = (kernel_segment_command_t *)lcp;
12273 start = ((uintptr_t)(seg->vmaddr)) + *slidep;
12274 } else if (lcp->cmd == LC_FILESET_ENTRY) {
12275 fse = (struct fileset_entry_command *)lcp;
12276 k_mh = (kernel_mach_header_t *)(((uintptr_t)(fse->vmaddr)) + *slidep);
12277
12278 /* Map the segments of the mach-o binary */
12279 err = OSKext::mapKCFileSet(control, 0, &k_mh, fse->fileoff, slidep, pageable, map_entry_list);
12280 if (err) {
12281 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12282 return kOSKextReturnInvalidArgument;
12283 }
12284 continue;
12285 } else if (lcp->cmd == LC_DYLD_CHAINED_FIXUPS) {
12286 /* Check if the Aux KC is built pageable style */
12287 if (!pageable && !fileset_load && !auxKCloaded) {
12288 resetAuxKCSegmentOnUnload = true;
12289 }
12290 continue;
12291 } else {
12292 continue;
12293 }
12294
12295 if (fileset_load) {
12296 if (seg->vmsize == 0) {
12297 continue;
12298 }
12299
12300 /* Only map __PRELINK_INFO, __BRANCH_STUBS, __BRANCH_GOTS and __LINKEDIT sections */
12301 if (strncmp(seg->segname, kPrelinkInfoSegment, sizeof(seg->segname)) != 0 &&
12302 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) != 0 &&
12303 strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) != 0 &&
12304 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) != 0) {
12305 continue;
12306 }
12307 } else {
12308 if (seg->vmsize == 0) {
12309 continue;
12310 }
12311
12312 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12313 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12314 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12315 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12316 continue;
12317 }
12318 }
12319
12320 ret = vm_map_kcfileset_segment(
12321 &start, seg->vmsize,
12322 (memory_object_control_t)control, seg->fileoff, seg->maxprot);
12323
12324 if (ret != KERN_SUCCESS) {
12325 if (fileset_load) {
12326 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12327 }
12328 return kOSKextReturnInvalidArgument;
12329 }
12330 add_kcfileset_map_entry(map_entry_list, start, seg->vmsize);
12331 }
12332
12333 /* Return if regular mach-o */
12334 if (!fileset_load) {
12335 return 0;
12336 }
12337
12338 /*
12339 * Fixup for the Pageable KC and the Aux KC is done by
12340 * i386_slide_kext_collection_mh_addrs, but it differs in
12341 * following ways:
12342 *
12343 * PageableKC: Fixup only __BRANCH_STUBS segment and top level load commands.
12344 * The fixup of kext segments and kext load commands are done at kext
12345 * load time by calling i386_slide_individual_kext.
12346 *
12347 * AuxKC old style: Fixup all the segments and all the load commands.
12348 *
12349 * AuxKC pageable style: Same as the Pageable KC.
12350 */
12351 bool adjust_mach_header = (pageable ? true : ((resetAuxKCSegmentOnUnload) ? true : false));
12352 ret = i386_slide_kext_collection_mh_addrs(*mhp, *slidep, adjust_mach_header);
12353 if (ret != KERN_SUCCESS) {
12354 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12355 return kOSKextReturnInvalidArgument;
12356 }
12357
12358 /* Get the prelink info dictionary */
12359 infoPlistSection = getsectbynamefromheader(*mhp, kPrelinkInfoSegment, kPrelinkInfoSection);
12360 parsedXML = OSUnserializeXML((const char *)infoPlistSection->addr, errorString);
12361 if (parsedXML) {
12362 infoDict = OSDynamicCast(OSDictionary, parsedXML.get());
12363 }
12364
12365 if (!infoDict) {
12366 const char *errorCString = "(unknown error)";
12367
12368 if (errorString && errorString->getCStringNoCopy()) {
12369 errorCString = errorString->getCStringNoCopy();
12370 } else if (parsedXML) {
12371 errorCString = "not a dictionary";
12372 }
12373 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12374 "Error unserializing kext info plist section: %s.", errorCString);
12375 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12376 return kOSKextReturnInvalidArgument;
12377 }
12378
12379 /* Validate that the Kext Collection is prelinked to the loaded KC */
12380 err = OSKext::validateKCFileSetUUID(infoDict, pageable ? KCKindPageable : KCKindAuxiliary);
12381 if (err) {
12382 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, TRUE, pageable);
12383 return kOSKextReturnInvalidArgument;
12384 }
12385
12386 /* Set Protection of Segments */
12387 OSKext::protectKCFileSet(*mhp, pageable ? KCKindPageable : KCKindAuxiliary);
12388
12389 OSKext::addKextsFromKextCollection(*mhp,
12390 infoDict, kPrelinkTextSegment,
12391 loaded_kcUUID, pageable ? KCKindPageable : KCKindAuxiliary);
12392
12393 /* Copy in the KC UUID */
12394 if (!loaded_kcUUID) {
12395 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12396 "WARNING: did not find UUID in prelinked %s KC!", pageable ? "Pageable" : "Aux");
12397 } else if (pageable) {
12398 pageablekc_uuid_valid = TRUE;
12399 memcpy((void *)&pageablekc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12400 uuid_unparse_upper(pageablekc_uuid, pageablekc_uuid_string);
12401 } else {
12402 auxkc_uuid_valid = TRUE;
12403 memcpy((void *)&auxkc_uuid, (const void *)loaded_kcUUID->getBytesNoCopy(), loaded_kcUUID->getLength());
12404 uuid_unparse_upper(auxkc_uuid, auxkc_uuid_string);
12405 }
12406
12407 deallocate_kcfileset_map_entry_list_and_unmap_entries(map_entry_list, FALSE, pageable);
12408
12409 return 0;
12410 }
12411
12412 /*********************************************************************
12413 * Assumes sKextLock is held.
12414 *********************************************************************/
12415 /* static */
12416 OSReturn
12417 OSKext::mapKCTextSegment(
12418 void *control,
12419 kernel_mach_header_t **mhp,
12420 off_t file_offset,
12421 uintptr_t *slidep,
12422 void *map_entry_list)
12423 {
12424 kern_return_t ret;
12425 vm_map_offset_t mach_header_map_size = vm_map_round_page(sizeof(kernel_mach_header_t),
12426 PAGE_MASK);
12427 vm_map_offset_t load_command_map_size = 0;
12428 kernel_mach_header_t *base_mh = *mhp;
12429
12430 /* Map the mach header at start of fileset for now (vmaddr = 0) */
12431 ret = vm_map_kcfileset_segment(
12432 (vm_map_offset_t *)&base_mh, mach_header_map_size,
12433 (memory_object_control_t)control, file_offset, (VM_PROT_READ | VM_PROT_WRITE));
12434
12435 if (ret != KERN_SUCCESS) {
12436 printf("Kext Log: mapKCTextSegment failed to map mach header of fileset %x", ret);
12437
12438 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12439 "Failed to map mach header of kc fileset with error %d", ret);
12440 return kOSKextReturnInvalidArgument;
12441 }
12442
12443 if (slidep) {
12444 /* Verify that it's an MH_FILESET */
12445 if (base_mh->filetype != MH_FILESET) {
12446 printf("Kext Log: mapKCTextSegment mach header filetype"
12447 " is not an MH_FILESET, it is %x", base_mh->filetype);
12448
12449 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12450 "mapKCTextSegment mach header filetype is not an MH_FILESET, it is %x", base_mh->filetype);
12451
12452 /* Unmap the mach header */
12453 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12454 return kOSKextReturnInvalidArgument;
12455 }
12456 }
12457
12458 /* Map the remaining pages of load commands */
12459 if (base_mh->sizeofcmds > mach_header_map_size) {
12460 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12461 load_command_map_size = base_mh->sizeofcmds - mach_header_map_size;
12462
12463 /* Map the load commands */
12464 ret = vm_map_kcfileset_segment(
12465 &load_command_addr, load_command_map_size,
12466 (memory_object_control_t)control, file_offset + mach_header_map_size,
12467 (VM_PROT_READ | VM_PROT_WRITE));
12468
12469 if (ret != KERN_SUCCESS) {
12470 printf("KextLog: mapKCTextSegment failed to map load commands of fileset %x", ret);
12471 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12472 "Failed to map load commands of kc fileset with error %d", ret);
12473
12474 /* Unmap the mach header */
12475 vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12476 return kOSKextReturnInvalidArgument;
12477 }
12478 }
12479
12480 kernel_segment_command_t *text_seg;
12481 text_seg = getsegbynamefromheader((kernel_mach_header_t *)base_mh, SEG_TEXT);
12482
12483 /* Calculate the slide and vm addr of mach header */
12484 if (slidep) {
12485 *mhp = (kernel_mach_header_t *)((uintptr_t)base_mh + text_seg->vmaddr);
12486 *slidep = ((uintptr_t)*mhp) - text_seg->vmaddr;
12487 }
12488
12489 /* Cache the text segment size and file offset before unmapping */
12490 vm_map_offset_t text_segment_size = text_seg->vmsize;
12491 vm_object_offset_t text_segment_fileoff = text_seg->fileoff;
12492 vm_prot_t text_maxprot = text_seg->maxprot;
12493
12494 /* Unmap the first page and loadcommands and map the text segment */
12495 ret = vm_unmap_kcfileset_segment((vm_map_offset_t *)&base_mh, mach_header_map_size);
12496 assert(ret == KERN_SUCCESS);
12497
12498 if (load_command_map_size) {
12499 vm_map_offset_t load_command_addr = ((vm_map_offset_t)base_mh) + mach_header_map_size;
12500 ret = vm_unmap_kcfileset_segment(&load_command_addr, load_command_map_size);
12501 assert(ret == KERN_SUCCESS);
12502 }
12503
12504 /* Map the text segment at actual vm addr specified in fileset */
12505 ret = vm_map_kcfileset_segment((vm_map_offset_t *)mhp, text_segment_size,
12506 (memory_object_control_t)control, text_segment_fileoff, text_maxprot);
12507 if (ret != KERN_SUCCESS) {
12508 OSKextLog(/* kext */ NULL, kOSKextLogDebugLevel | kOSKextLogIPCFlag,
12509 "Failed to map Text segment of kc fileset with error %d", ret);
12510 return kOSKextReturnInvalidArgument;
12511 }
12512
12513 add_kcfileset_map_entry(map_entry_list, (vm_map_offset_t)*mhp, text_segment_size);
12514 return 0;
12515 }
12516
12517 /*********************************************************************
12518 * Assumes sKextLock is held.
12519 *********************************************************************/
12520 /* static */
12521 OSReturn
12522 OSKext::protectKCFileSet(
12523 kernel_mach_header_t *mh,
12524 kc_kind_t type)
12525 {
12526 vm_map_t kext_map = g_kext_map;
12527 kernel_segment_command_t * seg = NULL;
12528 vm_map_offset_t start = 0;
12529 vm_map_offset_t end = 0;
12530 OSReturn ret = 0;
12531
12532 /* Set VM permissions */
12533 seg = firstsegfromheader((kernel_mach_header_t *)mh);
12534 while (seg) {
12535 start = round_page(seg->vmaddr);
12536 end = trunc_page(seg->vmaddr + seg->vmsize);
12537
12538 /*
12539 * Wire down and protect __TEXT, __BRANCH_STUBS and __BRANCH_GOTS
12540 * for the Pageable KC and the Aux KC, wire down and protect __LINKEDIT
12541 * for the Aux KC as well.
12542 */
12543 if (strncmp(seg->segname, kKCBranchGots, sizeof(seg->segname)) == 0 ||
12544 strncmp(seg->segname, kKCBranchStubs, sizeof(seg->segname)) == 0 ||
12545 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0 ||
12546 (type == KCKindAuxiliary && !resetAuxKCSegmentOnUnload &&
12547 strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0)) {
12548 ret = OSKext_protect((kernel_mach_header_t *)mh,
12549 kext_map, start, end, seg->maxprot, TRUE, type);
12550 if (ret != KERN_SUCCESS) {
12551 printf("OSKext protect failed with error %d", ret);
12552 return kOSKextReturnInvalidArgument;
12553 }
12554
12555 ret = OSKext_protect((kernel_mach_header_t *)mh,
12556 kext_map, start, end, seg->initprot, FALSE, type);
12557 if (ret != KERN_SUCCESS) {
12558 printf("OSKext protect failed with error %d", ret);
12559 return kOSKextReturnInvalidArgument;
12560 }
12561
12562 ret = OSKext_wire((kernel_mach_header_t *)mh,
12563 kext_map, start, end, seg->initprot, FALSE, type);
12564 if (ret != KERN_SUCCESS) {
12565 printf("OSKext wire failed with error %d", ret);
12566 return kOSKextReturnInvalidArgument;
12567 }
12568 }
12569
12570 seg = nextsegfromheader((kernel_mach_header_t *) mh, seg);
12571 }
12572
12573 return 0;
12574 }
12575
12576 /*********************************************************************
12577 * Assumes sKextLock is held.
12578 *********************************************************************/
12579 /* static */
12580 void
12581 OSKext::freeKCFileSetcontrol(void)
12582 {
12583 PE_reset_all_kc_vp();
12584 }
12585
12586 /*********************************************************************
12587 * Assumes sKextLock is held.
12588 *
12589 * resetKCFileSetSegments: Kext start function expects data segment to
12590 * be pristine on every load, unmap the dirty segments on unload and
12591 * remap them from FileSet on disk. Remap all segments of kext since
12592 * fixups are done per kext and not per segment.
12593 *********************************************************************/
12594 OSReturn
12595 OSKext::resetKCFileSetSegments(void)
12596 {
12597 kernel_segment_command_t *seg = NULL;
12598 kernel_segment_command_t *text_seg;
12599 uint32_t text_fileoff;
12600 kernel_mach_header_t *k_mh = NULL;
12601 uintptr_t slide;
12602 struct vnode *vp = NULL;
12603 void *fileset_control = NULL;
12604 bool pageable = (kc_type == KCKindPageable);
12605 OSReturn err;
12606 kern_return_t kr;
12607
12608 /* Check the vnode reference is still available */
12609 vp = (struct vnode *)PE_get_kc_vp(kc_type);
12610 if (vp == NULL) {
12611 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12612 "Kext %s could not be reset, since reboot released the vnode ref", getIdentifierCString());
12613 return kOSKextReturnInternalError;
12614 }
12615
12616 fileset_control = ubc_getobject(vp, 0);
12617 assert(fileset_control != NULL);
12618
12619 OSKextLog(this, kOSKextLogProgressLevel | kOSKextLogLoadFlag,
12620 "Kext %s resetting all segments", getIdentifierCString());
12621
12622 k_mh = (kernel_mach_header_t *)kmod_info->address;
12623 text_seg = getsegbynamefromheader((kernel_mach_header_t *)kmod_info->address, SEG_TEXT);
12624 text_fileoff = text_seg->fileoff;
12625 slide = PE_get_kc_slide(kc_type);
12626
12627 seg = firstsegfromheader((kernel_mach_header_t *)k_mh);
12628 while (seg) {
12629 if (seg->vmsize == 0) {
12630 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12631 continue;
12632 }
12633
12634 /* Skip the __LINKEDIT, __LINKINFO and __TEXT segments */
12635 if (strncmp(seg->segname, SEG_LINKEDIT, sizeof(seg->segname)) == 0 ||
12636 strncmp(seg->segname, SEG_LINKINFO, sizeof(seg->segname)) == 0 ||
12637 strncmp(seg->segname, SEG_TEXT, sizeof(seg->segname)) == 0) {
12638 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12639 continue;
12640 }
12641
12642 kr = vm_unmap_kcfileset_segment(&seg->vmaddr, seg->vmsize);
12643 assert(kr == KERN_SUCCESS);
12644 seg = nextsegfromheader((kernel_mach_header_t *) k_mh, seg);
12645 }
12646
12647 /* Unmap the text segment */
12648 kr = vm_unmap_kcfileset_segment(&text_seg->vmaddr, text_seg->vmsize);
12649 assert(kr == KERN_SUCCESS);
12650
12651 /* Map all the segments of the kext */
12652 err = OSKext::mapKCFileSet(fileset_control, 0, &k_mh, text_fileoff, &slide, pageable, NULL);
12653 if (err) {
12654 panic("Could not reset segments of a mapped kext, error %x", err);
12655 }
12656
12657 /* Update address in kmod_info, since it has been reset */
12658 if (kmod_info->address) {
12659 kmod_info->address = (((uintptr_t)(kmod_info->address)) + slide);
12660 }
12661
12662 return 0;
12663 }
12664
12665 /*********************************************************************
12666 * Mechanism to track all segment mapping while mapping KC fileset.
12667 *********************************************************************/
12668
12669 struct kcfileset_map_entry {
12670 vm_map_offset_t me_start;
12671 vm_map_offset_t me_size;
12672 };
12673
12674 struct kcfileset_map_entry_list {
12675 int kme_list_count;
12676 int kme_list_index;
12677 struct kcfileset_map_entry kme_list[];
12678 };
12679
12680 #define KCFILESET_MAP_ENTRY_MAX (16380)
12681
12682 static void *
12683 allocate_kcfileset_map_entry_list(void)
12684 {
12685 struct kcfileset_map_entry_list *entry_list;
12686
12687 entry_list = (struct kcfileset_map_entry_list *)kalloc(sizeof(struct kcfileset_map_entry_list) +
12688 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12689
12690 entry_list->kme_list_count = KCFILESET_MAP_ENTRY_MAX;
12691 entry_list->kme_list_index = 0;
12692 return entry_list;
12693 }
12694
12695 static void
12696 add_kcfileset_map_entry(
12697 void *map_entry_list,
12698 vm_map_offset_t start,
12699 vm_map_offset_t size)
12700 {
12701 if (map_entry_list == NULL) {
12702 return;
12703 }
12704
12705 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12706
12707 if (entry_list->kme_list_index >= entry_list->kme_list_count) {
12708 panic("Ran out of map kc fileset list\n");
12709 }
12710
12711 entry_list->kme_list[entry_list->kme_list_index].me_start = start;
12712 entry_list->kme_list[entry_list->kme_list_index].me_size = size;
12713
12714 entry_list->kme_list_index++;
12715 }
12716
12717 static void
12718 deallocate_kcfileset_map_entry_list_and_unmap_entries(
12719 void *map_entry_list,
12720 boolean_t unmap_entries,
12721 bool pageable)
12722 {
12723 struct kcfileset_map_entry_list *entry_list = (struct kcfileset_map_entry_list *)map_entry_list;
12724
12725 if (unmap_entries) {
12726 for (int i = 0; i < entry_list->kme_list_index; i++) {
12727 kern_return_t ret;
12728 ret = vm_unmap_kcfileset_segment(
12729 &(entry_list->kme_list[i].me_start),
12730 entry_list->kme_list[i].me_size);
12731 assert(ret == KERN_SUCCESS);
12732 }
12733
12734 PE_reset_kc_header(pageable ? KCKindPageable : KCKindAuxiliary);
12735 }
12736
12737 kfree(entry_list, sizeof(struct kcfileset_map_entry_list) +
12738 (sizeof(struct kcfileset_map_entry) * KCFILESET_MAP_ENTRY_MAX));
12739 }
12740
12741 /*********************************************************************
12742 * Mechanism to map kext segment.
12743 *********************************************************************/
12744
12745 kern_return_t
12746 vm_map_kcfileset_segment(
12747 vm_map_offset_t *start,
12748 vm_map_offset_t size,
12749 void *control,
12750 vm_object_offset_t fileoffset,
12751 vm_prot_t max_prot)
12752 {
12753 vm_map_kernel_flags_t vmk_flags;
12754 vmk_flags.vmkf_no_copy_on_read = 1;
12755 vmk_flags.vmkf_cs_enforcement = 0;
12756 vmk_flags.vmkf_cs_enforcement_override = 1;
12757 kern_return_t ret;
12758
12759 /* Add Write to max prot to allow fixups */
12760 max_prot = max_prot | VM_PROT_WRITE;
12761
12762 /*
12763 * Map the segments from file as COPY mappings to
12764 * make sure changes on disk to the file does not affect
12765 * mapped segments.
12766 */
12767 ret = vm_map_enter_mem_object_control(
12768 g_kext_map,
12769 start,
12770 size,
12771 (mach_vm_offset_t)0,
12772 VM_FLAGS_FIXED,
12773 vmk_flags,
12774 VM_KERN_MEMORY_OSKEXT,
12775 (memory_object_control_t)control,
12776 fileoffset,
12777 TRUE, /* copy */
12778 (VM_PROT_READ | VM_PROT_WRITE), max_prot,
12779 VM_INHERIT_NONE);
12780
12781 return ret;
12782 }
12783
12784 kern_return_t
12785 vm_unmap_kcfileset_segment(
12786 vm_map_offset_t *start,
12787 vm_map_offset_t size)
12788 {
12789 return mach_vm_deallocate(g_kext_map, *start, size);
12790 }
12791
12792 #endif //(__x86_64__) || defined(__i386__)
12793
12794 /*********************************************************************
12795 * Assumes sKextLock is held.
12796 *********************************************************************/
12797 /* static */
12798 OSReturn
12799 OSKext::validateKCFileSetUUID(
12800 OSDictionary *infoDict,
12801 kc_kind_t type)
12802 {
12803 OSReturn ret = kOSReturnSuccess;
12804
12805 if (!kernelcache_uuid_valid) {
12806 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12807 "validateKCFileSetUUID Boot KC UUID was not set at boot.");
12808 ret = kOSKextReturnInvalidArgument;
12809 goto finish;
12810 }
12811 ret = OSKext::validateKCUUIDfromPrelinkInfo(&kernelcache_uuid, type, infoDict, kPrelinkInfoBootKCIDKey);
12812 if (ret != 0) {
12813 goto finish;
12814 }
12815
12816 #if defined(__x86_64__) || defined(__i386__)
12817 /* Check if the Aux KC is prelinked to correct Pageable KC */
12818 if (type == KCKindAuxiliary) {
12819 if (!pageablekc_uuid_valid) {
12820 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12821 "validateKCFileSetUUID Pageable KC UUID was not set while loading Pageable KC.");
12822 ret = kOSKextReturnInvalidArgument;
12823 goto finish;
12824 }
12825 ret = OSKext::validateKCUUIDfromPrelinkInfo(&pageablekc_uuid, type, infoDict, kPrelinkInfoPageableKCIDKey);
12826 if (ret != 0) {
12827 goto finish;
12828 }
12829 }
12830 #endif //(__x86_64__) || defined(__i386__)
12831
12832 printf("KextLog: Collection UUID matches with loaded KCs.\n");
12833 finish:
12834 return ret;
12835 }
12836
12837 /*********************************************************************
12838 * Assumes sKextLock is held.
12839 *********************************************************************/
12840 /* static */
12841 OSReturn
12842 OSKext::validateKCUUIDfromPrelinkInfo(
12843 uuid_t *loaded_kcuuid,
12844 kc_kind_t type,
12845 OSDictionary *infoDict,
12846 const char *uuid_key)
12847 {
12848 /* extract the UUID from the dictionary */
12849 OSData *prelinkinfoKCUUID = OSDynamicCast(OSData, infoDict->getObject(uuid_key));
12850 if (!prelinkinfoKCUUID) {
12851 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12852 "validateKCUUID Info plist does not contain %s KC UUID key.", uuid_key);
12853 return kOSKextReturnInvalidArgument;
12854 }
12855
12856 if (prelinkinfoKCUUID->getLength() != sizeof(uuid_t)) {
12857 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12858 "validateKCUUID %s KC UUID has wrong length: %d.", uuid_key, prelinkinfoKCUUID->getLength());
12859 return kOSKextReturnInvalidArgument;
12860 }
12861
12862 if (memcmp((void *)loaded_kcuuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(),
12863 prelinkinfoKCUUID->getLength())) {
12864 OSData *info_dict_uuid;
12865 uuid_string_t info_dict_uuid_str = {};
12866 uuid_string_t expected_uuid_str = {};
12867 uuid_string_t given_uuid_str = {};
12868 uuid_t given_uuid;
12869
12870 /* extract the KC UUID from the dictionary */
12871 info_dict_uuid = OSDynamicCast(OSData, infoDict->getObject(kPrelinkInfoKCIDKey));
12872 if (info_dict_uuid && info_dict_uuid->getLength() == sizeof(uuid_t)) {
12873 uuid_t tmp_uuid;
12874 memcpy(tmp_uuid, (const void *)info_dict_uuid->getBytesNoCopy(), sizeof(tmp_uuid));
12875 uuid_unparse(tmp_uuid, info_dict_uuid_str);
12876 }
12877
12878 uuid_unparse(*loaded_kcuuid, expected_uuid_str);
12879 memcpy(given_uuid, (const void *)prelinkinfoKCUUID->getBytesNoCopy(), sizeof(given_uuid));
12880 uuid_unparse(given_uuid, given_uuid_str);
12881
12882 printf("KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12883 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12884 OSKextLog(/* kext */ NULL, kOSKextLogErrorLevel | kOSKextLogArchiveFlag,
12885 "KextLog: ERROR: UUID from key:%s %s != expected %s (KC UUID: %s)\n", uuid_key,
12886 given_uuid_str, expected_uuid_str, info_dict_uuid_str);
12887 if (type == KCKindPageable && sPanicOnKCMismatch) {
12888 panic("System KC UUID %s linked against %s, but %s is loaded",
12889 info_dict_uuid_str, given_uuid_str, expected_uuid_str);
12890 }
12891 return kOSKextReturnInvalidArgument;
12892 }
12893
12894 return 0;
12895 }
12896
12897 /*********************************************************************
12898 * Assumes sKextLock is held.
12899 *********************************************************************/
12900 /* static */
12901 OSReturn
12902 OSKext::dispatchResource(OSDictionary * requestDict)
12903 {
12904 OSReturn result = kOSReturnError;
12905 OSSharedPtr<OSDictionary> callbackRecord;
12906 OSNumber * requestTag = NULL; // do not release
12907 OSNumber * requestResult = NULL; // do not release
12908 OSData * dataObj = NULL; // do not release
12909 uint32_t dataLength = 0;
12910 const void * dataPtr = NULL; // do not free
12911 OSData * callbackWrapper = NULL; // do not release
12912 OSKextRequestResourceCallback callback = NULL;
12913 OSData * contextWrapper = NULL; // do not release
12914 void * context = NULL; // do not free
12915 OSSharedPtr<OSKext> callbackKext;
12916
12917 /* Get the args from the request. Right now we need the tag
12918 * to look up the callback record, and the result for invoking the callback.
12919 */
12920 requestTag = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12921 kKextRequestArgumentRequestTagKey));
12922 requestResult = OSDynamicCast(OSNumber, _OSKextGetRequestArgument(requestDict,
12923 kKextRequestArgumentResultKey));
12924 if (!requestTag || !requestResult) {
12925 result = kOSKextReturnInvalidArgument;
12926 goto finish;
12927 }
12928
12929 /* Look for a callback record matching this request's tag.
12930 */
12931 result = dequeueCallbackForRequestTag(requestTag, callbackRecord);
12932 if (result != kOSReturnSuccess) {
12933 goto finish;
12934 }
12935
12936 /*****
12937 * Get the context pointer of the callback record (if there is one).
12938 */
12939 contextWrapper = OSDynamicCast(OSData, _OSKextGetRequestArgument(callbackRecord.get(),
12940 kKextRequestArgumentContextKey));
12941 context = _OSKextExtractPointer(contextWrapper);
12942 if (contextWrapper && !context) {
12943 goto finish;
12944 }
12945
12946 callbackWrapper = OSDynamicCast(OSData,
12947 _OSKextGetRequestArgument(callbackRecord.get(),
12948 kKextRequestArgumentCallbackKey));
12949 callback = _OSKextExtractCallbackPointer(callbackWrapper);
12950 if (!callback) {
12951 goto finish;
12952 }
12953
12954 /* Check for a data obj. We might not have one and that's ok, that means
12955 * we didn't find the requested resource, and we still have to tell the
12956 * caller that via the callback.
12957 */
12958 dataObj = OSDynamicCast(OSData, _OSKextGetRequestArgument(requestDict,
12959 kKextRequestArgumentValueKey));
12960 if (dataObj) {
12961 dataPtr = dataObj->getBytesNoCopy();
12962 dataLength = dataObj->getLength();
12963 }
12964
12965 callbackKext = OSKext::lookupKextWithAddress((vm_address_t)callback);
12966 if (!callbackKext) {
12967 OSKextLog(/* kext */ NULL,
12968 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12969 "Can't invoke callback for resource request; ");
12970 goto finish;
12971 }
12972 if (!callbackKext->flags.starting && !callbackKext->flags.started) {
12973 OSKextLog(/* kext */ NULL,
12974 kOSKextLogErrorLevel | kOSKextLogIPCFlag,
12975 "Can't invoke kext resource callback; ");
12976 goto finish;
12977 }
12978
12979 (void)callback(requestTag->unsigned32BitValue(),
12980 (OSReturn)requestResult->unsigned32BitValue(),
12981 dataPtr, dataLength, context);
12982
12983 result = kOSReturnSuccess;
12984
12985 finish:
12986 return result;
12987 }
12988
12989 /*********************************************************************
12990 * Assumes sKextLock is held.
12991 *********************************************************************/
12992 /* static */
12993 OSReturn
12994 OSKext::setMissingAuxKCBundles(OSDictionary * requestDict)
12995 {
12996 OSSharedPtr<OSDictionary> missingIDs;
12997 OSArray *bundleIDList = NULL; // do not release
12998
12999 bundleIDList = OSDynamicCast(OSArray, _OSKextGetRequestArgument(
13000 requestDict, kKextRequestArgumentMissingBundleIDs));
13001 if (!bundleIDList) {
13002 return kOSKextReturnInvalidArgument;
13003 }
13004
13005 missingIDs = OSDictionary::withCapacity(bundleIDList->getCount());
13006 if (!missingIDs) {
13007 return kOSKextReturnNoMemory;
13008 }
13009
13010 uint32_t count, i;
13011 count = bundleIDList->getCount();
13012 for (i = 0; i < count; i++) {
13013 OSString *thisID = OSDynamicCast(OSString, bundleIDList->getObject(i));
13014 if (thisID) {
13015 missingIDs->setObject(thisID, kOSBooleanFalse);
13016 }
13017 }
13018
13019 sNonLoadableKextsByID.reset(missingIDs.get(), OSRetain);
13020
13021 return kOSReturnSuccess;
13022 }
13023
13024 /*********************************************************************
13025 * Assumes sKextLock is held.
13026 *********************************************************************/
13027 /* static */
13028 OSReturn
13029 OSKext::setAuxKCBundleAvailable(OSString *kextIdentifier, OSDictionary *requestDict)
13030 {
13031 bool loadable = true;
13032 if (!kextIdentifier) {
13033 return kOSKextReturnInvalidArgument;
13034 }
13035
13036 if (requestDict) {
13037 OSBoolean *loadableArg;
13038 loadableArg = OSDynamicCast(OSBoolean, _OSKextGetRequestArgument(
13039 requestDict, kKextRequestArgumentBundleAvailability));
13040 /* If we find the "Bundle Available" arg, and it's false, then
13041 * mark the bundle ID as _not_ loadable
13042 */
13043 if (loadableArg && !loadableArg->getValue()) {
13044 loadable = false;
13045 }
13046 }
13047
13048 if (!sNonLoadableKextsByID) {
13049 sNonLoadableKextsByID = OSDictionary::withCapacity(1);
13050 }
13051
13052 sNonLoadableKextsByID->setObject(kextIdentifier, OSBoolean::withBoolean(loadable));
13053
13054 OSKextLog(/* kext */ NULL,
13055 kOSKextLogBasicLevel | kOSKextLogIPCFlag,
13056 "KextLog: AuxKC bundle %s marked as %s",
13057 kextIdentifier->getCStringNoCopy(),
13058 (loadable ? "loadable" : "NOT loadable"));
13059
13060 return kOSReturnSuccess;
13061 }
13062
13063 /*********************************************************************
13064 *********************************************************************/
13065 /* static */
13066 void
13067 OSKext::invokeRequestCallback(
13068 OSDictionary * callbackRecord,
13069 OSReturn callbackResult)
13070 {
13071 OSString * predicate = _OSKextGetRequestPredicate(callbackRecord);
13072 OSSharedPtr<OSNumber> resultNum;
13073
13074 if (!predicate) {
13075 goto finish;
13076 }
13077
13078 resultNum = OSNumber::withNumber((long long unsigned int)callbackResult,
13079 8 * sizeof(callbackResult));
13080 if (!resultNum) {
13081 goto finish;
13082 }
13083
13084 /* Insert the result into the callback record and dispatch it as if it
13085 * were the reply coming down from user space.
13086 */
13087 _OSKextSetRequestArgument(callbackRecord, kKextRequestArgumentResultKey,
13088 resultNum.get());
13089
13090 if (predicate->isEqualTo(kKextRequestPredicateRequestResource)) {
13091 /* This removes the pending callback record.
13092 */
13093 OSKext::dispatchResource(callbackRecord);
13094 }
13095
13096 finish:
13097 return;
13098 }
13099
13100 /*********************************************************************
13101 * Assumes sKextLock is held.
13102 *********************************************************************/
13103 /* static */
13104 OSReturn
13105 OSKext::cancelRequest(
13106 OSKextRequestTag requestTag,
13107 void ** contextOut)
13108 {
13109 OSReturn result = kOSKextReturnNoMemory;
13110 OSSharedPtr<OSDictionary> callbackRecord;
13111 OSData * contextWrapper = NULL; // do not release
13112
13113 IORecursiveLockLock(sKextLock);
13114 result = OSKext::dequeueCallbackForRequestTag(requestTag,
13115 callbackRecord);
13116 IORecursiveLockUnlock(sKextLock);
13117
13118 if (result == kOSReturnSuccess && contextOut) {
13119 contextWrapper = OSDynamicCast(OSData,
13120 _OSKextGetRequestArgument(callbackRecord.get(),
13121 kKextRequestArgumentContextKey));
13122 *contextOut = _OSKextExtractPointer(contextWrapper);
13123 }
13124
13125 return result;
13126 }
13127
13128 /*********************************************************************
13129 * Assumes sKextLock is held.
13130 *********************************************************************/
13131 void
13132 OSKext::invokeOrCancelRequestCallbacks(
13133 OSReturn callbackResult,
13134 bool invokeFlag)
13135 {
13136 unsigned int count, i;
13137
13138 count = sRequestCallbackRecords->getCount();
13139 if (!count) {
13140 goto finish;
13141 }
13142
13143 i = count - 1;
13144 do {
13145 OSDictionary * request = OSDynamicCast(OSDictionary,
13146 sRequestCallbackRecords->getObject(i));
13147
13148 if (!request) {
13149 continue;
13150 }
13151 OSData * callbackWrapper = OSDynamicCast(OSData,
13152 _OSKextGetRequestArgument(request,
13153 kKextRequestArgumentCallbackKey));
13154
13155 if (!callbackWrapper) {
13156 sRequestCallbackRecords->removeObject(i);
13157 continue;
13158 }
13159
13160 vm_address_t callbackAddress = (vm_address_t)
13161 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13162
13163 if ((kmod_info->address <= callbackAddress) &&
13164 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13165 if (invokeFlag) {
13166 /* This removes the callback record.
13167 */
13168 invokeRequestCallback(request, callbackResult);
13169 } else {
13170 sRequestCallbackRecords->removeObject(i);
13171 }
13172 }
13173 } while (i--);
13174
13175 finish:
13176 return;
13177 }
13178
13179 /*********************************************************************
13180 * Assumes sKextLock is held.
13181 *********************************************************************/
13182 uint32_t
13183 OSKext::countRequestCallbacks(void)
13184 {
13185 uint32_t result = 0;
13186 unsigned int count, i;
13187
13188 count = sRequestCallbackRecords->getCount();
13189 if (!count) {
13190 goto finish;
13191 }
13192
13193 i = count - 1;
13194 do {
13195 OSDictionary * request = OSDynamicCast(OSDictionary,
13196 sRequestCallbackRecords->getObject(i));
13197
13198 if (!request) {
13199 continue;
13200 }
13201 OSData * callbackWrapper = OSDynamicCast(OSData,
13202 _OSKextGetRequestArgument(request,
13203 kKextRequestArgumentCallbackKey));
13204
13205 if (!callbackWrapper) {
13206 continue;
13207 }
13208
13209 vm_address_t callbackAddress = (vm_address_t)
13210 ptrauth_strip(_OSKextExtractPointer(callbackWrapper), ptrauth_key_function_pointer);
13211
13212 if ((kmod_info->address <= callbackAddress) &&
13213 (callbackAddress < (kmod_info->address + kmod_info->size))) {
13214 result++;
13215 }
13216 } while (i--);
13217
13218 finish:
13219 return result;
13220 }
13221
13222 /*********************************************************************
13223 *********************************************************************/
13224 static OSReturn
13225 _OSKextCreateRequest(
13226 const char * predicate,
13227 OSSharedPtr<OSDictionary> & requestR)
13228 {
13229 OSReturn result = kOSKextReturnNoMemory;
13230 OSSharedPtr<OSDictionary> request;
13231
13232 request = OSDictionary::withCapacity(2);
13233 if (!request) {
13234 goto finish;
13235 }
13236 result = _OSDictionarySetCStringValue(request.get(),
13237 kKextRequestPredicateKey, predicate);
13238 if (result != kOSReturnSuccess) {
13239 goto finish;
13240 }
13241 result = kOSReturnSuccess;
13242
13243 finish:
13244 if (result == kOSReturnSuccess) {
13245 requestR = os::move(request);
13246 }
13247
13248 return result;
13249 }
13250
13251 /*********************************************************************
13252 *********************************************************************/
13253 static OSString *
13254 _OSKextGetRequestPredicate(OSDictionary * requestDict)
13255 {
13256 return OSDynamicCast(OSString,
13257 requestDict->getObject(kKextRequestPredicateKey));
13258 }
13259
13260 /*********************************************************************
13261 *********************************************************************/
13262 static OSObject *
13263 _OSKextGetRequestArgument(
13264 OSDictionary * requestDict,
13265 const char * argName)
13266 {
13267 OSDictionary * args = OSDynamicCast(OSDictionary,
13268 requestDict->getObject(kKextRequestArgumentsKey));
13269 if (args) {
13270 return args->getObject(argName);
13271 }
13272 return NULL;
13273 }
13274
13275 /*********************************************************************
13276 *********************************************************************/
13277 static bool
13278 _OSKextSetRequestArgument(
13279 OSDictionary * requestDict,
13280 const char * argName,
13281 OSObject * value)
13282 {
13283 OSDictionary * args = OSDynamicCast(OSDictionary,
13284 requestDict->getObject(kKextRequestArgumentsKey));
13285 OSSharedPtr<OSDictionary> newArgs;
13286 if (!args) {
13287 newArgs = OSDictionary::withCapacity(2);
13288 args = newArgs.get();
13289 if (!args) {
13290 goto finish;
13291 }
13292 requestDict->setObject(kKextRequestArgumentsKey, args);
13293 }
13294 if (args) {
13295 return args->setObject(argName, value);
13296 }
13297 finish:
13298 return false;
13299 }
13300
13301 /*********************************************************************
13302 *********************************************************************/
13303 static void *
13304 _OSKextExtractPointer(OSData * wrapper)
13305 {
13306 void * result = NULL;
13307 const void * resultPtr = NULL;
13308
13309 if (!wrapper) {
13310 goto finish;
13311 }
13312 resultPtr = wrapper->getBytesNoCopy();
13313 result = *(void **)resultPtr;
13314 finish:
13315 return result;
13316 }
13317
13318 /*********************************************************************
13319 *********************************************************************/
13320 static OSKextRequestResourceCallback
13321 _OSKextExtractCallbackPointer(OSData * wrapper)
13322 {
13323 OSKextRequestResourceCallback result = NULL;
13324 const void * resultPtr = NULL;
13325
13326 if (!wrapper) {
13327 goto finish;
13328 }
13329 resultPtr = wrapper->getBytesNoCopy();
13330 result = *(OSKextRequestResourceCallback *)resultPtr;
13331 finish:
13332 return result;
13333 }
13334
13335
13336 /*********************************************************************
13337 *********************************************************************/
13338 static OSReturn
13339 _OSDictionarySetCStringValue(
13340 OSDictionary * dict,
13341 const char * cKey,
13342 const char * cValue)
13343 {
13344 OSReturn result = kOSKextReturnNoMemory;
13345 OSSharedPtr<const OSSymbol> key;
13346 OSSharedPtr<OSString> value;
13347
13348 key = OSSymbol::withCString(cKey);
13349 value = OSString::withCString(cValue);
13350 if (!key || !value) {
13351 goto finish;
13352 }
13353 if (dict->setObject(key.get(), value.get())) {
13354 result = kOSReturnSuccess;
13355 }
13356
13357 finish:
13358 return result;
13359 }
13360
13361 /*********************************************************************
13362 *********************************************************************/
13363 static bool
13364 _OSArrayContainsCString(
13365 OSArray * array,
13366 const char * cString)
13367 {
13368 bool result = false;
13369 OSSharedPtr<const OSSymbol> symbol;
13370 uint32_t count, i;
13371
13372 if (!array || !cString) {
13373 goto finish;
13374 }
13375
13376 symbol = OSSymbol::withCStringNoCopy(cString);
13377 if (!symbol) {
13378 goto finish;
13379 }
13380
13381 count = array->getCount();
13382 for (i = 0; i < count; i++) {
13383 OSObject * thisObject = array->getObject(i);
13384 if (symbol->isEqualTo(thisObject)) {
13385 result = true;
13386 goto finish;
13387 }
13388 }
13389
13390 finish:
13391 return result;
13392 }
13393
13394 #if CONFIG_KXLD
13395 /*********************************************************************
13396 * We really only care about boot / system start up related kexts.
13397 * We return true if we're less than REBUILD_MAX_TIME since start up,
13398 * otherwise return false.
13399 *********************************************************************/
13400 bool
13401 _OSKextInPrelinkRebuildWindow(void)
13402 {
13403 static bool outside_the_window = false;
13404 AbsoluteTime my_abstime;
13405 UInt64 my_ns;
13406 SInt32 my_secs;
13407
13408 if (outside_the_window) {
13409 return false;
13410 }
13411 clock_get_uptime(&my_abstime);
13412 absolutetime_to_nanoseconds(my_abstime, &my_ns);
13413 my_secs = (SInt32)(my_ns / NSEC_PER_SEC);
13414 if (my_secs > REBUILD_MAX_TIME) {
13415 outside_the_window = true;
13416 return false;
13417 }
13418 return true;
13419 }
13420 #endif /* CONFIG_KXLD */
13421
13422 /*********************************************************************
13423 *********************************************************************/
13424 bool
13425 _OSKextInUnloadedPrelinkedKexts( const OSSymbol * theBundleID )
13426 {
13427 int unLoadedCount, i;
13428 bool result = false;
13429
13430 IORecursiveLockLock(sKextLock);
13431
13432 if (sUnloadedPrelinkedKexts == NULL) {
13433 goto finish;
13434 }
13435 unLoadedCount = sUnloadedPrelinkedKexts->getCount();
13436 if (unLoadedCount == 0) {
13437 goto finish;
13438 }
13439
13440 for (i = 0; i < unLoadedCount; i++) {
13441 const OSSymbol * myBundleID; // do not release
13442
13443 myBundleID = OSDynamicCast(OSSymbol, sUnloadedPrelinkedKexts->getObject(i));
13444 if (!myBundleID) {
13445 continue;
13446 }
13447 if (theBundleID->isEqualTo(myBundleID->getCStringNoCopy())) {
13448 result = true;
13449 break;
13450 }
13451 }
13452 finish:
13453 IORecursiveLockUnlock(sKextLock);
13454 return result;
13455 }
13456
13457 #if PRAGMA_MARK
13458 #pragma mark Personalities (IOKit Drivers)
13459 #endif
13460 /*********************************************************************
13461 *********************************************************************/
13462 /* static */
13463 OSSharedPtr<OSArray>
13464 OSKext::copyAllKextPersonalities(bool filterSafeBootFlag)
13465 {
13466 OSSharedPtr<OSArray> result;
13467 OSSharedPtr<OSCollectionIterator> kextIterator;
13468 OSSharedPtr<OSArray> personalities;
13469
13470 OSString * kextID = NULL; // do not release
13471 OSKext * theKext = NULL; // do not release
13472
13473 IORecursiveLockLock(sKextLock);
13474
13475 /* Let's conservatively guess that any given kext has around 3
13476 * personalities for now.
13477 */
13478 result = OSArray::withCapacity(sKextsByID->getCount() * 3);
13479 if (!result) {
13480 goto finish;
13481 }
13482
13483 kextIterator = OSCollectionIterator::withCollection(sKextsByID.get());
13484 if (!kextIterator) {
13485 goto finish;
13486 }
13487
13488 while ((kextID = OSDynamicCast(OSString, kextIterator->getNextObject()))) {
13489 theKext = OSDynamicCast(OSKext, sKextsByID->getObject(kextID));
13490 if (theKext->flags.requireExplicitLoad) {
13491 OSKextLog(theKext,
13492 kOSKextLogDebugLevel |
13493 kOSKextLogLoadFlag,
13494 "Kext %s requires an explicit kextload; "
13495 "omitting its personalities.",
13496 theKext->getIdentifierCString());
13497 } else if (!sSafeBoot || !filterSafeBootFlag || theKext->isLoadableInSafeBoot()) {
13498 personalities = theKext->copyPersonalitiesArray();
13499 if (!personalities) {
13500 continue;
13501 }
13502 result->merge(personalities.get());
13503 } else {
13504 // xxx - check for better place to put this log msg
13505 OSKextLog(theKext,
13506 kOSKextLogWarningLevel |
13507 kOSKextLogLoadFlag,
13508 "Kext %s is not loadable during safe boot; "
13509 "omitting its personalities.",
13510 theKext->getIdentifierCString());
13511 }
13512 }
13513
13514 finish:
13515 IORecursiveLockUnlock(sKextLock);
13516
13517 return result;
13518 }
13519
13520 /*********************************************************************
13521 *********************************************************************/
13522 /* static */
13523 void
13524 OSKext::sendAllKextPersonalitiesToCatalog(bool startMatching)
13525 {
13526 int numPersonalities = 0;
13527
13528 OSKextLog(/* kext */ NULL,
13529 kOSKextLogStepLevel |
13530 kOSKextLogLoadFlag,
13531 "Sending all eligible registered kexts' personalities "
13532 "to the IOCatalogue %s.",
13533 startMatching ? "and starting matching" : "but not starting matching");
13534
13535 OSSharedPtr<OSArray> personalities = OSKext::copyAllKextPersonalities(
13536 /* filterSafeBootFlag */ true);
13537
13538 if (personalities) {
13539 gIOCatalogue->addDrivers(personalities.get(), startMatching);
13540 numPersonalities = personalities->getCount();
13541 }
13542
13543 OSKextLog(/* kext */ NULL,
13544 kOSKextLogStepLevel |
13545 kOSKextLogLoadFlag,
13546 "%d kext personalit%s sent to the IOCatalogue; %s.",
13547 numPersonalities, numPersonalities > 0 ? "ies" : "y",
13548 startMatching ? "matching started" : "matching not started");
13549 return;
13550 }
13551
13552 /*********************************************************************
13553 * Do not make a deep copy, just convert the IOKitPersonalities dict
13554 * to an array for sending to the IOCatalogue.
13555 *********************************************************************/
13556 OSSharedPtr<OSArray>
13557 OSKext::copyPersonalitiesArray(void)
13558 {
13559 OSSharedPtr<OSArray> result;
13560 OSDictionary * personalities = NULL; // do not release
13561 OSSharedPtr<OSCollectionIterator> personalitiesIterator;
13562
13563 OSString * personalityName = NULL; // do not release
13564 OSString * personalityBundleIdentifier = NULL; // do not release
13565
13566 personalities = OSDynamicCast(OSDictionary,
13567 getPropertyForHostArch(kIOKitPersonalitiesKey));
13568 if (!personalities) {
13569 goto finish;
13570 }
13571
13572 result = OSArray::withCapacity(personalities->getCount());
13573 if (!result) {
13574 goto finish;
13575 }
13576
13577 personalitiesIterator =
13578 OSCollectionIterator::withCollection(personalities);
13579 if (!personalitiesIterator) {
13580 goto finish;
13581 }
13582 while ((personalityName = OSDynamicCast(OSString,
13583 personalitiesIterator->getNextObject()))) {
13584 OSDictionary * personality = OSDynamicCast(OSDictionary,
13585 personalities->getObject(personalityName));
13586
13587 /******
13588 * If the personality doesn't have a CFBundleIdentifier, or if it
13589 * differs from the kext's, insert the kext's ID so we can find it.
13590 * The publisher ID is used to remove personalities from bundles
13591 * correctly.
13592 */
13593 personalityBundleIdentifier = OSDynamicCast(OSString,
13594 personality->getObject(kCFBundleIdentifierKey));
13595
13596 if (!personalityBundleIdentifier) {
13597 personality->setObject(kCFBundleIdentifierKey, bundleID.get());
13598 } else if (!personalityBundleIdentifier->isEqualTo(bundleID.get())) {
13599 personality->setObject(kIOPersonalityPublisherKey, bundleID.get());
13600 }
13601
13602 result->setObject(personality);
13603 }
13604
13605 finish:
13606 return result;
13607 }
13608
13609 /*********************************************************************
13610 * Might want to change this to a bool return?
13611 *********************************************************************/
13612 OSReturn
13613 OSKext::sendPersonalitiesToCatalog(
13614 bool startMatching,
13615 OSArray * personalityNames)
13616 {
13617 OSReturn result = kOSReturnSuccess;
13618 OSSharedPtr<OSArray> personalitiesToSend;
13619 OSDictionary * kextPersonalities = NULL; // do not release
13620 int count, i;
13621
13622 if (!sLoadEnabled) {
13623 OSKextLog(this,
13624 kOSKextLogErrorLevel |
13625 kOSKextLogLoadFlag,
13626 "Kext loading is disabled (attempt to start matching for kext %s).",
13627 getIdentifierCString());
13628 result = kOSKextReturnDisabled;
13629 goto finish;
13630 }
13631
13632 if (sSafeBoot && !isLoadableInSafeBoot()) {
13633 OSKextLog(this,
13634 kOSKextLogErrorLevel |
13635 kOSKextLogLoadFlag,
13636 "Kext %s is not loadable during safe boot; "
13637 "not sending personalities to the IOCatalogue.",
13638 getIdentifierCString());
13639 result = kOSKextReturnNotLoadable;
13640 goto finish;
13641 }
13642
13643 if (!personalityNames || !personalityNames->getCount()) {
13644 personalitiesToSend = copyPersonalitiesArray();
13645 } else {
13646 kextPersonalities = OSDynamicCast(OSDictionary,
13647 getPropertyForHostArch(kIOKitPersonalitiesKey));
13648 if (!kextPersonalities || !kextPersonalities->getCount()) {
13649 // not an error
13650 goto finish;
13651 }
13652 personalitiesToSend = OSArray::withCapacity(0);
13653 if (!personalitiesToSend) {
13654 result = kOSKextReturnNoMemory;
13655 goto finish;
13656 }
13657 count = personalityNames->getCount();
13658 for (i = 0; i < count; i++) {
13659 OSString * name = OSDynamicCast(OSString,
13660 personalityNames->getObject(i));
13661 if (!name) {
13662 continue;
13663 }
13664 OSDictionary * personality = OSDynamicCast(OSDictionary,
13665 kextPersonalities->getObject(name));
13666 if (personality) {
13667 personalitiesToSend->setObject(personality);
13668 }
13669 }
13670 }
13671 if (personalitiesToSend) {
13672 unsigned numPersonalities = personalitiesToSend->getCount();
13673 OSKextLog(this,
13674 kOSKextLogStepLevel |
13675 kOSKextLogLoadFlag,
13676 "Kext %s sending %d personalit%s to the IOCatalogue%s.",
13677 getIdentifierCString(),
13678 numPersonalities,
13679 numPersonalities > 1 ? "ies" : "y",
13680 startMatching ? " and starting matching" : " but not starting matching");
13681 gIOCatalogue->addDrivers(personalitiesToSend.get(), startMatching);
13682 }
13683 finish:
13684 return result;
13685 }
13686
13687 /*********************************************************************
13688 * xxx - We should allow removing the kext's declared personalities,
13689 * xxx - even with other bundle identifiers.
13690 *********************************************************************/
13691 void
13692 OSKext::removePersonalitiesFromCatalog(void)
13693 {
13694 OSSharedPtr<OSDictionary> personality;
13695
13696 personality = OSDictionary::withCapacity(1);
13697 if (!personality) {
13698 goto finish;
13699 }
13700 personality->setObject(kCFBundleIdentifierKey, getIdentifier());
13701
13702 OSKextLog(this,
13703 kOSKextLogStepLevel |
13704 kOSKextLogLoadFlag,
13705 "Kext %s removing all personalities naming it from the IOCatalogue.",
13706 getIdentifierCString());
13707
13708 /* Have the IOCatalog remove all personalities matching this kext's
13709 * bundle ID and trigger matching anew.
13710 */
13711 gIOCatalogue->removeDrivers(personality.get(), /* startMatching */ true);
13712
13713 finish:
13714 return;
13715 }
13716
13717
13718 #if PRAGMA_MARK
13719 #pragma mark Logging
13720 #endif
13721 /*********************************************************************
13722 * Do not call any function that takes sKextLock here!
13723 *********************************************************************/
13724 /* static */
13725 OSKextLogSpec
13726 OSKext::setUserSpaceLogFilter(
13727 OSKextLogSpec newUserLogFilter,
13728 bool captureFlag)
13729 {
13730 OSKextLogSpec result;
13731 bool allocError = false;
13732
13733 /* Do not call any function that takes sKextLoggingLock during
13734 * this critical block. That means do logging after.
13735 */
13736 IOLockLock(sKextLoggingLock);
13737
13738 result = sUserSpaceKextLogFilter;
13739 sUserSpaceKextLogFilter = newUserLogFilter;
13740
13741 if (newUserLogFilter && captureFlag &&
13742 !sUserSpaceLogSpecArray && !sUserSpaceLogMessageArray) {
13743 // xxx - do some measurements for a good initial capacity?
13744 sUserSpaceLogSpecArray = OSArray::withCapacity(0);
13745 sUserSpaceLogMessageArray = OSArray::withCapacity(0);
13746
13747 if (!sUserSpaceLogSpecArray || !sUserSpaceLogMessageArray) {
13748 allocError = true;
13749 }
13750 }
13751
13752 IOLockUnlock(sKextLoggingLock);
13753
13754 /* If the config flag itself is changing, log the state change
13755 * going both ways, before setting up the user-space log arrays,
13756 * so that this is only logged in the kernel.
13757 */
13758 if (result != newUserLogFilter) {
13759 OSKextLog(/* kext */ NULL,
13760 kOSKextLogDebugLevel |
13761 kOSKextLogGeneralFlag,
13762 "User-space log flags changed from 0x%x to 0x%x.",
13763 result, newUserLogFilter);
13764 }
13765 if (allocError) {
13766 OSKextLog(/* kext */ NULL,
13767 kOSKextLogErrorLevel |
13768 kOSKextLogGeneralFlag,
13769 "Failed to allocate user-space log message arrays.");
13770 }
13771
13772 return result;
13773 }
13774
13775 /*********************************************************************
13776 * Do not call any function that takes sKextLock here!
13777 *********************************************************************/
13778 /* static */
13779 OSSharedPtr<OSArray>
13780 OSKext::clearUserSpaceLogFilter(void)
13781 {
13782 OSSharedPtr<OSArray> result;
13783 OSKextLogSpec oldLogFilter;
13784 OSKextLogSpec newLogFilter = kOSKextLogSilentFilter;
13785
13786 /* Do not call any function that takes sKextLoggingLock during
13787 * this critical block. That means do logging after.
13788 */
13789 IOLockLock(sKextLoggingLock);
13790
13791 result = OSArray::withCapacity(2);
13792 if (result) {
13793 result->setObject(sUserSpaceLogSpecArray.get());
13794 result->setObject(sUserSpaceLogMessageArray.get());
13795 }
13796 sUserSpaceLogSpecArray.reset();
13797 sUserSpaceLogMessageArray.reset();
13798
13799 oldLogFilter = sUserSpaceKextLogFilter;
13800 sUserSpaceKextLogFilter = newLogFilter;
13801
13802 IOLockUnlock(sKextLoggingLock);
13803
13804 /* If the config flag itself is changing, log the state change
13805 * going both ways, after tearing down the user-space log
13806 * arrays, so this is only logged within the kernel.
13807 */
13808 if (oldLogFilter != newLogFilter) {
13809 OSKextLog(/* kext */ NULL,
13810 kOSKextLogDebugLevel |
13811 kOSKextLogGeneralFlag,
13812 "User-space log flags changed from 0x%x to 0x%x.",
13813 oldLogFilter, newLogFilter);
13814 }
13815
13816 return result;
13817 }
13818
13819
13820 /*********************************************************************
13821 * Do not call any function that takes sKextLock here!
13822 *********************************************************************/
13823 /* static */
13824 OSKextLogSpec
13825 OSKext::getUserSpaceLogFilter(void)
13826 {
13827 OSKextLogSpec result;
13828
13829 IOLockLock(sKextLoggingLock);
13830 result = sUserSpaceKextLogFilter;
13831 IOLockUnlock(sKextLoggingLock);
13832
13833 return result;
13834 }
13835
13836 /*********************************************************************
13837 * This function is called by OSMetaClass during kernel C++ setup.
13838 * Be careful what you access here; assume only OSKext::initialize()
13839 * has been called.
13840 *
13841 * Do not call any function that takes sKextLock here!
13842 *********************************************************************/
13843 #define VTRESET "\033[0m"
13844
13845 #define VTBOLD "\033[1m"
13846 #define VTUNDER "\033[4m"
13847
13848 #define VTRED "\033[31m"
13849 #define VTGREEN "\033[32m"
13850 #define VTYELLOW "\033[33m"
13851 #define VTBLUE "\033[34m"
13852 #define VTMAGENTA "\033[35m"
13853 #define VTCYAN "\033[36m"
13854
13855 inline const char *
13856 colorForFlags(OSKextLogSpec flags)
13857 {
13858 OSKextLogSpec logLevel = flags & kOSKextLogLevelMask;
13859
13860 switch (logLevel) {
13861 case kOSKextLogErrorLevel:
13862 return VTRED VTBOLD;
13863 case kOSKextLogWarningLevel:
13864 return VTRED;
13865 case kOSKextLogBasicLevel:
13866 return VTYELLOW VTUNDER;
13867 case kOSKextLogProgressLevel:
13868 return VTYELLOW;
13869 case kOSKextLogStepLevel:
13870 return VTGREEN;
13871 case kOSKextLogDetailLevel:
13872 return VTCYAN;
13873 case kOSKextLogDebugLevel:
13874 return VTMAGENTA;
13875 default:
13876 return ""; // white
13877 }
13878 }
13879
13880 inline bool
13881 logSpecMatch(
13882 OSKextLogSpec msgLogSpec,
13883 OSKextLogSpec logFilter)
13884 {
13885 OSKextLogSpec filterKextGlobal = logFilter & kOSKextLogKextOrGlobalMask;
13886 OSKextLogSpec filterLevel = logFilter & kOSKextLogLevelMask;
13887 OSKextLogSpec filterFlags = logFilter & kOSKextLogFlagsMask;
13888
13889 OSKextLogSpec msgKextGlobal = msgLogSpec & kOSKextLogKextOrGlobalMask;
13890 OSKextLogSpec msgLevel = msgLogSpec & kOSKextLogLevelMask;
13891 OSKextLogSpec msgFlags = msgLogSpec & kOSKextLogFlagsMask;
13892
13893 /* Explicit messages always get logged.
13894 */
13895 if (msgLevel == kOSKextLogExplicitLevel) {
13896 return true;
13897 }
13898
13899 /* Warnings and errors are logged regardless of the flags.
13900 */
13901 if (msgLevel <= kOSKextLogBasicLevel && (msgLevel <= filterLevel)) {
13902 return true;
13903 }
13904
13905 /* A verbose message that isn't for a logging-enabled kext and isn't global
13906 * does *not* get logged.
13907 */
13908 if (!msgKextGlobal && !filterKextGlobal) {
13909 return false;
13910 }
13911
13912 /* Warnings and errors are logged regardless of the flags.
13913 * All other messages must fit the flags and
13914 * have a level at or below the filter.
13915 *
13916 */
13917 if ((msgFlags & filterFlags) && (msgLevel <= filterLevel)) {
13918 return true;
13919 }
13920 return false;
13921 }
13922
13923 extern "C" {
13924 void
13925 OSKextLog(
13926 OSKext * aKext,
13927 OSKextLogSpec msgLogSpec,
13928 const char * format, ...)
13929 {
13930 va_list argList;
13931
13932 va_start(argList, format);
13933 OSKextVLog(aKext, msgLogSpec, format, argList);
13934 va_end(argList);
13935 }
13936
13937 void
13938 OSKextVLog(
13939 OSKext * aKext,
13940 OSKextLogSpec msgLogSpec,
13941 const char * format,
13942 va_list srcArgList)
13943 {
13944 extern int disableConsoleOutput;
13945
13946 bool logForKernel = false;
13947 bool logForUser = false;
13948 va_list argList;
13949 char stackBuffer[120];
13950 uint32_t length = 0;
13951 char * allocBuffer = NULL; // must kfree
13952 OSSharedPtr<OSNumber> logSpecNum;
13953 OSSharedPtr<OSString> logString;
13954 char * buffer = stackBuffer; // do not free
13955
13956 IOLockLock(sKextLoggingLock);
13957
13958 /* Set the kext/global bit in the message spec if we have no
13959 * kext or if the kext requests logging.
13960 */
13961 if (!aKext || aKext->flags.loggingEnabled) {
13962 msgLogSpec = msgLogSpec | kOSKextLogKextOrGlobalMask;
13963 }
13964
13965 logForKernel = logSpecMatch(msgLogSpec, sKernelLogFilter);
13966 if (sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
13967 logForUser = logSpecMatch(msgLogSpec, sUserSpaceKextLogFilter);
13968 }
13969
13970 if (!(logForKernel || logForUser)) {
13971 goto finish;
13972 }
13973
13974 /* No goto from here until past va_end()!
13975 */
13976 va_copy(argList, srcArgList);
13977 length = vsnprintf(stackBuffer, sizeof(stackBuffer), format, argList);
13978 va_end(argList);
13979
13980 if (length + 1 >= sizeof(stackBuffer)) {
13981 allocBuffer = (char *)kheap_alloc_tag(KHEAP_TEMP,
13982 length + 1, Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
13983 if (!allocBuffer) {
13984 goto finish;
13985 }
13986
13987 /* No goto from here until past va_end()!
13988 */
13989 va_copy(argList, srcArgList);
13990 vsnprintf(allocBuffer, length + 1, format, argList);
13991 va_end(argList);
13992
13993 buffer = allocBuffer;
13994 }
13995
13996 /* If user space wants the log message, queue it up.
13997 */
13998 if (logForUser && sUserSpaceLogSpecArray && sUserSpaceLogMessageArray) {
13999 logSpecNum = OSNumber::withNumber(msgLogSpec, 8 * sizeof(msgLogSpec));
14000 logString = OSString::withCString(buffer);
14001 if (logSpecNum && logString) {
14002 sUserSpaceLogSpecArray->setObject(logSpecNum.get());
14003 sUserSpaceLogMessageArray->setObject(logString.get());
14004 }
14005 }
14006
14007 /* Always log messages from the kernel according to the kernel's
14008 * log flags.
14009 */
14010 if (logForKernel) {
14011 /* If we are in console mode and have a custom log filter,
14012 * colorize the log message.
14013 */
14014 if (!disableConsoleOutput && sBootArgLogFilterFound) {
14015 const char * color = ""; // do not free
14016 color = colorForFlags(msgLogSpec);
14017 printf("%s%s%s\n", colorForFlags(msgLogSpec),
14018 buffer, color[0] ? VTRESET : "");
14019 } else {
14020 printf("%s\n", buffer);
14021 }
14022 }
14023
14024 finish:
14025 IOLockUnlock(sKextLoggingLock);
14026
14027 if (allocBuffer) {
14028 kheap_free(KHEAP_TEMP, allocBuffer, (length + 1) * sizeof(char));
14029 }
14030 return;
14031 }
14032
14033 #if KASLR_IOREG_DEBUG
14034
14035 #define IOLOG_INDENT( the_indention ) \
14036 { \
14037 int i; \
14038 for ( i = 0; i < (the_indention); i++ ) { \
14039 IOLog(" "); \
14040 } \
14041 }
14042
14043 extern vm_offset_t vm_kernel_stext;
14044 extern vm_offset_t vm_kernel_etext;
14045 extern mach_vm_offset_t kext_alloc_base;
14046 extern mach_vm_offset_t kext_alloc_max;
14047
14048 bool ScanForAddrInObject(OSObject * theObject,
14049 int indent );
14050
14051 bool
14052 ScanForAddrInObject(OSObject * theObject,
14053 int indent)
14054 {
14055 const OSMetaClass * myTypeID;
14056 OSSharedPtr<OSCollectionIterator> myIter;
14057 OSSymbol * myKey;
14058 OSObject * myValue;
14059 bool myResult = false;
14060
14061 if (theObject == NULL) {
14062 IOLog("%s: theObject is NULL \n",
14063 __FUNCTION__);
14064 return myResult;
14065 }
14066
14067 myTypeID = OSTypeIDInst(theObject);
14068
14069 if (myTypeID == OSTypeID(OSDictionary)) {
14070 OSDictionary * myDictionary;
14071
14072 myDictionary = OSDynamicCast(OSDictionary, theObject);
14073 myIter = OSCollectionIterator::withCollection( myDictionary );
14074 if (myIter == NULL) {
14075 return myResult;
14076 }
14077
14078 // !! reset the iterator
14079 myIter->reset();
14080
14081 while ((myKey = OSDynamicCast(OSSymbol, myIter->getNextObject()))) {
14082 bool myTempResult;
14083
14084 myValue = myDictionary->getObject(myKey);
14085 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14086 if (myTempResult) {
14087 // if we ever get a true result return true
14088 myResult = true;
14089 IOLOG_INDENT(indent);
14090 IOLog("OSDictionary key \"%s\" \n", myKey->getCStringNoCopy());
14091 }
14092 }
14093
14094 // !! release the iterator
14095 myIter.reset();
14096 } else if (myTypeID == OSTypeID(OSArray)) {
14097 OSArray * myArray;
14098
14099 myArray = OSDynamicCast(OSArray, theObject);
14100 myIter = OSCollectionIterator::withCollection(myArray);
14101 if (myIter == NULL) {
14102 return myResult;
14103 }
14104 // !! reset the iterator
14105 myIter->reset();
14106
14107 while ((myValue = myIter->getNextObject())) {
14108 bool myTempResult;
14109 myTempResult = ScanForAddrInObject(myValue, (indent + 4));
14110 if (myTempResult) {
14111 // if we ever get a true result return true
14112 myResult = true;
14113 IOLOG_INDENT(indent);
14114 IOLog("OSArray: \n");
14115 }
14116 }
14117 // !! release the iterator
14118 myIter.reset();
14119 } else if (myTypeID == OSTypeID(OSString) || myTypeID == OSTypeID(OSSymbol)) {
14120 // should we look for addresses in strings?
14121 } else if (myTypeID == OSTypeID(OSData)) {
14122 void * * myPtrPtr;
14123 unsigned int myLen;
14124 OSData * myDataObj;
14125
14126 myDataObj = OSDynamicCast(OSData, theObject);
14127 myPtrPtr = (void * *) myDataObj->getBytesNoCopy();
14128 myLen = myDataObj->getLength();
14129
14130 if (myPtrPtr && myLen && myLen > 7) {
14131 int i;
14132 int myPtrCount = (myLen / sizeof(void *));
14133
14134 for (i = 0; i < myPtrCount; i++) {
14135 UInt64 numberValue = (UInt64) * (myPtrPtr);
14136
14137 if (kext_alloc_max != 0 &&
14138 numberValue >= kext_alloc_base &&
14139 numberValue < kext_alloc_max) {
14140 OSSharedPtr<OSKext> myKext;
14141 // IOLog("found OSData %p in kext map %p to %p \n",
14142 // *(myPtrPtr),
14143 // (void *) kext_alloc_base,
14144 // (void *) kext_alloc_max);
14145
14146 myKext = OSKext::lookupKextWithAddress((vm_address_t) *(myPtrPtr));
14147 if (myKext) {
14148 IOLog("found addr %p from an OSData obj within kext \"%s\" \n",
14149 *(myPtrPtr),
14150 myKext->getIdentifierCString());
14151 }
14152 myResult = true;
14153 }
14154 if (vm_kernel_etext != 0 &&
14155 numberValue >= vm_kernel_stext &&
14156 numberValue < vm_kernel_etext) {
14157 IOLog("found addr %p from an OSData obj within kernel text segment %p to %p \n",
14158 *(myPtrPtr),
14159 (void *) vm_kernel_stext,
14160 (void *) vm_kernel_etext);
14161 myResult = true;
14162 }
14163 myPtrPtr++;
14164 }
14165 }
14166 } else if (myTypeID == OSTypeID(OSBoolean)) {
14167 // do nothing here...
14168 } else if (myTypeID == OSTypeID(OSNumber)) {
14169 OSNumber * number = OSDynamicCast(OSNumber, theObject);
14170
14171 UInt64 numberValue = number->unsigned64BitValue();
14172
14173 if (kext_alloc_max != 0 &&
14174 numberValue >= kext_alloc_base &&
14175 numberValue < kext_alloc_max) {
14176 OSSharedPtr<OSKext> myKext;
14177 IOLog("found OSNumber in kext map %p to %p \n",
14178 (void *) kext_alloc_base,
14179 (void *) kext_alloc_max);
14180 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14181
14182 myKext = OSKext::lookupKextWithAddress((vm_address_t) numberValue );
14183 if (myKext) {
14184 IOLog("found in kext \"%s\" \n",
14185 myKext->getIdentifierCString());
14186 }
14187
14188 myResult = true;
14189 }
14190 if (vm_kernel_etext != 0 &&
14191 numberValue >= vm_kernel_stext &&
14192 numberValue < vm_kernel_etext) {
14193 IOLog("found OSNumber in kernel text segment %p to %p \n",
14194 (void *) vm_kernel_stext,
14195 (void *) vm_kernel_etext);
14196 IOLog("OSNumber 0x%08llx (%llu) \n", numberValue, numberValue);
14197 myResult = true;
14198 }
14199 }
14200 #if 0
14201 else {
14202 const OSMetaClass* myMetaClass = NULL;
14203
14204 myMetaClass = theObject->getMetaClass();
14205 if (myMetaClass) {
14206 IOLog("class %s \n", myMetaClass->getClassName());
14207 } else {
14208 IOLog("Unknown object \n" );
14209 }
14210 }
14211 #endif
14212
14213 return myResult;
14214 }
14215 #endif // KASLR_KEXT_DEBUG
14216 }; /* extern "C" */
14217
14218 #if PRAGMA_MARK
14219 #pragma mark Backtrace Dump & kmod_get_info() support
14220 #endif
14221 /*********************************************************************
14222 * This function must be safe to call in panic context.
14223 *********************************************************************/
14224 /* static */
14225 void
14226 OSKext::printKextsInBacktrace(
14227 vm_offset_t * addr __unused,
14228 unsigned int cnt __unused,
14229 int (* printf_func)(const char *fmt, ...) __unused,
14230 uint32_t flags __unused)
14231 {
14232 addr64_t summary_page = 0;
14233 addr64_t last_summary_page = 0;
14234 bool found_kmod = false;
14235 u_int i = 0;
14236
14237 if (kPrintKextsLock & flags) {
14238 if (!sKextSummariesLock) {
14239 return;
14240 }
14241 IOLockLock(sKextSummariesLock);
14242 }
14243
14244 if (!gLoadedKextSummaries) {
14245 (*printf_func)(" can't perform kext scan: no kext summary");
14246 goto finish;
14247 }
14248
14249 summary_page = trunc_page((addr64_t)(uintptr_t)gLoadedKextSummaries);
14250 last_summary_page = round_page(summary_page + sLoadedKextSummariesAllocSize);
14251 for (; summary_page < last_summary_page; summary_page += PAGE_SIZE) {
14252 if (pmap_find_phys(kernel_pmap, summary_page) == 0) {
14253 (*printf_func)(" can't perform kext scan: "
14254 "missing kext summary page %p", summary_page);
14255 goto finish;
14256 }
14257 }
14258
14259 for (i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14260 OSKextLoadedKextSummary * summary;
14261
14262 summary = gLoadedKextSummaries->summaries + i;
14263 if (!summary->address) {
14264 continue;
14265 }
14266
14267 if (!summaryIsInBacktrace(summary, addr, cnt)) {
14268 continue;
14269 }
14270
14271 if (!found_kmod) {
14272 if (!(kPrintKextsTerse & flags)) {
14273 (*printf_func)(" Kernel Extensions in backtrace:\n");
14274 }
14275 found_kmod = true;
14276 }
14277
14278 printSummary(summary, printf_func, flags);
14279 }
14280
14281 finish:
14282 if (kPrintKextsLock & flags) {
14283 IOLockUnlock(sKextSummariesLock);
14284 }
14285
14286 return;
14287 }
14288
14289 /*********************************************************************
14290 * This function must be safe to call in panic context.
14291 *********************************************************************/
14292 /* static */
14293 boolean_t
14294 OSKext::summaryIsInBacktrace(
14295 OSKextLoadedKextSummary * summary,
14296 vm_offset_t * addr,
14297 unsigned int cnt)
14298 {
14299 u_int i = 0;
14300
14301 for (i = 0; i < cnt; i++) {
14302 vm_offset_t kscan_addr = addr[i];
14303 #if __has_feature(ptrauth_calls)
14304 kscan_addr = (vm_offset_t)VM_KERNEL_STRIP_PTR(kscan_addr);
14305 #endif /* __has_feature(ptrauth_calls) */
14306 if ((kscan_addr >= summary->text_exec_address) &&
14307 (kscan_addr < (summary->text_exec_address + summary->text_exec_size))) {
14308 return TRUE;
14309 }
14310 }
14311
14312 return FALSE;
14313 }
14314
14315 /*
14316 * Get the kext summary object for the kext where 'addr' lies. Must be called with
14317 * sKextSummariesLock held.
14318 */
14319 OSKextLoadedKextSummary *
14320 OSKext::summaryForAddress(uintptr_t addr)
14321 {
14322 #if __has_feature(ptrauth_calls)
14323 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14324 #endif /* __has_feature(ptrauth_calls) */
14325 for (unsigned i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14326 OSKextLoadedKextSummary *summary = &gLoadedKextSummaries->summaries[i];
14327 if (!summary->address) {
14328 continue;
14329 }
14330
14331 #if VM_MAPPED_KEXTS
14332 /* On our platforms that use VM_MAPPED_KEXTS, we currently do not
14333 * support split kexts, but we also may unmap the kexts, which can
14334 * race with the above codepath (see OSKext::unload). As such,
14335 * use a simple range lookup if we are using VM_MAPPED_KEXTS.
14336 */
14337 if ((addr >= summary->address) && (addr < (summary->address + summary->size))) {
14338 return summary;
14339 }
14340 #else
14341 kernel_mach_header_t *mh = (kernel_mach_header_t *)summary->address;
14342 kernel_segment_command_t *seg;
14343
14344 for (seg = firstsegfromheader(mh); seg != NULL; seg = nextsegfromheader(mh, seg)) {
14345 if ((addr >= seg->vmaddr) && (addr < (seg->vmaddr + seg->vmsize))) {
14346 return summary;
14347 }
14348 }
14349 #endif
14350 }
14351
14352 /* addr did not map to any kext */
14353 return NULL;
14354 }
14355
14356 /* static */
14357 void *
14358 OSKext::kextForAddress(const void *address)
14359 {
14360 void * image = NULL;
14361 OSKextActiveAccount * active;
14362 OSKext * kext = NULL;
14363 uint32_t baseIdx;
14364 uint32_t lim;
14365 uintptr_t addr = (uintptr_t) address;
14366 size_t i;
14367
14368 if (!addr) {
14369 return NULL;
14370 }
14371 #if __has_feature(ptrauth_calls)
14372 addr = (uintptr_t)VM_KERNEL_STRIP_PTR(addr);
14373 #endif /* __has_feature(ptrauth_calls) */
14374
14375 if (sKextAccountsCount) {
14376 IOSimpleLockLock(sKextAccountsLock);
14377 // bsearch sKextAccounts list
14378 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
14379 active = &sKextAccounts[baseIdx + (lim >> 1)];
14380 if ((addr >= active->address) && (addr < active->address_end)) {
14381 kext = active->account->kext;
14382 if (kext && kext->kmod_info) {
14383 image = (void *) kext->kmod_info->address;
14384 }
14385 break;
14386 } else if (addr > active->address) {
14387 // move right
14388 baseIdx += (lim >> 1) + 1;
14389 lim--;
14390 }
14391 // else move left
14392 }
14393 IOSimpleLockUnlock(sKextAccountsLock);
14394 }
14395 if (!image && (addr >= vm_kernel_stext) && (addr < vm_kernel_etext)) {
14396 image = (void *) &_mh_execute_header;
14397 }
14398 if (!image && gLoadedKextSummaries) {
14399 IOLockLock(sKextSummariesLock);
14400 for (i = 0; i < gLoadedKextSummaries->numSummaries; i++) {
14401 OSKextLoadedKextSummary *summary = gLoadedKextSummaries->summaries + i;
14402 if (addr >= summary->address && addr < summary->address + summary->size) {
14403 image = (void *)summary->address;
14404 }
14405 }
14406 IOLockUnlock(sKextSummariesLock);
14407 }
14408
14409 return image;
14410 }
14411
14412 /*
14413 * Find a OSKextLoadedKextSummary given the ID from a kmod_info_t *
14414 * Safe to call in panic context.
14415 */
14416 static OSKextLoadedKextSummary *
14417 findSummary(uint32_t tagID)
14418 {
14419 OSKextLoadedKextSummary * summary;
14420 for (size_t i = 0; i < gLoadedKextSummaries->numSummaries; ++i) {
14421 summary = gLoadedKextSummaries->summaries + i;
14422 if (summary->loadTag == tagID) {
14423 return summary;
14424 }
14425 }
14426 return NULL;
14427 }
14428
14429 /*********************************************************************
14430 * This function must be safe to call in panic context.
14431 *********************************************************************/
14432 void
14433 OSKext::printSummary(
14434 OSKextLoadedKextSummary * summary,
14435 int (* printf_func)(const char *fmt, ...),
14436 uint32_t flags)
14437 {
14438 kmod_reference_t * kmod_ref = NULL;
14439 uuid_string_t uuid;
14440 char version[kOSKextVersionMaxLength];
14441 uint64_t tmpAddr;
14442 uint64_t tmpSize;
14443 OSKextLoadedKextSummary *dependencySummary;
14444
14445 if (!OSKextVersionGetString(summary->version, version, sizeof(version))) {
14446 strlcpy(version, "unknown version", sizeof(version));
14447 }
14448 (void) uuid_unparse(summary->uuid, uuid);
14449
14450 #if defined(__arm__) || defined(__arm64__)
14451 tmpAddr = summary->text_exec_address;
14452 tmpSize = summary->text_exec_size;
14453 #else
14454 tmpAddr = summary->address;
14455 tmpSize = summary->size;
14456 #endif
14457 if (kPrintKextsUnslide & flags) {
14458 tmpAddr = ml_static_unslide(tmpAddr);
14459 }
14460 (*printf_func)("%s%s(%s)[%s]@0x%llx->0x%llx\n",
14461 (kPrintKextsTerse & flags) ? "" : " ",
14462 summary->name, version, uuid,
14463 tmpAddr, tmpAddr + tmpSize - 1);
14464
14465 if (kPrintKextsTerse & flags) {
14466 return;
14467 }
14468
14469 /* print dependency info */
14470 for (kmod_ref = (kmod_reference_t *) summary->reference_list;
14471 kmod_ref;
14472 kmod_ref = kmod_ref->next) {
14473 kmod_info_t * rinfo;
14474
14475 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_ref)) == 0) {
14476 (*printf_func)(" kmod dependency scan stopped "
14477 "due to missing dependency page: %p\n",
14478 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)kmod_ref) : kmod_ref);
14479 break;
14480 }
14481 rinfo = kmod_ref->info;
14482
14483 if (pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)rinfo)) == 0) {
14484 (*printf_func)(" kmod dependency scan stopped "
14485 "due to missing kmod page: %p\n",
14486 (kPrintKextsUnslide & flags) ? (void *)ml_static_unslide((vm_offset_t)rinfo) : rinfo);
14487 break;
14488 }
14489
14490 if (!rinfo->address) {
14491 continue; // skip fake entries for built-ins
14492 }
14493
14494 dependencySummary = findSummary(rinfo->id);
14495 uuid[0] = 0x00;
14496 tmpAddr = rinfo->address;
14497 tmpSize = rinfo->size;
14498 if (dependencySummary) {
14499 (void) uuid_unparse(dependencySummary->uuid, uuid);
14500 #if defined(__arm__) || defined(__arm64__)
14501 tmpAddr = dependencySummary->text_exec_address;
14502 tmpSize = dependencySummary->text_exec_size;
14503 #endif
14504 }
14505
14506 if (kPrintKextsUnslide & flags) {
14507 tmpAddr = ml_static_unslide(tmpAddr);
14508 }
14509 (*printf_func)(" dependency: %s(%s)[%s]@%p->%p\n",
14510 rinfo->name, rinfo->version, uuid, tmpAddr, tmpAddr + tmpSize - 1);
14511 }
14512 return;
14513 }
14514
14515
14516 #if !defined(__arm__) && !defined(__arm64__)
14517 /*******************************************************************************
14518 * substitute() looks at an input string (a pointer within a larger buffer)
14519 * for a match to a substring, and on match it writes the marker & substitution
14520 * character to an output string, updating the scan (from) and
14521 * output (to) indexes as appropriate.
14522 *******************************************************************************/
14523 static int substitute(
14524 const char * scan_string,
14525 char * string_out,
14526 uint32_t * to_index,
14527 uint32_t * from_index,
14528 const char * substring,
14529 char marker,
14530 char substitution);
14531
14532 /* string_out must be at least KMOD_MAX_NAME bytes.
14533 */
14534 static int
14535 substitute(
14536 const char * scan_string,
14537 char * string_out,
14538 uint32_t * to_index,
14539 uint32_t * from_index,
14540 const char * substring,
14541 char marker,
14542 char substitution)
14543 {
14544 size_t substring_length = strnlen(substring, KMOD_MAX_NAME - 1);
14545
14546 /* On a substring match, append the marker (if there is one) and then
14547 * the substitution character, updating the output (to) index accordingly.
14548 * Then update the input (from) length by the length of the substring
14549 * that got replaced.
14550 */
14551 if (!strncmp(scan_string, substring, substring_length)) {
14552 if (marker) {
14553 string_out[(*to_index)++] = marker;
14554 }
14555 string_out[(*to_index)++] = substitution;
14556 (*from_index) += substring_length;
14557 return 1;
14558 }
14559 return 0;
14560 }
14561
14562 /*******************************************************************************
14563 * compactIdentifier() takes a CFBundleIdentifier in a buffer of at least
14564 * KMOD_MAX_NAME characters and performs various substitutions of common
14565 * prefixes & substrings as defined by tables in kext_panic_report.h.
14566 *******************************************************************************/
14567 static void compactIdentifier(
14568 const char * identifier,
14569 char * identifier_out,
14570 char ** identifier_out_end);
14571
14572 static void
14573 compactIdentifier(
14574 const char * identifier,
14575 char * identifier_out,
14576 char ** identifier_out_end)
14577 {
14578 uint32_t from_index, to_index;
14579 uint32_t scan_from_index = 0;
14580 uint32_t scan_to_index = 0;
14581 subs_entry_t * subs_entry = NULL;
14582 int did_sub = 0;
14583
14584 from_index = to_index = 0;
14585 identifier_out[0] = '\0';
14586
14587 /* Replace certain identifier prefixes with shorter @+character sequences.
14588 * Check the return value of substitute() so we only replace the prefix.
14589 */
14590 for (subs_entry = &kext_identifier_prefix_subs[0];
14591 subs_entry->substring && !did_sub;
14592 subs_entry++) {
14593 did_sub = substitute(identifier, identifier_out,
14594 &scan_to_index, &scan_from_index,
14595 subs_entry->substring, /* marker */ '\0', subs_entry->substitute);
14596 }
14597 did_sub = 0;
14598
14599 /* Now scan through the identifier looking for the common substrings
14600 * and replacing them with shorter !+character sequences via substitute().
14601 */
14602 for (/* see above */;
14603 scan_from_index < KMOD_MAX_NAME - 1 && identifier[scan_from_index];
14604 /* see loop */) {
14605 const char * scan_string = &identifier[scan_from_index];
14606
14607 did_sub = 0;
14608
14609 if (scan_from_index) {
14610 for (subs_entry = &kext_identifier_substring_subs[0];
14611 subs_entry->substring && !did_sub;
14612 subs_entry++) {
14613 did_sub = substitute(scan_string, identifier_out,
14614 &scan_to_index, &scan_from_index,
14615 subs_entry->substring, '!', subs_entry->substitute);
14616 }
14617 }
14618
14619 /* If we didn't substitute, copy the input character to the output.
14620 */
14621 if (!did_sub) {
14622 identifier_out[scan_to_index++] = identifier[scan_from_index++];
14623 }
14624 }
14625
14626 identifier_out[scan_to_index] = '\0';
14627 if (identifier_out_end) {
14628 *identifier_out_end = &identifier_out[scan_to_index];
14629 }
14630
14631 return;
14632 }
14633 #endif /* !defined(__arm__) && !defined(__arm64__) */
14634
14635 /*******************************************************************************
14636 * assemble_identifier_and_version() adds to a string buffer a compacted
14637 * bundle identifier followed by a version string.
14638 *******************************************************************************/
14639
14640 /* identPlusVers must be at least 2*KMOD_MAX_NAME in length.
14641 */
14642 static size_t assemble_identifier_and_version(
14643 kmod_info_t * kmod_info,
14644 char * identPlusVers,
14645 size_t bufSize);
14646
14647 static size_t
14648 assemble_identifier_and_version(
14649 kmod_info_t * kmod_info,
14650 char * identPlusVers,
14651 size_t bufSize)
14652 {
14653 size_t result = 0;
14654
14655 #if defined(__arm__) || defined(__arm64__)
14656 result = strlcpy(identPlusVers, kmod_info->name, KMOD_MAX_NAME);
14657 #else
14658 compactIdentifier(kmod_info->name, identPlusVers, NULL);
14659 result = strnlen(identPlusVers, KMOD_MAX_NAME - 1);
14660 #endif
14661 identPlusVers[result++] = '\t'; // increment for real char
14662 identPlusVers[result] = '\0'; // don't increment for nul char
14663 result = strlcat(identPlusVers, kmod_info->version, bufSize);
14664 if (result >= bufSize) {
14665 identPlusVers[bufSize - 1] = '\0';
14666 result = bufSize - 1;
14667 }
14668
14669 return result;
14670 }
14671
14672 /*******************************************************************************
14673 * Assumes sKextLock is held.
14674 *******************************************************************************/
14675 /* static */
14676 int
14677 OSKext::saveLoadedKextPanicListTyped(
14678 const char * prefix,
14679 int invertFlag,
14680 int libsFlag,
14681 char * paniclist,
14682 uint32_t list_size)
14683 {
14684 int result = -1;
14685 unsigned int count, i;
14686
14687 count = sLoadedKexts->getCount();
14688 if (!count) {
14689 goto finish;
14690 }
14691
14692 i = count - 1;
14693 do {
14694 OSObject * rawKext = sLoadedKexts->getObject(i);
14695 OSKext * theKext = OSDynamicCast(OSKext, rawKext);
14696 int match;
14697 size_t identPlusVersLength;
14698 size_t tempLen;
14699 char identPlusVers[2 * KMOD_MAX_NAME];
14700
14701 if (!rawKext) {
14702 printf("OSKext::saveLoadedKextPanicListTyped - "
14703 "NULL kext in loaded kext list; continuing\n");
14704 continue;
14705 }
14706
14707 if (!theKext) {
14708 printf("OSKext::saveLoadedKextPanicListTyped - "
14709 "Kext type cast failed in loaded kext list; continuing\n");
14710 continue;
14711 }
14712
14713 /* Skip all built-in kexts.
14714 */
14715 if (theKext->isKernelComponent()) {
14716 continue;
14717 }
14718
14719 kmod_info_t * kmod_info = theKext->kmod_info;
14720
14721 /* Filter for kmod name (bundle identifier).
14722 */
14723 match = !strncmp(kmod_info->name, prefix, strnlen(prefix, KMOD_MAX_NAME));
14724 if ((match && invertFlag) || (!match && !invertFlag)) {
14725 continue;
14726 }
14727
14728 /* Filter for libraries (kexts that have a compatible version).
14729 */
14730 if ((libsFlag == 0 && theKext->getCompatibleVersion() > 1) ||
14731 (libsFlag == 1 && theKext->getCompatibleVersion() < 1)) {
14732 continue;
14733 }
14734
14735 if (!kmod_info ||
14736 !pmap_find_phys(kernel_pmap, (addr64_t)((uintptr_t)kmod_info))) {
14737 printf("kext scan stopped due to missing kmod_info page: %p\n",
14738 kmod_info);
14739 goto finish;
14740 }
14741
14742 identPlusVersLength = assemble_identifier_and_version(kmod_info,
14743 identPlusVers,
14744 sizeof(identPlusVers));
14745 if (!identPlusVersLength) {
14746 printf("error saving loaded kext info\n");
14747 goto finish;
14748 }
14749
14750 /* make sure everything fits and we null terminate.
14751 */
14752 tempLen = strlcat(paniclist, identPlusVers, list_size);
14753 if (tempLen >= list_size) {
14754 // panic list is full, keep it and null terminate
14755 paniclist[list_size - 1] = 0x00;
14756 result = 0;
14757 goto finish;
14758 }
14759 tempLen = strlcat(paniclist, "\n", list_size);
14760 if (tempLen >= list_size) {
14761 // panic list is full, keep it and null terminate
14762 paniclist[list_size - 1] = 0x00;
14763 result = 0;
14764 goto finish;
14765 }
14766 } while (i--);
14767
14768 result = 0;
14769 finish:
14770
14771 return result;
14772 }
14773
14774 /*********************************************************************
14775 *********************************************************************/
14776 /* static */
14777 void
14778 OSKext::saveLoadedKextPanicList(void)
14779 {
14780 char * newlist = NULL;
14781 uint32_t newlist_size = 0;
14782
14783 newlist_size = KEXT_PANICLIST_SIZE;
14784 newlist = (char *)kheap_alloc_tag(KHEAP_DATA_BUFFERS, newlist_size,
14785 Z_WAITOK, VM_KERN_MEMORY_OSKEXT);
14786
14787 if (!newlist) {
14788 OSKextLog(/* kext */ NULL,
14789 kOSKextLogErrorLevel | kOSKextLogGeneralFlag,
14790 "Couldn't allocate kext panic log buffer.");
14791 goto finish;
14792 }
14793
14794 newlist[0] = '\0';
14795
14796 // non-"com.apple." kexts
14797 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 1,
14798 /* libs? */ -1, newlist, newlist_size) != 0) {
14799 goto finish;
14800 }
14801 // "com.apple." nonlibrary kexts
14802 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14803 /* libs? */ 0, newlist, newlist_size) != 0) {
14804 goto finish;
14805 }
14806 // "com.apple." library kexts
14807 if (OSKext::saveLoadedKextPanicListTyped("com.apple.", /* invert? */ 0,
14808 /* libs? */ 1, newlist, newlist_size) != 0) {
14809 goto finish;
14810 }
14811
14812 if (loaded_kext_paniclist) {
14813 kheap_free(KHEAP_DATA_BUFFERS, loaded_kext_paniclist,
14814 loaded_kext_paniclist_size);
14815 }
14816 loaded_kext_paniclist = newlist;
14817 newlist = NULL;
14818 loaded_kext_paniclist_size = newlist_size;
14819
14820 finish:
14821 if (newlist) {
14822 kheap_free(KHEAP_TEMP, newlist, newlist_size);
14823 }
14824 return;
14825 }
14826
14827 /*********************************************************************
14828 * Assumes sKextLock is held.
14829 *********************************************************************/
14830 void
14831 OSKext::savePanicString(bool isLoading)
14832 {
14833 u_long len;
14834
14835 if (!kmod_info) {
14836 return; // do not goto finish here b/c of lock
14837 }
14838
14839 len = assemble_identifier_and_version( kmod_info,
14840 (isLoading) ? last_loaded_str_buf : last_unloaded_str_buf,
14841 (isLoading) ? sizeof(last_loaded_str_buf) : sizeof(last_unloaded_str_buf));
14842 if (!len) {
14843 printf("error saving unloaded kext info\n");
14844 goto finish;
14845 }
14846
14847 if (isLoading) {
14848 last_loaded_strlen = len;
14849 last_loaded_address = (void *)kmod_info->address;
14850 last_loaded_size = kmod_info->size;
14851 clock_get_uptime(&last_loaded_timestamp);
14852 } else {
14853 last_unloaded_strlen = len;
14854 last_unloaded_address = (void *)kmod_info->address;
14855 last_unloaded_size = kmod_info->size;
14856 clock_get_uptime(&last_unloaded_timestamp);
14857 }
14858
14859 finish:
14860 return;
14861 }
14862
14863 /*********************************************************************
14864 *********************************************************************/
14865 /* static */
14866 void
14867 OSKext::printKextPanicLists(int (*printf_func)(const char *fmt, ...))
14868 {
14869 if (last_loaded_strlen) {
14870 printf_func("last started kext at %llu: %.*s (addr %p, size %lu)\n",
14871 AbsoluteTime_to_scalar(&last_loaded_timestamp),
14872 last_loaded_strlen, last_loaded_str_buf,
14873 last_loaded_address, last_loaded_size);
14874 }
14875
14876 if (last_unloaded_strlen) {
14877 printf_func("last stopped kext at %llu: %.*s (addr %p, size %lu)\n",
14878 AbsoluteTime_to_scalar(&last_unloaded_timestamp),
14879 last_unloaded_strlen, last_unloaded_str_buf,
14880 last_unloaded_address, last_unloaded_size);
14881 }
14882
14883 printf_func("loaded kexts:\n");
14884 if (loaded_kext_paniclist &&
14885 pmap_find_phys(kernel_pmap, (addr64_t) (uintptr_t) loaded_kext_paniclist) &&
14886 loaded_kext_paniclist[0]) {
14887 printf_func("%.*s",
14888 strnlen(loaded_kext_paniclist, loaded_kext_paniclist_size),
14889 loaded_kext_paniclist);
14890 } else {
14891 printf_func("(none)\n");
14892 }
14893 return;
14894 }
14895
14896 /*********************************************************************
14897 * Assumes sKextLock is held.
14898 *********************************************************************/
14899 /* static */
14900 void
14901 OSKext::updateLoadedKextSummaries(void)
14902 {
14903 kern_return_t result = KERN_FAILURE;
14904 OSKextLoadedKextSummaryHeader *summaryHeader = NULL;
14905 OSKextLoadedKextSummaryHeader *summaryHeaderAlloc = NULL;
14906 OSKext *aKext;
14907 vm_map_offset_t start, end;
14908 size_t summarySize = 0;
14909 size_t size;
14910 u_int count;
14911 u_int maxKexts;
14912 u_int i, j;
14913 OSKextActiveAccount * accountingList;
14914 OSKextActiveAccount * prevAccountingList;
14915 uint32_t idx, accountingListAlloc, accountingListCount, prevAccountingListCount;
14916
14917 prevAccountingList = NULL;
14918 prevAccountingListCount = 0;
14919
14920 #if DEVELOPMENT || DEBUG
14921 if (IORecursiveLockHaveLock(sKextLock) == false) {
14922 panic("sKextLock must be held");
14923 }
14924 #endif
14925
14926 IOLockLock(sKextSummariesLock);
14927
14928 count = sLoadedKexts->getCount();
14929 for (i = 0, maxKexts = 0; i < count; ++i) {
14930 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14931 maxKexts += (aKext && aKext->isExecutable());
14932 }
14933
14934 if (!maxKexts) {
14935 goto finish;
14936 }
14937 if (maxKexts < kOSKextTypicalLoadCount) {
14938 maxKexts = kOSKextTypicalLoadCount;
14939 }
14940
14941 /* Calculate the size needed for the new summary headers.
14942 */
14943
14944 size = sizeof(*gLoadedKextSummaries);
14945 size += maxKexts * sizeof(*gLoadedKextSummaries->summaries);
14946 size = round_page(size);
14947
14948 if (gLoadedKextSummaries == NULL || sLoadedKextSummariesAllocSize < size) {
14949 if (gLoadedKextSummaries) {
14950 kmem_free(kernel_map, (vm_offset_t)gLoadedKextSummaries, sLoadedKextSummariesAllocSize);
14951 gLoadedKextSummaries = NULL;
14952 gLoadedKextSummariesTimestamp = mach_absolute_time();
14953 sLoadedKextSummariesAllocSize = 0;
14954 }
14955 result = kmem_alloc(kernel_map, (vm_offset_t *)&summaryHeaderAlloc, size, VM_KERN_MEMORY_OSKEXT);
14956 if (result != KERN_SUCCESS) {
14957 goto finish;
14958 }
14959 summaryHeader = summaryHeaderAlloc;
14960 summarySize = size;
14961 } else {
14962 summaryHeader = gLoadedKextSummaries;
14963 summarySize = sLoadedKextSummariesAllocSize;
14964
14965 start = (vm_map_offset_t) summaryHeader;
14966 end = start + summarySize;
14967 result = vm_map_protect(kernel_map,
14968 start,
14969 end,
14970 VM_PROT_DEFAULT,
14971 FALSE);
14972 if (result != KERN_SUCCESS) {
14973 goto finish;
14974 }
14975 }
14976
14977 /* Populate the summary header.
14978 */
14979
14980 bzero(summaryHeader, summarySize);
14981 summaryHeader->version = kOSKextLoadedKextSummaryVersion;
14982 summaryHeader->entry_size = sizeof(OSKextLoadedKextSummary);
14983
14984 /* Populate each kext summary.
14985 */
14986
14987 count = sLoadedKexts->getCount();
14988 accountingListAlloc = 0;
14989 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
14990 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
14991 if (!aKext || !aKext->isExecutable()) {
14992 continue;
14993 }
14994
14995 aKext->updateLoadedKextSummary(&summaryHeader->summaries[j++]);
14996 summaryHeader->numSummaries++;
14997 accountingListAlloc++;
14998 }
14999
15000 accountingList = IONew(typeof(accountingList[0]), accountingListAlloc);
15001 accountingListCount = 0;
15002 for (i = 0, j = 0; i < count && j < maxKexts; ++i) {
15003 aKext = OSDynamicCast(OSKext, sLoadedKexts->getObject(i));
15004 if (!aKext || !aKext->isExecutable()) {
15005 continue;
15006 }
15007
15008 OSKextActiveAccount activeAccount;
15009 aKext->updateActiveAccount(&activeAccount);
15010 // order by address
15011 for (idx = 0; idx < accountingListCount; idx++) {
15012 if (activeAccount.address < accountingList[idx].address) {
15013 break;
15014 }
15015 }
15016 bcopy(&accountingList[idx], &accountingList[idx + 1], (accountingListCount - idx) * sizeof(accountingList[0]));
15017 accountingList[idx] = activeAccount;
15018 accountingListCount++;
15019 }
15020 assert(accountingListCount == accountingListAlloc);
15021 /* Write protect the buffer and move it into place.
15022 */
15023
15024 start = (vm_map_offset_t) summaryHeader;
15025 end = start + summarySize;
15026
15027 result = vm_map_protect(kernel_map, start, end, VM_PROT_READ, FALSE);
15028 if (result != KERN_SUCCESS) {
15029 goto finish;
15030 }
15031
15032 gLoadedKextSummaries = summaryHeader;
15033 gLoadedKextSummariesTimestamp = mach_absolute_time();
15034 sLoadedKextSummariesAllocSize = summarySize;
15035 summaryHeaderAlloc = NULL;
15036
15037 /* Call the magic breakpoint function through a static function pointer so
15038 * the compiler can't optimize the function away.
15039 */
15040 if (sLoadedKextSummariesUpdated) {
15041 (*sLoadedKextSummariesUpdated)();
15042 }
15043
15044 IOSimpleLockLock(sKextAccountsLock);
15045 prevAccountingList = sKextAccounts;
15046 prevAccountingListCount = sKextAccountsCount;
15047 sKextAccounts = accountingList;
15048 sKextAccountsCount = accountingListCount;
15049 IOSimpleLockUnlock(sKextAccountsLock);
15050
15051 finish:
15052 IOLockUnlock(sKextSummariesLock);
15053
15054 /* If we had to allocate a new buffer but failed to generate the summaries,
15055 * free that now.
15056 */
15057 if (summaryHeaderAlloc) {
15058 kmem_free(kernel_map, (vm_offset_t)summaryHeaderAlloc, summarySize);
15059 }
15060 if (prevAccountingList) {
15061 IODelete(prevAccountingList, typeof(accountingList[0]), prevAccountingListCount);
15062 }
15063
15064 return;
15065 }
15066
15067 /*********************************************************************
15068 *********************************************************************/
15069 void
15070 OSKext::updateLoadedKextSummary(OSKextLoadedKextSummary *summary)
15071 {
15072 OSSharedPtr<OSData> uuid;
15073
15074 strlcpy(summary->name, getIdentifierCString(),
15075 sizeof(summary->name));
15076
15077 uuid = copyUUID();
15078 if (uuid) {
15079 memcpy(summary->uuid, uuid->getBytesNoCopy(), sizeof(summary->uuid));
15080 }
15081
15082 if (flags.builtin) {
15083 // this value will stop lldb from parsing the mach-o header
15084 // summary->address = UINT64_MAX;
15085 // summary->size = 0;
15086 summary->address = kmod_info->address;
15087 summary->size = kmod_info->size;
15088 } else {
15089 summary->address = kmod_info->address;
15090 summary->size = kmod_info->size;
15091 }
15092 summary->version = getVersion();
15093 summary->loadTag = kmod_info->id;
15094 summary->flags = 0;
15095 summary->reference_list = (uint64_t) kmod_info->reference_list;
15096
15097 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT_EXEC", &summary->text_exec_size);
15098 if (summary->text_exec_address == 0) {
15099 // Fallback to __TEXT
15100 summary->text_exec_address = (uint64_t) getsegdatafromheader((kernel_mach_header_t *)summary->address, "__TEXT", &summary->text_exec_size);
15101 }
15102 return;
15103 }
15104
15105 /*********************************************************************
15106 *********************************************************************/
15107
15108 void
15109 OSKext::updateActiveAccount(OSKextActiveAccount *accountp)
15110 {
15111 kernel_mach_header_t *hdr = NULL;
15112 kernel_segment_command_t *seg = NULL;
15113
15114 bzero(accountp, sizeof(*accountp));
15115
15116 hdr = (kernel_mach_header_t *)kmod_info->address;
15117 if (getcommandfromheader(hdr, LC_SEGMENT_SPLIT_INFO) || isInFileset()) {
15118 /*
15119 * If this kext supports split segments (or is in a new
15120 * MH_FILESET kext collection), use the first
15121 * executable segment as the range for instructions
15122 * (and thus for backtracing.
15123 */
15124 for (seg = firstsegfromheader(hdr); seg != NULL; seg = nextsegfromheader(hdr, seg)) {
15125 if (seg->initprot & VM_PROT_EXECUTE) {
15126 break;
15127 }
15128 }
15129 }
15130 if (seg) {
15131 accountp->address = seg->vmaddr;
15132 if (accountp->address) {
15133 accountp->address_end = seg->vmaddr + seg->vmsize;
15134 }
15135 } else {
15136 /* For non-split kexts and for kexts without executable
15137 * segments, just use the kmod_info range (as the kext
15138 * is either all in one range or should not show up in
15139 * instruction backtraces).
15140 */
15141 accountp->address = kmod_info->address;
15142 if (accountp->address) {
15143 accountp->address_end = kmod_info->address + kmod_info->size;
15144 }
15145 }
15146
15147 accountp->account = this->account;
15148 }
15149
15150 bool
15151 OSKext::isDriverKit(void)
15152 {
15153 OSString *bundleType;
15154
15155 if (infoDict) {
15156 bundleType = OSDynamicCast(OSString, infoDict->getObject(kCFBundlePackageTypeKey));
15157 if (bundleType && bundleType->isEqualTo(kOSKextBundlePackageTypeDriverKit)) {
15158 return TRUE;
15159 }
15160 }
15161 return FALSE;
15162 }
15163
15164 bool
15165 OSKext::isInFileset(void)
15166 {
15167 if (!kmod_info) {
15168 goto check_prelinked;
15169 }
15170
15171 if (kmod_info->address && kernel_mach_header_is_in_fileset((kernel_mach_header_t *)kmod_info->address)) {
15172 return true;
15173 }
15174
15175 check_prelinked:
15176 if (isPrelinked()) {
15177 /*
15178 * If we haven't setup kmod_info yet, but we know
15179 * we're loading a prelinked kext in an MH_FILESET KC,
15180 * then return true
15181 */
15182 kc_format_t kc_format;
15183 if (PE_get_primary_kc_format(&kc_format) && kc_format == KCFormatFileset) {
15184 return true;
15185 }
15186 }
15187 return false;
15188 }
15189
15190 bool
15191 OSKextSavedMutableSegment::initWithSegment(kernel_segment_command_t *seg)
15192 {
15193 kern_return_t result;
15194 if (!super::init()) {
15195 return false;
15196 }
15197 if (seg == nullptr) {
15198 return false;
15199 }
15200 result = kmem_alloc_pageable(kernel_map, (vm_offset_t *)&data, seg->vmsize, VM_KERN_MEMORY_KEXT);
15201 if (result != KERN_SUCCESS) {
15202 return false;
15203 }
15204 memcpy((void *)data, (const void *)seg->vmaddr, seg->vmsize);
15205 savedSegment = seg;
15206 vmsize = seg->vmsize;
15207 vmaddr = seg->vmaddr;
15208 return true;
15209 }
15210
15211 OSSharedPtr<OSKextSavedMutableSegment>
15212 OSKextSavedMutableSegment::withSegment(kernel_segment_command_t *seg)
15213 {
15214 OSSharedPtr<OSKextSavedMutableSegment> me = OSMakeShared<OSKextSavedMutableSegment>();
15215 if (me && !me->initWithSegment(seg)) {
15216 return nullptr;
15217 }
15218 return me;
15219 }
15220
15221 void
15222 OSKextSavedMutableSegment::free(void)
15223 {
15224 if (data) {
15225 kmem_free(kernel_map, (vm_offset_t)data, vmsize);
15226 }
15227 }
15228
15229 vm_offset_t
15230 OSKextSavedMutableSegment::getVMAddr() const
15231 {
15232 return vmaddr;
15233 }
15234
15235 vm_offset_t
15236 OSKextSavedMutableSegment::getVMSize() const
15237 {
15238 return vmsize;
15239 }
15240
15241 OSReturn
15242 OSKextSavedMutableSegment::restoreContents(kernel_segment_command_t *seg)
15243 {
15244 if (seg != savedSegment) {
15245 return kOSKextReturnInvalidArgument;
15246 }
15247 if (seg->vmaddr != vmaddr || seg->vmsize != vmsize) {
15248 return kOSKextReturnInvalidArgument;
15249 }
15250 memcpy((void *)seg->vmaddr, data, vmsize);
15251 return kOSReturnSuccess;
15252 }
15253
15254 extern "C" const vm_allocation_site_t *
15255 OSKextGetAllocationSiteForCaller(uintptr_t address)
15256 {
15257 OSKextActiveAccount * active;
15258 vm_allocation_site_t * site;
15259 vm_allocation_site_t * releasesite;
15260
15261 uint32_t baseIdx;
15262 uint32_t lim;
15263 #if __has_feature(ptrauth_calls)
15264 address = (uintptr_t)VM_KERNEL_STRIP_PTR(address);
15265 #endif /* __has_feature(ptrauth_calls) */
15266
15267 IOSimpleLockLock(sKextAccountsLock);
15268 site = releasesite = NULL;
15269
15270 // bsearch sKextAccounts list
15271 for (baseIdx = 0, lim = sKextAccountsCount; lim; lim >>= 1) {
15272 active = &sKextAccounts[baseIdx + (lim >> 1)];
15273 if ((address >= active->address) && (address < active->address_end)) {
15274 site = &active->account->site;
15275 if (!site->tag) {
15276 vm_tag_alloc_locked(site, &releasesite);
15277 }
15278 break;
15279 } else if (address > active->address) {
15280 // move right
15281 baseIdx += (lim >> 1) + 1;
15282 lim--;
15283 }
15284 // else move left
15285 }
15286 IOSimpleLockUnlock(sKextAccountsLock);
15287 if (releasesite) {
15288 kern_allocation_name_release(releasesite);
15289 }
15290
15291 return site;
15292 }
15293
15294 extern "C" uint32_t
15295 OSKextGetKmodIDForSite(const vm_allocation_site_t * site, char * name, vm_size_t namelen)
15296 {
15297 OSKextAccount * account = (typeof(account))site;
15298 const char * kname;
15299
15300 if (name) {
15301 if (account->kext) {
15302 kname = account->kext->getIdentifierCString();
15303 } else {
15304 kname = "<>";
15305 }
15306 strlcpy(name, kname, namelen);
15307 }
15308
15309 return account->loadTag;
15310 }
15311
15312 extern "C" void
15313 OSKextFreeSite(vm_allocation_site_t * site)
15314 {
15315 OSKextAccount * freeAccount = (typeof(freeAccount))site;
15316 IODelete(freeAccount, OSKextAccount, 1);
15317 }
15318
15319 /*********************************************************************
15320 *********************************************************************/
15321
15322 #if CONFIG_IMAGEBOOT
15323 int
15324 OSKextGetUUIDForName(const char *name, uuid_t uuid)
15325 {
15326 OSSharedPtr<OSKext> kext = OSKext::lookupKextWithIdentifier(name);
15327 if (!kext) {
15328 return 1;
15329 }
15330
15331 OSSharedPtr<OSData> uuid_data = kext->copyUUID();
15332 if (uuid_data) {
15333 memcpy(uuid, uuid_data->getBytesNoCopy(), sizeof(uuid_t));
15334 return 0;
15335 }
15336
15337 return 1;
15338 }
15339 #endif
15340
15341 static int
15342 sysctl_willuserspacereboot
15343 (__unused struct sysctl_oid *oidp, __unused void *arg1, __unused int arg2, struct sysctl_req *req)
15344 {
15345 int new_value = 0, old_value = 0, changed = 0;
15346 int error = sysctl_io_number(req, old_value, sizeof(int), &new_value, &changed);
15347 if (error) {
15348 return error;
15349 }
15350 if (changed) {
15351 OSKext::willUserspaceReboot();
15352 }
15353 return 0;
15354 }
15355
15356 static SYSCTL_PROC(_kern, OID_AUTO, willuserspacereboot,
15357 CTLTYPE_INT | CTLFLAG_RW | CTLFLAG_LOCKED,
15358 NULL, 0, sysctl_willuserspacereboot, "I", "");